I am trying to transfer the music list from an app to Spotify.
I got an array of songs (like [Hold On To Me Placebo, Come Undone Placebo] etc.) and tried to automate the liking of songs in this way:
let inputField = document.getElementsByClassName('_2f8ed265fb69fb70c0c9afef329ae0b6-scss')[0];
let menu = document.querySelectorAll('react-contextmenu')[0];
let like = document.querySelectorAll('react-contextmenu-item')[1];
function addSong() {
for (song of arrOfSongs) {
inputField.value = song;
menu.click();
like.click();
inputField.value = '';
}
}
addSong();
There are 2 problems:
When the value is changed in the input field, the search doesn't work: the content on the page stays the same as before filling it;
Even if I type the name of some song by myself, it returns the values of menu and like variables as undefined.
Problem 1: it's unclear what you mean with "the search doesn't work: the content on the page stays the same as before filling it". If you mean the value of the input, this happens because you first put there a value of a song, then 2 rows later you clear it with the instruction inputField.value = ''; . If you remove that everything will be updated.
Problem 2, probably react-contextmenu and react-contextmenu-item are class names and the querySelectorAll function works with selectors (see here https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors ). In this case you should change the assignment to the menu and like variables in this way
let menu = document.querySelectorAll('.react-contextmenu')[0];
let like = document.querySelectorAll('.react-contextmenu-item')[1];
See this fiddle
Related
Update: This is a better way of asking the following question.
Is there an Id like attribute for an Element in a Document which I can use to reach that element at a later time. Let's say I inserted a paragraph to a document as follows:
var myParagraph = 'This should be highlighted when user clicks a button';
body.insertParagraph(0, myParagraph);
Then the user inserts another one at the beginning manually (i.e. by typing or pasting). Now the childIndex of my paragraph changes to 1 from 0. I want to reach that paragraph at a later time and highlight it. But because of the insertion, the childIndex is not valid anymore. There is no Id like attribute for Element interface or any type implementing that. CahceService and PropertiesService only accepts String data, so I can't store myParagraphas an Object.
Do you guys have any idea to achieve what I want?
Thanks,
Old version of the same question (Optional Read):
Imagine that user selects a word and presses the highlight button of my add-on. Then she does the same thing for several more words. Then she edits the document in a way that the start end end indexes of those highlighted words change.
At this point she presses the remove highlighting button. My add-on should disable highlighting on all previously selected words. The problem is that I don't want to scan the entire document and find any highlighted text. I just want direct access to those that previously selected.
Is there a way to do that? I tried caching selected elements. But when I get them back from the cache, I get TypeError: Cannot find function insertText in object Text. error. It seems like the type of the object or something changes in between cache.put() and cache.get().
var elements = selection.getSelectedElements();
for (var i = 0; i < elements.length; ++i) {
if (elements[i].isPartial()) {
Logger.log('partial');
var element = elements[i].getElement().asText();
var cache = CacheService.getDocumentCache();
cache.put('element', element);
var startIndex = elements[i].getStartOffset();
var endIndex = elements[i].getEndOffsetInclusive();
}
// ...
}
When I get back the element I get TypeError: Cannot find function insertText in object Text. error.
var cache = CacheService.getDocumentCache();
cache.get('text').insertText(0, ':)');
I hope I can clearly explained what I want to achieve.
One direct way is to add a bookmark, which is not dependent on subsequent document changes. It has a disadvantage: a bookmark is visible for everyone...
More interesting way is to add a named range with a unique name. Sample code is below:
function setNamedParagraph() {
var doc = DocumentApp.getActiveDocument();
// Suppose you want to remember namely the third paragraph (currently)
var par = doc.getBody().getParagraphs()[2];
Logger.log(par.getText());
var rng = doc.newRange().addElement(par);
doc.addNamedRange("My Unique Paragraph", rng);
}
function getParagraphByName() {
var doc = DocumentApp.getActiveDocument();
var rng = doc.getNamedRanges("My Unique Paragraph")[0];
if (rng) {
var par = rng.getRange().getRangeElements()[0].getElement().asParagraph();
Logger.log(par.getText());
} else {
Logger.log("Deleted!");
}
}
The first function "marks" the third paragraph as named range. The second one takes this paragraph by the range name despite subsequent document changes. Really here we need to consider the exception, when our "unique paragraph" was deleted.
Not sure if cache is the best approach. Cache is volatile, so it might happen that the cached value doesn't exist anymore. Probably PropertiesService is a better choice.
I am quite new the using Google Apps Script, but not to JavaScript. I was wondering if there was a way that I could retrieve some text from a Google Docs, and send it in an email, something like this.
This is not the correct syntax, but bear with me.
function createAndSendDocument() {
var email = "email";
var subject = "Subject";
var body =
GmailApp.sendEmail(email, subject, body);
}
Is there a way that I could do something like this,
var randnum = random(1,4)
getText(documentname, text from document)
Text on the document would look something like this.
Hello
Test
How are you?
Watermelon!
Where getting the text from the document is based on randnum, example: randnum = 1 so email body would be "Hello"
Sorry for all the jumping around in the question, but hope you can answer this. Comment if you need any clarification.
I believe I understand what you are looking for.
The tricky part is understanding how you have formatted the list in the Google Doc. A list can be formatted as an actual indented list where the list items are automatically incremented as you enter a new line or a list can just be a hardcoded list of entries where nothing is automatically indented and the list items are manually incremented. See the two examples in this document. Accessing the lines is different depending on how the list is built. If you truly only care about finding a particular numbered child, I would probably suggest formatting it as an actual list. If you think you might require more advanced searching, I would format it as a hardcoded list, because then you can use some regular expressions to find the relevant child.
Now to actually grabbing the text, this is what I came up with (please note that this is written in the new-ish V8 engine, so you won't be able to use this in the legacy script editor):
const getTextFromDocument = (documentID, randomNumber) => {
const doc = DocumentApp.openById(documentID);
const body = doc.getBody();
// get text from non-list elements
const find = body.findText('^' + randomNumber);
if (find) {
return find.getElement().asText().getText();
}
// get text from list elements
const listItems = body.getListItems();
for (let lix = 0; lix < listItems.length; lix++) {
const listItem = listItems[lix];
if (lix + 1 === randomNumber) {
return listItem.getText();
}
}
}
If the script finds the information in a hardcoded list, the first chunk runs, otherwise it'll proceed into the next chunk.
Depending on how the text is formatted, the returned text is slightly different. If the text is formatted as an actual list, the text looks like this:
Watermelon!
(Without the number.) Whereas if it's a hardcoded listed, the returned text looks like this:
4. Watermelon!
(With the preceding number.)
With that, sending the email will look something like this:
const sendEmail = () => {
const documentID = '1DljXJtDdZLKr_TcZKuFESo4VrgPEpwXLI3bM3RA0Kjk';
const randomNumber = Math.floor(Math.random() * 4) + 1;
const text = getTextFromDocument(documentID, randomNumber);
console.log(randomNumber);
console.log(text);
// MailApp.sendEmail({
// to: 'someone#gmail.com',
// subject: 'Subject Line',
// body: text
// });
}
I opted for MailApp as opposed to GmailApp, since MailApp is meant for sending emails exclusively whereas GmailApp also offers methods for managing Gmail. You can test it out over here if you want. If you want to take advantage of more email styling, I recommend checking out the guides over here. And if you want to read more about DocumentApp, you can check that out here.
I recently posted another question about how to add content to a string (Dynamically change string with JS?), and I made progress on that front but it seems the updated variable is not being submitted. Am I missing something?
Here is my code:
<script type="text/javascript">
var selections = 'Gender, ';
jQuery(".add-to-form").click(function () {
var title = jQuery(this).attr("title");
selections += title + ', ';
console.log(selections);
});
var ss_form = {'account': 'XYZ', 'formID': 'XYZ'};
ss_form.width = '100%';
ss_form.height = '1000';
ss_form.domain = 'app-XYZ.marketingautomation.services';
ss_form.hidden = {'field_XXXXX': selections };
</script>
This works great in that the correct values are showing up in the console log, but when I submit the form and look in SharpSpring the only value getting through is the initial variable value (Gender, ). Do I need to somehow refresh the variable value in the hidden field?
All help is appreciated, thank you!
The following line is executed on page load:
ss_form.hidden = {'field_XXXXX': selections };
This assigns the value of selections as it is at that moment. The field_XXXXX property is a separate variable that will not change when you assign a different value to selections later.
So when the click event fires, and you assign a new (longer) value to selections, then only that variable changes. It is not connected to the property above.
How to solve? Just do another assignment to the ss_form.hidden.field_XXXXX property within the click handler:
jQuery(".add-to-form").click(function () {
var title = jQuery(this).attr("title");
selections += title + ', ';
ss_form.hidden.field_XXXXX = selections; // <-------
console.log(selections);
});
I assume that ss_form.hidden is some API driven way to set a hidden input element, and that this works. If not, make sure to identify the input element that needs to get a new value, which could look like this:
$('#id_of_hidden_input').val(selections);
I want to ask if anyone knows, in javascript code, how to refer to a text entry response/input in a Loop and Merge block. I got to know the corresponding format when there is no Loop and Merge from this very useful post Qualtrics: Javascript to prevent saving entry from Text Box. See the code below:
Qualtrics.SurveyEngine.addOnload(function()
{
/*Place Your Javascript Below This Line*/
var currentQuestionID = this.getQuestionInfo().QuestionID
var input = $("QR~"+currentQuestionID);
$('NextButton').onclick = function (event) {
input.value = ""
}
});
The line quoted below works when there is no Loop and Merge.
var input = $("QR~"+currentQuestionID);
The problem: I then tried to combine $("QR~"+currentQuestionID) with Loop and Merge row id (e.g., 1, 2, 3, 4, 5), such as $("1~QR~"+currentQuestionID), $("QR~1~"+currentQuestionID) and $("QR~"+currentQuestionID + "~1"). Unfortunately, none of them works.
Thank you in advance!
The structure you're looking for is this:
var input = $("QR~${lm://CurrentLoopNumber}_"+currentQuestionID);
i.e. the loop number goes after QR~ and there is an extra _ underscore before the questionID.
I've only been able to test this in an "SE" survey engine, but in another survey that is using the JFE survey engine, the element IDs seem to be structured the same way, so it should work whichever engine your survey is using.
I have a page that has an unordered list on it. I am populating the list via javascript like this:
var vidList = document.getElementById("vidList");
var li = document.createElement("li");
li.id = "videoPlayer" + count;
var runat = document.createAttribute("runat");
runat.value = "server";
li.setAttributeNode(runat);
// Here I insert a flash video stream into li
vidlist.appendChild(li);
This works as far as creating the elements and rendering them to the page. The issue is accessing them later. Since they are video streams I want to remove them when they are no longer valid streams. In my Visual Basic code behind I have the following code:
For videoNumber As Integer = 1 to numVideos
Dim li = vidList.FindControl("videoPlayer" & videoNumber.toString())
// Check if the stream is valid and delete it if it isn't
Next
When I debug the call to FindControl returns Nothing. So I looked through the local variables and found that my list had 5 elements all of which are Nothing. I looked at both this question and this one, but neither quite worked for my needs. Is there a reason that the list items are coming into the code behind as null values?
Request.Form['videoPlayer' + count]
More generally you can use Request.Form['clientID'] for dynamically created controls.