So I already looked at all the articles that I could find here, yet I still couldn't solve the problem. My question is how do I make Google App Scripts ask for permission to view certain files. Here's the problem in Google App Scripts:
Script:
var NamesToDelete = [""];
function moveFiles(sourceFileId, targetFolderId) {
var file = DriveApp.getFileById(sourceFileId);
var folder = DriveApp.getFolderById(targetFolderId);
file.moveTo(folder);
}
function createFolder(folderName){
var parentFolder = DriveApp.getRootFolder();
var subFolders = parentFolder.getFolders();
var doesntExists = true;
var newFolder = '';
// Check if folder already exists.
while(subFolders.hasNext()){
var folder = subFolders.next();
//If the name exists return the id of the folder
if(folder.getName() === folderName){
doesntExists = false;
newFolder = folder;
return newFolder.getId();
};
};
//If the name doesn't exists, then create a new folder
if(doesntExists == true){
//If the file doesn't exists
newFolder = parentFolder.createFolder(folderName);
return newFolder.getId();
};
};
function start(user){
var body = "Hello " + user + ",<br> Your google drive cleanup has been successfully initiated. <br> Please go to your drive and click the file named 'Delete Me.' Select everything inside (shift+select) and right click it. In the options that come up, click 'Remove.' <br> Thank you, <br> SS Tools"
body = body + "<br> Words you chose: <br>";
for (var i = 0; i<NamesToDelete.length; i++) {
body = body + NamesToDelete[i] + "<br>";
}
var NEW_FOLDER_NAME = "DELETE ME";
var myFolderID = createFolder(NEW_FOLDER_NAME);
var tutorialPicture = UrlFetchApp
.fetch("https://i.gyazo.com/f8716f9d9b0539506a78fba52e12788b.png")
.getBlob()
.setName("How to Delete");
Logger.log(myFolderID);
listFolders(myFolderID)
MailApp.sendEmail({
to: user,
subject: "SS Tools: Drive Cleanup Successfully Initiated",
htmlBody: body,
inlineImages:
{
Tutorial: tutorialPicture,
}
});
};
function FirstWord(word) {
var wordLength = word.length
var firstWord = ""
for (var i = 0; i < wordLength; i++) {
var c = word[i]
if (c == " ") {
break;
}
else if(c >= '0' && c <= '9') {
continue;
}
firstWord = firstWord + word[i]
}
return firstWord
}
function checkIfDeleteAB(One, Two) {
var theFirstWord = FirstWord(One)
if (theFirstWord == Two || theFirstWord == "") {
return true
}
return false
}
function listFolders(parentID, folder) {
folder = folder || DriveApp.getRootFolder();
var name = folder.getName();
var files = folder.getFiles();
while ( files.hasNext() ) {
var nextFile = files.next();
var nextName = nextFile.getName();
var arrayLength = NamesToDelete.length
for (var i = 0; i < arrayLength; i++) {
if (checkIfDeleteAB(nextName, NamesToDelete[i])) {
Logger.log(name + " :: " + nextName);
//nextFile.setTrashed(true);
moveFiles(nextFile.getId(), parentID);
break;
}
}
}
var subfolders = folder.getFolders();
while (subfolders.hasNext()) {
listFolders(parentID, subfolders.next());
}
}
function GetResponsesArray(form) {
var response = form.response;
var user = response.getRespondentEmail();
var item = response.getItemResponses();
var array = item[0].getResponse();
var word = "";
var c = 0;
var done = false;
Logger.log(array)
for (var i = 0; i<array.length; i++){
if(array[i] == " "){
c = 0;
NamesToDelete.push(word);
Logger.log(word)
word = "";
done = true;
}else{
word += array[i];
Logger.log("Shaping word :: " + word)
c++;
done = false;
}
}
if (done == false){
NamesToDelete.push(word);
}
Logger.log(user)
start(user);
}
If you can find the answer to my question I would be grateful!
Google gives the following explanation for the Access denied: DriveApp exception:
Administrators of G Suite domains have the ability to disable the Drive SDK for their domain, which prevents their users from installing and using Google Drive apps. This setting also prevents the users from being able to use Apps Script add-ons that use the Drive service or Advanced Drive Service (even if the script was authorized prior to the admin disabling Drive SDK).
In other words, it seems like you are not the admin of your domain and the admin had disabled the usage of Drive SDK for you / for the whole doman.
You need to contact the admin and ask him to change permissions.
Related
I wonder if is possible to get the text inside of a PDF file by using only Javascript?
If yes, can anyone show me how?
I know there are some server-side java, c#, etc libraries but I would prefer not using a server.
thanks
Because pdf.js has been developing over the years, I would like to give a new answer. That is, it can be done locally without involving any server or external service. The new pdf.js has a function: page.getTextContent(). You can get the text content from that. I've done it successfully with the following code.
What you get in each step is a promise. You need to code this way: .then( function(){...}) to proceed to the next step.
PDFJS.getDocument( data ).then( function(pdf) {
pdf.getPage(i).then( function(page){
page.getTextContent().then( function(textContent){
What you finally get is an string array textContent.bidiTexts[]. You concatenate them to get the text of 1 page. Text blocks' coordinates are used to judge whether newline or space need to be inserted. (This may not be totally robust, but from my test it seems ok.)
The input parameter data needs to be either a URL or ArrayBuffer type data. I used the ReadAsArrayBuffer(file) function in FileReader API to get the data.
Note: According to some other user, the library has updated and caused the code to break. According to the comment by async5 below, you need to replace textContent.bidiTexts with textContent.items.
function Pdf2TextClass(){
var self = this;
this.complete = 0;
/**
*
* #param data ArrayBuffer of the pdf file content
* #param callbackPageDone To inform the progress each time
* when a page is finished. The callback function's input parameters are:
* 1) number of pages done;
* 2) total number of pages in file.
* #param callbackAllDone The input parameter of callback function is
* the result of extracted text from pdf file.
*
*/
this.pdfToText = function(data, callbackPageDone, callbackAllDone){
console.assert( data instanceof ArrayBuffer || typeof data == 'string' );
PDFJS.getDocument( data ).then( function(pdf) {
var div = document.getElementById('viewer');
var total = pdf.numPages;
callbackPageDone( 0, total );
var layers = {};
for (i = 1; i <= total; i++){
pdf.getPage(i).then( function(page){
var n = page.pageNumber;
page.getTextContent().then( function(textContent){
if( null != textContent.bidiTexts ){
var page_text = "";
var last_block = null;
for( var k = 0; k < textContent.bidiTexts.length; k++ ){
var block = textContent.bidiTexts[k];
if( last_block != null && last_block.str[last_block.str.length-1] != ' '){
if( block.x < last_block.x )
page_text += "\r\n";
else if ( last_block.y != block.y && ( last_block.str.match(/^(\s?[a-zA-Z])$|^(.+\s[a-zA-Z])$/) == null ))
page_text += ' ';
}
page_text += block.str;
last_block = block;
}
textContent != null && console.log("page " + n + " finished."); //" content: \n" + page_text);
layers[n] = page_text + "\n\n";
}
++ self.complete;
callbackPageDone( self.complete, total );
if (self.complete == total){
window.setTimeout(function(){
var full_text = "";
var num_pages = Object.keys(layers).length;
for( var j = 1; j <= num_pages; j++)
full_text += layers[j] ;
callbackAllDone(full_text);
}, 1000);
}
}); // end of page.getTextContent().then
}); // end of page.then
} // of for
});
}; // end of pdfToText()
}; // end of class
I couldn't get gm2008's example to work (the internal data structure on pdf.js has changed apparently), so I wrote my own fully promise-based solution that doesn't use any DOM elements, queryselectors or canvas, using the updated pdf.js from the example at mozilla
It eats a file path for the upload since i'm using it with node-webkit.
You need to make sure you have the cmaps downloaded and pointed somewhere and you nee pdf.js and pdf.worker.js to get this working.
/**
* Extract text from PDFs with PDF.js
* Uses the demo pdf.js from https://mozilla.github.io/pdf.js/getting_started/
*/
this.pdfToText = function(data) {
PDFJS.workerSrc = 'js/vendor/pdf.worker.js';
PDFJS.cMapUrl = 'js/vendor/pdfjs/cmaps/';
PDFJS.cMapPacked = true;
return PDFJS.getDocument(data).then(function(pdf) {
var pages = [];
for (var i = 0; i < pdf.numPages; i++) {
pages.push(i);
}
return Promise.all(pages.map(function(pageNumber) {
return pdf.getPage(pageNumber + 1).then(function(page) {
return page.getTextContent().then(function(textContent) {
return textContent.items.map(function(item) {
return item.str;
}).join(' ');
});
});
})).then(function(pages) {
return pages.join("\r\n");
});
});
}
usage:
self.pdfToText(files[0].path).then(function(result) {
console.log("PDF done!", result);
})
Just leaving here a full working sample.
<html>
<head>
<script src="https://npmcdn.com/pdfjs-dist/build/pdf.js"></script>
</head>
<body>
<input id="pdffile" name="pdffile" type="file" />
<button id="btn" onclick="convert()">Process</button>
<div id="result"></div>
</body>
</html>
<script>
function convert() {
var fr=new FileReader();
var pdff = new Pdf2TextClass();
fr.onload=function(){
pdff.pdfToText(fr.result, null, (text) => { document.getElementById('result').innerText += text; });
}
fr.readAsDataURL(document.getElementById('pdffile').files[0])
}
function Pdf2TextClass() {
var self = this;
this.complete = 0;
this.pdfToText = function (data, callbackPageDone, callbackAllDone) {
console.assert(data instanceof ArrayBuffer || typeof data == 'string');
var loadingTask = pdfjsLib.getDocument(data);
loadingTask.promise.then(function (pdf) {
var total = pdf._pdfInfo.numPages;
//callbackPageDone( 0, total );
var layers = {};
for (i = 1; i <= total; i++) {
pdf.getPage(i).then(function (page) {
var n = page.pageNumber;
page.getTextContent().then(function (textContent) {
//console.log(textContent.items[0]);0
if (null != textContent.items) {
var page_text = "";
var last_block = null;
for (var k = 0; k < textContent.items.length; k++) {
var block = textContent.items[k];
if (last_block != null && last_block.str[last_block.str.length - 1] != ' ') {
if (block.x < last_block.x)
page_text += "\r\n";
else if (last_block.y != block.y && (last_block.str.match(/^(\s?[a-zA-Z])$|^(.+\s[a-zA-Z])$/) == null))
page_text += ' ';
}
page_text += block.str;
last_block = block;
}
textContent != null && console.log("page " + n + " finished."); //" content: \n" + page_text);
layers[n] = page_text + "\n\n";
}
++self.complete;
//callbackPageDone( self.complete, total );
if (self.complete == total) {
window.setTimeout(function () {
var full_text = "";
var num_pages = Object.keys(layers).length;
for (var j = 1; j <= num_pages; j++)
full_text += layers[j];
callbackAllDone(full_text);
}, 1000);
}
}); // end of page.getTextContent().then
}); // end of page.then
} // of for
});
}; // end of pdfToText()
}; // end of class
</script>
Here's some JavaScript code that does what you want using Pdf.js from http://hublog.hubmed.org/archives/001948.html:
var input = document.getElementById("input");
var processor = document.getElementById("processor");
var output = document.getElementById("output");
// listen for messages from the processor
window.addEventListener("message", function(event){
if (event.source != processor.contentWindow) return;
switch (event.data){
// "ready" = the processor is ready, so fetch the PDF file
case "ready":
var xhr = new XMLHttpRequest;
xhr.open('GET', input.getAttribute("src"), true);
xhr.responseType = "arraybuffer";
xhr.onload = function(event) {
processor.contentWindow.postMessage(this.response, "*");
};
xhr.send();
break;
// anything else = the processor has returned the text of the PDF
default:
output.textContent = event.data.replace(/\s+/g, " ");
break;
}
}, true);
...and here's an example:
http://git.macropus.org/2011/11/pdftotext/example/
Note: This code assumes you're using nodejs. That means you're parsing a local file instead of one from a web page since the original question doesn't explicitly ask about parsing pdfs on a web page.
#gm2008's answer was a great starting point (please read it and its comments for more info), but needed some updates (08/19) and had some unused code. I also like examples that are more full. There's more refactoring and tweaking that could be done (e.g. with await), but for now it's as close to that original answer as it could be.
As before, this uses Mozilla's PDFjs library. The npmjs package is at https://www.npmjs.com/package/pdfjs-dist.
In my experience, this doesn't do well in finding where to put spaces, but that's a problem for another time.
[Edit: I believe the update to the use of .transform has restored the whitespace as it originally behaved.]
// This file is called myPDFfileToText.js and is in the root folder
let PDFJS = require('pdfjs-dist');
let pathToPDF = 'path/to/myPDFfileToText.pdf';
let toText = Pdf2TextObj();
let onPageDone = function() {}; // don't want to do anything between pages
let onFinish = function(fullText) { console.log(fullText) };
toText.pdfToText(pathToPDF, onPageDone, onFinish);
function Pdf2TextObj() {
let self = this;
this.complete = 0;
/**
*
* #param path Path to the pdf file.
* #param callbackPageDone To inform the progress each time
* when a page is finished. The callback function's input parameters are:
* 1) number of pages done.
* 2) total number of pages in file.
* 3) the `page` object itself or null.
* #param callbackAllDone Called after all text has been collected. Input parameters:
* 1) full text of parsed pdf.
*
*/
this.pdfToText = function(path, callbackPageDone, callbackAllDone) {
// console.assert(typeof path == 'string');
PDFJS.getDocument(path).promise.then(function(pdf) {
let total = pdf.numPages;
callbackPageDone(0, total, null);
let pages = {};
// For some (pdf?) reason these don't all come in consecutive
// order. That's why they're stored as an object and then
// processed one final time at the end.
for (let pagei = 1; pagei <= total; pagei++) {
pdf.getPage(pagei).then(function(page) {
let pageNumber = page.pageNumber;
page.getTextContent().then(function(textContent) {
if (null != textContent.items) {
let page_text = "";
let last_item = null;
for (let itemsi = 0; itemsi < textContent.items.length; itemsi++) {
let item = textContent.items[itemsi];
// I think to add whitespace properly would be more complex and
// would require two loops.
if (last_item != null && last_item.str[last_item.str.length - 1] != ' ') {
let itemX = item.transform[5]
let lastItemX = last_item.transform[5]
let itemY = item.transform[4]
let lastItemY = last_item.transform[4]
if (itemX < lastItemX)
page_text += "\r\n";
else if (itemY != lastItemY && (last_item.str.match(/^(\s?[a-zA-Z])$|^(.+\s[a-zA-Z])$/) == null))
page_text += ' ';
} // ends if may need to add whitespace
page_text += item.str;
last_item = item;
} // ends for every item of text
textContent != null && console.log("page " + pageNumber + " finished.") // " content: \n" + page_text);
pages[pageNumber] = page_text + "\n\n";
} // ends if has items
++self.complete;
callbackPageDone(self.complete, total, page);
// If all done, put pages in order and combine all
// text, then pass that to the callback
if (self.complete == total) {
// Using `setTimeout()` isn't a stable way of making sure
// the process has finished. Watch out for missed pages.
// A future version might do this with promises.
setTimeout(function() {
let full_text = "";
let num_pages = Object.keys(pages).length;
for (let pageNum = 1; pageNum <= num_pages; pageNum++)
full_text += pages[pageNum];
callbackAllDone(full_text);
}, 1000);
}
}); // ends page.getTextContent().then
}); // ends page.then
} // ends for every page
});
}; // Ends pdfToText()
return self;
}; // Ends object factory
Run in the terminal:
node myPDFfileToText.js
Updated 02/2021
<script src="https://npmcdn.com/pdfjs-dist/build/pdf.js"></script>
<script>
function Pdf2TextClass(){
var self = this;
this.complete = 0;
this.pdfToText = function(data, callbackPageDone, callbackAllDone){
console.assert( data instanceof ArrayBuffer || typeof data == 'string' );
var loadingTask = pdfjsLib.getDocument(data);
loadingTask.promise.then(function(pdf) {
var total = pdf._pdfInfo.numPages;
//callbackPageDone( 0, total );
var layers = {};
for (i = 1; i <= total; i++){
pdf.getPage(i).then( function(page){
var n = page.pageNumber;
page.getTextContent().then( function(textContent){
//console.log(textContent.items[0]);0
if( null != textContent.items ){
var page_text = "";
var last_block = null;
for( var k = 0; k < textContent.items.length; k++ ){
var block = textContent.items[k];
if( last_block != null && last_block.str[last_block.str.length-1] != ' '){
if( block.x < last_block.x )
page_text += "\r\n";
else if ( last_block.y != block.y && ( last_block.str.match(/^(\s?[a-zA-Z])$|^(.+\s[a-zA-Z])$/) == null ))
page_text += ' ';
}
page_text += block.str;
last_block = block;
}
textContent != null && console.log("page " + n + " finished."); //" content: \n" + page_text);
layers[n] = page_text + "\n\n";
}
++ self.complete;
//callbackPageDone( self.complete, total );
if (self.complete == total){
window.setTimeout(function(){
var full_text = "";
var num_pages = Object.keys(layers).length;
for( var j = 1; j <= num_pages; j++)
full_text += layers[j] ;
console.log(full_text);
}, 1000);
}
}); // end of page.getTextContent().then
}); // end of page.then
} // of for
});
}; // end of pdfToText()
}; // end of class
var pdff = new Pdf2TextClass();
pdff.pdfToText('PDF_URL');
</script>
For all the people who actually want to use it on a node server:
/**
* Created by velten on 25.04.16.
*/
"use strict";
let pdfUrl = "http://example.com/example.pdf";
let request = require('request');
var pdfParser = require('pdf2json');
let pdfPipe = request({url: pdfUrl, encoding:null}).pipe(pdfParser);
pdfPipe.on("pdfParser_dataError", err => console.error(err) );
pdfPipe.on("pdfParser_dataReady", pdf => {
//optionally:
//let pdf = pdfParser.getMergedTextBlocksIfNeeded();
let count1 = 0;
//get text on a particular page
for (let page of pdf.formImage.Pages) {
count1 += page.Texts.length;
}
console.log(count1);
pdfParser.destroy();
});
It is possible but:
you would have to use the server anyway, there's no way you can get content of a file on user computer without transferring it to server and back
I don't thing anyone has written such library yet
So if you have some free time you can learn pdf format and write such a library yourself, or you can just use server side library of course.
i´m desperately finding a solution for my issue. I need to place a huge amount of inline graphics in InDesign with this script, but for some reason it doesn't work. I have a very poor knowledge of Javascript and my time is running out so i cannot spend much time studying JS. I'm working in InDesign CC2014 on an iMac with Yosemite.
The following error message pops-up:
error snap:
I'll be so glad if someone give me a light on this.
main();
function main() {
var name, f, file, text,
arr = [];
if(app.documents.length != 0) {
var doc = app.activeDocument;
var folder = Folder.selectDialog("Choose a folder with images");
if (folder != null) {
app.findObjectPreferences = app.changeGrepPreferences = NothingEnum.NOTHING;
app.findGrepPreferences.findWhat = "#.+?#";
f = doc.findGrep(true);
for (i = 0; i < f.length; i++) {
name = f[i].contents.replace(/#/g, "");
file = new File(folder.fsName + "/" + name);
if (file.exists) {
f[i].contents = "";
var rect = f[i].insertionPoints[0].rectangles.add({geometricBounds:[0,0, 60, 40.667 ]} );
rect.place ( file );
rect.fit ( FitOptions.FRAME_TO_CONTENT);
}
else {
arr.push("File doesn't exist '" + name + "'");
}
}
app.findObjectPreferences = app.changeGrepPreferences = NothingEnum.NOTHING;
arr.push("------------------------------------------");
text = arr.join("\r");
writeToFile(text);
}
}
else{
alert("Please open a document and try again.");
}
}
function writeToFile(text) {
var file = new File("~/Desktop/Place inline images.txt");
if (file.exists) {
file.open("e");
file.seek(0, 2);
}
else {
file.open("w");
}
file.write(text + "\r");
file.close();
}
Problem is - probably - cause script is editing found contents and refering to it in the next lines of code.
I suggest to use backward looping and move f[i].contents = "" to the line after.
Something like:
main();
function main() {
var name, f, cF, file, text,
arr = [];
if(app.documents.length != 0) {
var doc = app.activeDocument;
var folder = Folder.selectDialog("Choose a folder with images");
if (folder != null) {
app.findObjectPreferences = app.changeGrepPreferences = NothingEnum.NOTHING;
app.findGrepPreferences.findWhat = "#.+?#";
f = doc.findGrep(true);
while(cF = f.pop()) {
name = cF.contents.replace(/#/g, "");
file = new File(folder.fsName + "/" + name);
if (file.exists) {
var rect = cF.insertionPoints[0].rectangles.add({geometricBounds:[0,0, 60, 40.667 ]} );
rect.place ( file );
rect.fit ( FitOptions.FRAME_TO_CONTENT);
cF.contents = "";
}
else {
arr.push("File doesn't exist '" + name + "'");
}
}
app.findObjectPreferences = app.changeGrepPreferences = NothingEnum.NOTHING;
arr.push("------------------------------------------");
text = arr.join("\r");
writeToFile(text);
}
}
else{
alert("Please open a document and try again.");
}
}
function writeToFile(text) {
var file = new File("~/Desktop/Place inline images.txt");
if (file.exists) {
file.open("e");
file.seek(0, 2);
}
else {
file.open("w");
}
file.write(text + "\r");
file.close();
}
I am working on my hello world project. I have two pages let's call them "configuration" and "add configuration" *.html. Each one has its own controller like this:
angular.module('MissionControlApp').controller('ConfigController', ConfigController);
angular.module('MissionControlApp').controller('AddConfigController', AddConfigController);
Now, each controller has some properties that very much overlap:
function ConfigController($routeParams, ConfigFactory, $window){
var vm = this;
vm.status;
vm.projectId = $routeParams.projectId;
vm.selectedProject;
vm.configurations;
vm.selectedConfig;
vm.selectedRecords;
vm.filteredConfig;
vm.newFile;
vm.fileWarningMsg = '';
vm.addFile = function(){
var filePath = vm.newFile;
var encodedUri = encodeURIComponent(filePath);
vm.fileWarningMsg='';
ConfigFactory
.getByEncodedUri(encodedUri).then(function(response){
var configFound = response.data;
var configNames = '';
var configMatched = false;
if(response.status === 200 && configFound.length > 0){
//find an exact match from text search result
for(var i = 0; i < configFound.length; i++) {
var config = configFound[i];
for(var j=0; j<config.files.length; j++){
var file = config.files[j];
if(file.centralPath.toLowerCase() === filePath.toLowerCase()){
configMatched = true;
configNames += ' [' + config.name + '] ';
break;
}
}
}
}
if(configMatched){
vm.fileWarningMsg = 'Warning! File already exists in other configurations.\n' + configNames;
} else if(filePath.length > 0 && filePath.includes('.rvt')){
var file1 = { centralPath: filePath };
vm.selectedConfig.files.push(file1);
vm.newFile = '';
} else{
vm.fileWarningMsg = 'Warning! Please enter a valid file.';
}
}, function(error){
vm.status = 'Unable to get configuration data: ' + error.message;
});
};
My AddConfigController also wants to have the same functionality for addFile() so I just copy pasted the same code, but coming from C# i am sure i can do some class inheritance here, and just inherit from ConfigController and extend...right?
If this is super noob question. then apologies. js is a bit of a mystery to me.
function AddConfigController($routeParams, ConfigFactory, $window){
var vm = this;
vm.status;
vm.projectId = $routeParams.projectId;
vm.selectedProject = {};
vm.newConfig = {};
vm.newFile;
vm.fileWarningMsg = '';
vm.addFile = function(){
var filePath = vm.newFile;
var encodedUri = encodeURIComponent(filePath);
vm.fileWarningMsg='';
ConfigFactory
.getByEncodedUri(encodedUri).then(function(response){
var configFound = response.data;
var configNames = '';
var configMatched = false;
if(response.status === 200 && configFound.length > 0){
//find an exact match from text search result
for(var i = 0; i < configFound.length; i++) {
var config = configFound[i];
for(var j=0; j<config.files.length; j++){
var file = config.files[j];
if(file.centralPath.toLowerCase() === filePath.toLowerCase()){
configMatched = true;
configNames += ' [' + config.name + '] ';
break;
}
}
}
}
if(configMatched){
vm.fileWarningMsg = 'Warning! File already exists in other configurations.\n' + configNames;
} else if(filePath.length > 0 && filePath.includes('.rvt')){
var file1 = { centralPath: filePath };
vm.selectedConfig.files.push(file1);
vm.newFile = '';
} else{
vm.fileWarningMsg = 'Warning! Please enter a valid file.';
}
}, function(error){
vm.status = 'Unable to get configuration data: ' + error.message;
});
};
Since you asked about inheritance and you appear to be using ECMAScript 5, let me suggest taking a look at Object.create(). Specifically, the classical inheritance example.
That said, in AngularJS, a better solution would be to create a Service that manages files or configurations and put the addFile function in there. That way, both controllers could inject the service and call the same function when it is time to add a file. Likewise, other services and controllers that may need access to this functionality could inject it as well.
Is there a way with Javascript (or other) from Google Spreadsheet to get the Gmail account signature?
Details:
I have a Google spreadsheet with information in it.
When clicking on a button, it identifies who has to receive the information, prepare a mail, and send it to the person.
However, I want to add the sender's signature at the end of the mail (it includes name, phone, logo, etc.).
I'm open if I get the signature from an other place, as long as it can change according to who's sending the mail.
This is for my volunteering association, not a job.
In case my code may help (I look to fill the var Signature):
var Signature;
var Receivers;
var Subject;
var Location ;
var MailtoSend= "Hello, \n\n The next meeting will be at " + Location + ". \n" + Signature;
MailApp.sendEmail(Receivers, Subject, MailtoSend);
SOLUTION:
I've find a way from another site (can't find it):
Create a template in your gmail draft with your signature, and put in the subject "Template" and in the body {Body}.
Then use the following code to create a copy of the mail, and fill it with all the information:
In the function to send the mail add:
sendGmailTemplate(RecipientTo, RecipientCC, RecipientBCC, SujetAEnvoyer, CourrielAEnvoyer);
Referring to the following functions:
function sendGmailTemplate(RecipientTo, RecipientCC, RecipientBCC, subject, body, options) { //mettre à jour la quantité de recipeien cc bcc to
options = options || {}; // default is no options
var drafts = GmailApp.getDraftMessages();
var found = false;
for (var i=0; i<drafts.length && !found; i++) {
if (drafts[i].getSubject() == "Template") {
found = true;
var template = drafts[i];
}
}
if (!found) throw new Error( "Impossible de trouver le brouillon 'Template' sur le gmail" );
// Generate htmlBody from template, with provided text body
var imgUpdates = updateInlineImages(template);
options.htmlBody = imgUpdates.templateBody.replace('{BODY}', body);
options.attachments = imgUpdates.attachments;
options.inlineImages = imgUpdates.inlineImages;
options.cc = RecipientCC;
options.bcc = RecipientBCC;
options.replyTo = "";
return GmailApp.sendEmail(RecipientTo, subject, body, options);
}
function updateInlineImages(template) {
//////////////////////////////////////////////////////////////////////////////
// Get inline images and make sure they stay as inline images
//////////////////////////////////////////////////////////////////////////////
var templateBody = template.getBody();
var rawContent = template.getRawContent();
var attachments = template.getAttachments();
var regMessageId = new RegExp(template.getId(), "g");
if (templateBody.match(regMessageId) != null) {
var inlineImages = {};
var nbrOfImg = templateBody.match(regMessageId).length;
var imgVars = templateBody.match(/<img[^>]+>/g);
var imgToReplace = [];
if(imgVars != null){
for (var i = 0; i < imgVars.length; i++) {
if (imgVars[i].search(regMessageId) != -1) {
var id = imgVars[i].match(/realattid=([^&]+)&/);
if (id != null) {
var temp = rawContent.split(id[1])[1];
temp = temp.substr(temp.lastIndexOf('Content-Type'));
var imgTitle = temp.match(/name="([^"]+)"/);
if (imgTitle != null) imgToReplace.push([imgTitle[1], imgVars[i], id[1]]);
}
}
}
}
for (var i = 0; i < imgToReplace.length; i++) {
for (var j = 0; j < attachments.length; j++) {
if(attachments[j].getName() == imgToReplace[i][0]) {
inlineImages[imgToReplace[i][2]] = attachments[j].copyBlob();
attachments.splice(j, 1);
var newImg = imgToReplace[i][1].replace(/src="[^\"]+\"/, "src=\"cid:" + imgToReplace[i][2] + "\"");
templateBody = templateBody.replace(imgToReplace[i][1], newImg);
}
}
}
}
var updatedTemplate = {
templateBody: templateBody,
attachments: attachments,
inlineImages: inlineImages
}
return updatedTemplate;
}
There is not a method to request a signature that you have already created. It is possible to create one yourself with inlineImages. The documentation for that can be found here: https://developers.google.com/apps-script/reference/gmail/gmail-app#sendemailrecipient-subject-body-options
I am developing an add-on which needs to create the list of accounts with their host name and username. I am able to do that using nsIMsgAccountManager but when I am creating new account using manual setup the host name appears is giving me the default imap server name i.e. imap.googlemail.com even if i have changed it to 192.168.0.25. Ideally I should get the host name as 192.168.0.25 but it's giving me imap.googlemail.com. This is the code I use:
var originalAccounts = PrefValue("mail.accountmanager.accounts");
var allServers = accountManager.allServers;
var accounts = originalAccounts.split(",");
var flagFirstItemIsSelected=false;
for (var i = 0; i < accounts.length; ++i) {
for (var ii=0; ii < allServers.Count(); ii++) {
var currentServer = allServers.GetElementAt(ii).QueryInterface(Components.interfaces.nsIMsgIncomingServer);
var type = currentServer.type;
alert(accounts[i]);
if ( accounts[i] == accountManager.FindAccountForServer(currentServer).key) {
// if (type == "none" || type == "pop3" || type == "imap" || type == "rss") {
if(type != "none")
{
if((currentServer.username.toLowerCase().search("Yahoo".toLowerCase()))==-1&&(currentServer.username.toLowerCase().search("Gmail".toLowerCase()))==-1&&(currentServer.username.toLowerCase().search("Rediffmail".toLowerCase()))==-1)
{
var theListitem = accountList.appendItem("[" + type + "] - " + currentServer.prettyName, accounts[i]);
if(flagFirstItemIsSelected==false)
{
//accountList.selectItem( theListitem );
flagFirstItemIsSelected=true;
}
theListitem.setAttribute("class", "folderMenuItem listitem-iconic")
theListitem.setAttribute("ServerType",type);
theListitem.setAttribute("IsServer",true);
theListitem.setAttribute("IsSecure",currentServer.isSecure);
theListitem.setAttribute("onclick","listClicked()");
}
}
}
}
}
Please any one tell me where I am wrong.
Don't use mail.accountmanager.accounts preference directly, use nsIMsgAccountService.accounts instead (nsISupportsArray instance). There is actually a code example on how one would iterate over all accounts. The property you should look at is nsIMsgAccount.incomingServer which is an nsIMsgIncomingServer instance and has all the necessary information. You probably want the properties realHostName and realUsername:
var accountManager = Components.classes["#mozilla.org/messenger/account-manager;1"]
.getService(Components.interfaces.nsIMsgAccountManager);
var accounts = accountManager.accounts;
for (var i = 0; i < accounts.Count(); i++) {
var account = accounts.QueryElementAt(i, Components.interfaces.nsIMsgAccount);
var server = account.incomingServer;
if (server.type == "pop3" || server.type == "imap")
alert(server.realHostName + " " + server.realUsername)
}