I'm trying to get the content from all the nodes in the bookmarks menu into textbox.value, but only the last bookmark appears. What am I doing wrong?
function AllBookmarks()
{
var historyService = Components.classes["#mozilla.org/browser/nav-history-service;1"]
.getService(Components.interfaces.nsINavHistoryService);
var options = historyService.getNewQueryOptions();
var query = historyService.getNewQuery();
var bookmarksService = Components.classes["#mozilla.org/browser/nav-bookmarks-service;1"]
.getService(Components.interfaces.nsINavBookmarksService);
//var toolbarFolder = bookmarksService.toolbarFolder;
//var bookmarksMenuFolder = bookmarksService.bookmarksMenuFolder;
var unfiledBookmarksFolder = bookmarksService.unfiledBookmarksFolder;
//query.setFolders([toolbarFolder], 1);
//query.setFolders([bookmarksMenuFolder], 1);
query.setFolders([unfiledBookmarksFolder], 1);
var result = historyService.executeQuery(query, options);
var rootNode = result.root;
rootNode.containerOpen = true;
// iterate over the immediate children of this folder
for (var i = 0; i < rootNode.childCount; i ++) {
var node = rootNode.getChild(i);
}
// close a container after using it!
rootNode.containerOpen = false;
var textbox = document.getElementById("MyExtension");
var title= "Title: " + node.title; // shows the title of URL
var url= "\nURL: " + node.uri; // shows the URL
textbox.value = title + url + "\n";
}
In the loop commented as "iterate over the immediate children of this folder", you are probably looping over each of the bookmarks correctly, but you are not doing anything with the each node before moving on to the next. As a result, the node variable is set to the last node when you leave the loop.
Also, you are assigning to textbox.value, rather than appending to it, so even if you were acting on the data for each node you would have clobbered it each time, resulting in only the data of the last node (the same outcome!). If you want to build up a string like that, you have to append to it, not assign to it. One way to do this is with the += operator.
So, the last part of the code should be something like:
var textbox = document.getElementById("MyExtension");
// iterate over the immediate children of this folder
for (var i = 0; i < rootNode.childCount; i ++) {
var node = rootNode.getChild(i);
var title = "Title: " + node.title; // gets the title of URL
var url = "\nURL: " + node.uri; // gets the URL
textbox.value += title + ": " + url + "\n"; // note the += (append) operator
}
// close a container after using it!
rootNode.containerOpen = false;
NB: In many other (stricter) languages, your posted code wouldn't compile because you're using the variable node outside of the "scope" (the braces) in which it was declared. It is a good rule of thumb to follow voluntarily though: violating this guideline often means you're making a mistake, or need to think more carefully about what you're doing. In this very case, it may have alerted you to the problem.
Related
The Problem: I am able to retrieve the HTMLOptionsCollection object from the select element, but unable to get an accurate length or array from it.
For context, I am trying to make an array from the HTMLOptionsCollection object so I can loop through the options to add the selected attribute to one of the option elements. Also, I'm doing this for a chrome extension so I'm not sure if there would be any odd compatibility issues because of that.
Right now, I have this code:
var dropdown = document.getElementById("clients"); // Initially empty
fillDropdown(); // This does in fact fill the select element with option elements
console.log(dropdown) // Returns select element
console.log(dropdown.options); // Returns filled HTMLOptionsCollection object
console.log(dropdown.options.length); // Returns 0
// Make an array out of HTMLOptionsCollection object (taken from https://stackoverflow.com/questions/6138042/javascript-selecbox-options-to-array)
var arr = Array.apply(null, dropdown.options).map(function(el) { return el.value; });
console.log(arr); // Returns Array[0]
Here are the console.log results:
I did not expect the length to be inaccurate at all and can't figure out why this is. Any help is greatly appreciated!
EDIT: Here is my fillDropdown() function. It's ultimate goal is to append option elements to the select element. The extra jargon is to prevent options from getting too long word wise.
// Input: None
// Output: None
// Proceeds to fill the clients dropdown with clients from local storage
function fillDropdown() {
chrome.storage.local.get(function(data) {
if (typeof data.lastClientName !== "undefined") {
for (var i = 0; i < clients.length; i++) {
// Create an option element to add to the dropdown.
var clientOption = document.createElement("option");
// cutoff is an array which holds whole words. This is done to cleanly cut off a name.
var cutoff = clients[i].split(" ");
// A clients name may have no more than 4 words to its name.
if (cutoff.length > 4) {
cutoff = cutoff[0] + " " + cutoff[1] + " " + cutoff[2] + " " + cutoff[3] + " ...";
// The full name attribute is used to store the actual name.
clientOption.setAttribute("fullName", clients[i]);
// The value and innerHTML are both the same and are user visible.
clientOption.setAttribute("value", cutoff);
if (data.lastClientName === cutoff) {
dropdown.value = clientOption.value;
}
clientOption.innerHTML = cutoff;
}
else {
// fullName is added here for consistency
clientOption.setAttribute("fullName", clients[i]);
clientOption.setAttribute("value", clients[i]);
if (data.lastClientName === clients[i]) {
dropdown.value = cutoff;
}
clientOption.innerHTML = clients[i];
}
dropdown.appendChild(clientOption);
}
}
else {
for (var i = 0; i < clients.length; i++) {
// Create an option element to add to the dropdown.
var clientOption = document.createElement("option");
// cutoff is an array which holds whole words. This is done to cleanly cut off a name.
var cutoff = clients[i].split(" ");
// A clients name may have no more than 4 words to its name.
if (cutoff.length > 4) {
cutoff = cutoff[0] + " " + cutoff[1] + " " + cutoff[2] + " " + cutoff[3] + " ...";
// The full name attribute is used to store the actual name.
clientOption.setAttribute("fullName", clients[i]);
// The value and innerHTML are both the same and are user visible.
clientOption.setAttribute("value", cutoff);
clientOption.innerHTML = cutoff;
}
else {
// fullName is added here for consistency
clientOption.setAttribute("fullName", clients[i]);
clientOption.setAttribute("value", clients[i]);
clientOption.innerHTML = clients[i];
}
dropdown.appendChild(clientOption);
}
}
});
}
Also the only html to be concerned with here is
<select name="clients" id="clients"></select>
Try this:
const newArr = Array.from(dropdown.options);
console.log(newArr.length)
You can find other ways to do this here: https://hackernoon.com/htmlcollection-nodelist-and-array-of-objects-da42737181f9
I'm so sorry, I just realized that clients in fillDropdown() was not defined. Clients is supposed to be an array of business names that I would use to actually fill the dropdown. Now I'm curious as to why I didn't get an error for that in my console. I thought any undefined variable would show in the console.
On top of clients not being defined, I also had to make fillDropdown a callback function.
Thank you everyone for helping!
I am trying to create a dynamic list so when the user performs a search it will repopulate the list. The problem is that I can't seem to make an immutable constant to store the original div content. Every time the function get's called this variable gets reinitialized.
Is there a way to achieve this without using cookies ? Any help is sincerely appreciated. The code is not complete because I couldn't get passed this step but if you think I am totally heading toward the wrong direction please let me know.
const originalList = document.getElementById('patientList').getElementsByTagName('li');
frozen = Object.freeze(originalList);
<script>
const originalList = document.getElementById('patientList').getElementsByTagName('li');
frozen = Object.freeze(originalList);
var newList = '';
var found = false;
function filterPatients(){
var searchQuery = document.getElementById('search');
var query = searchQuery.value;
var listContainer = document.getElementById('patientList');
var patientList = listContainer.getElementsByTagName('li');
for (var i = 0; i < originalList.length; i++){
var link = patientList[i].getElementsByTagName('a');
var link = link[0].text;
/** remove whitespaces for easy comparison **/
link = link.toLowerCase();
query = query.toLowerCase();
link = link.replace(/\s/g, "");
query = query.replace(/\s/g, "");
/** check every character in query **/
if (link.length > query.length && link.substring(0,query.length) == query){
found = true;
newList += '<li>' + patientList[i].innerHTML + '</li>';
}
}
if (found == true){
listContainer.innerHTML = newList;
newList = '';
}
else{
listContainer.innerHTML = "<li>No patient by that name</li>";
}
console.log(frozen);
}
</script>
const originalList = document.getElementById('patientList').getElementsByTagName('li').cloneNode(true);
Make originalList a copy of the element. Currently, you are setting originalList and patientList to be the same list of elements, so changing one will also change the other. Use element.cloneNode(true) to make a deep copy of a DOM element
Everytime an certain image is clicked I fetch some information, to add that information to a string and after that replace the current url with the new one. This is my code so far:
jQuery(document).ready(function(){
var kleuren = [];
jQuery('.swatch-category-container img').click(function(){
var kleur = jQuery(this).attr('title');
console.log("Selected kleur: " + kleur);
var link = jQuery(this).closest('.popup').find('.photo a').prop('href');
kleuren.push(kleur);
console.log(kleuren);
console.log(kleuren.length);
console.log("Fetched link: " + link);
var length = kleuren.length -1;
var avoid ="?kleur="+kleuren[length];
console.log("Remove string: " + avoid);
var news_link = link.replace(avoid,'');
var new_link = news_link + "?kleur="+kleur;
console.log("Cut string: " + news_link);
jQuery('.photo').find('.sendkleur').attr("href", new_link);
});
});
This works fine, but the previous data doesn't get removed.
For example
When the first image is clicked the kleur = zwart that info is put in the url.
But when the user clicks another image after that the url will look like ?kleur=zwart?kleur=beige instead just of ?kleur=beige
How can I remove the first part?
Although we could debug the replacement logic, I think I'd come at this a totally different way: Have a data-* attribute on the link that gives the raw version without kleur, then just reuse that; you can even initialize it on the first pass so you don't have to update your markup:
var linkElement = jQuery(this).closest('.popup').find('.photo a');
var link = linkElement.attr("data-rawhref");
if (!link) {
link = linkElement.attr("href");
linkElement.attr("data-rawhref", link);
}
// ...add kleur to `link`
If you don't need it to actually be an attribute, you can use data instead, but there's probably no real advantage over the above as the link is just a string.
var linkElement = jQuery(this).closest('.popup').find('.photo a');
var link = linkElement.data("rawhref");
if (!link) {
link = linkElement.attr("href");
linkElement.data("rawhref", link);
}
// ...add kleur to `link`
But the problem with your code is that you're using the current kleur, rather than the old one, in avoid:
kleuren.push(kleur); // Pushes the current kleur at the end
var length = kleuren.length -1; // Will be the index of the *current* kleur
var avoid ="?kleur="+kleuren[length];// ...and so this is looking for the wrong one
instead:
var avoid, new_link;
if (kleuren.length) {
avoid = "?kleur="+kleuren[kleuren.length - 1];
new_link = link.replace(avoid,'') + "?kleur="+kleur;
} else {
new_link = link + "?kleur="+kleur;
}
kleuren.push(kleur);
That's assuming you really need an array of previously-selected colors. If you don't, just use a variable:
var avoid, new_link;
if (letzteKleur) { // Meant to be "last color", my German is non-existant
avoid = "?kleur="+letzteKleur;
new_link = link.replace(avoid,'') + "?kleur="+kleur;
} else {
new_link = link + "?kleur="+kleur;
}
letzteKleur = kleur;
Maybe because you never do a pop on the array?
How does your log look like?
It seems that you try to replace the current value not the previous.
kleuren.push(kleur);
console.log(kleuren);
console.log(kleuren.length);
console.log("Fetched link: " + link);
var length = kleuren.length -1;
var avoid ="?kleur="+kleuren[length];
maybe that will do (of course only if there is at least 1 item in the array)
console.log(kleuren);
console.log(kleuren.length);
console.log("Fetched link: " + link);
var length = kleuren.length -1;
var avoid ="?kleur="+kleuren[length];
kleuren.push(kleur);
Can anyone fill in the blanks here.
I have been trying to get a script I could run to query all available users in the Global Catalog for active directory and finally managed it in VBS -looking for any particular username as below:
Const ADS_SECURE_AUTHENTICATION = 1
Set oGC = GetObject("GC:")
For Each child In oGC
Set oEntrprise = child
Exit For
Next
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFile = objFSO.CreateTextFile("AD.txt", True)
' Setup ADO.
Set oConn = CreateObject("ADODB.Connection")
Set oComm = CreateObject("ADODB.Command")
oConn.Provider = "ADsDSOObject"
oConn.Properties("ADSI Flag") = ADS_SECURE_AUTHENTICATION
oConn.Open
oComm.ActiveConnection = oConn
' Set the search command and filter.
objFile.WriteLine(oEntrprise.ADsPath)
oComm.CommandText = "<" & oEntrprise.ADsPath & ">;(&(objectCategory=person)(objectClass=user)(givenName=aaron*));cn,distinguishedName;subTree"
' Execute the query.
Set oRS = oComm.Execute
' Print the results.
oRS.MoveFirst
While Not oRS.EOF
For Each field In oRS.Fields
objFile.WriteLine(field)
Next
objFile.WriteLine("")
oRS.MoveNext
Wend
WScript.Echo "Finished"
Im now trying to convert it to JS but I cannot replicate it.
I cannot find the golden answer for looping through GetObject("GC:"). For each doesnt seem to work like for like in this case. Is anyone aware of how to do this?
So in effect i need the JS equivelant of oEntrprise in the above script.
var oConn = WScript.CreateObject("ADODB.Connection");
var oComm = WScript.CreateObject("ADODB.Command");
var keyname = "samaccountname";
var keyvalue = "aaron";
oConn.Provider = "ADsDSOObject";
oConn.Properties("ADSI Flag") = 1;
oConn.Open;
oComm.ActiveConnection = oConn;
var objRootDSE = GetObject("GC:");
for (var i = 0; i < objRootDSE.length; i++) {
WriteToFile("Moahhh");
var oEntrprise = objRootDSE[i];
oComm.CommandText = "<" + oEntrprise.ADsPath + ">;(&(objectCategory=person)(objectClass=user)(givenName=a*));cn,distinguishedName;subTree";
var oRS = oComm.Execute;
}
function WriteToFile(sText){
var fso = new ActiveXObject("Scripting.FileSystemObject");
var FileObject = fso.OpenTextFile("C:\\builds\\LogFile.txt", 8, true,0); // 8=append, true=create if not exist, 0 = ASCII
FileObject.write(sText)
FileObject.close()
}
In JScript you need to use an Enumerator to step over the elements of a collection
var objRootDSE = GetObject('GC:');
for (var childs = new Enumerator(objRootDSE) ; !childs.atEnd(); childs.moveNext()){
var child = childs.item();
WScript.Echo( child.Name );
};
Thanks for the suggested answer - answers the impossible loop I could not solve but I have now found a way to query the Global Catalogue for users directly without a need for the loop:
var aoi = WScript.CreateObject("ADSystemInfo");
var gcBase = aoi.ForestDNSName;
var ado = WScript.CreateObject("ADODB.Connection");
ado.Provider = "ADSDSOObject";
ado.Open;
WriteToFile(aoi.ForestDNSName);
var objectList = ado.Execute("<GC://" + gcBase + ">;(&(objectCategory=person)(objectClass=user)("+keyname+"="+keyvalue+"*));cn,distinguishedName;subTree");
if(!objectList.EOF)
{
WriteToFile(objectList("distinguishedName").value);
}
function WriteToFile(sText){
var fso = new ActiveXObject("Scripting.FileSystemObject");
var FileObject = fso.OpenTextFile("C:\\LogFile.txt", 8, true,0); // 8=append, true=create if not exist, 0 = ASCII
FileObject.write(sText)
FileObject.close()
}
Never again.
Whoever finds this I will help Google get here - Global Catalog JavaScript query for Active Directory!
Hello stack overflow community...
Thanks for all of the help that you have provided so far even though I have never posted on this site. I am a beginner... so that means most of the stuff that I have gotten to work has come after trying to shove a square peg into a round hole too many times to count until finally the edges are worn off enough that it actually fits...
Anyway... due to the Today() issue with SharePoint and the need to base data comparison against the current date/time I have been struggling to write my own code and display the data as I would like to in the SharePoint site that I have access too.
So far I have everything working as intended with one little flaw...
I cannot figure out how to count values even though I can make comparisons between two values. I believe it has something to do with how data is being retrieved from the SharePoint list rows and appended to the HTML table.
Relevant sections of code are as follows:
$(document).ready(function () {
$().SPServices({
operation: "GetListItems",
async: false,
CAMLRowLimit: 20,
listName: "Announcements",
completefunc: FirstFunc
});
});
function FirstFunc(xData, Status) {
var index = 0;
$documentListtable = $("#tableFirstFunc");
$(xData.responseXML).find("z\\:row, row").each(function () {
var LOTOSPLink =$(this).attr("ows_LOTODocLink");
var _Title = $(this).attr("ows_Title");
var ahref = "<a href='" + LOTOSPLink + "'>";
var anchor = "</a>"
var Titles = ahref + _Title + anchor
//Start of AReview
var _AReview = $(this).attr("ows_AReview");
var astartDateTime = $(this).attr("ows_AReview");
var astartDate = $(this).attr("ows_AReview").split(" ")[0];
var astartTime = $(this).attr("ows_AReview").split(" ")[1];
var astartDateParts = astartDate.split("-");
var aSPDYear = astartDateParts[0];
var aSPDMonth = astartDateParts[1];
var aSPDDay = astartDateParts[2];
var aSPDJoin = aSPDMonth+'/'+aSPDDay+'/'+aSPDYear;
var astartTimeParts = astartTime.split(":");
var aSPTHour = astartTimeParts[0];
var aSPTMin = astartTimeParts[1];
var aSPTSec = astartTimeParts[2];
//Combine SharePoint Date & Time split parts back together in JS Date Object
//format and than convert to millisecons to compare dates
var aReviewGraphic = ""
if(aSPDTValue === 18000000) {
aReviewGraphic="<img src="sites/Somesite/NAGlassyButton20.png>";
}
else if(aSPDTValue >= firstDCMonth && aSPDTValue < lastDCMonth) {
aReviewGraphic="<img src="/sites/Somesite/GreenButtNew20.png>";
}
else if(aSPDTValue >= firstDCYear && aSPDTValue < firstDCMonth) {
aReviewGraphic="<img src="/sites/Somesite//GreenButtOld20.png>";
}
else if(aSPDTValue < firstDCYear) {
aReviewGraphic="<img src="/sites/Somesite/RedButt20.png>";
}
var $row = $("#templates").find(".row-template").clone();
$row.find(".Titles").html(Titles);
$row.find(".aReviewGraphic").html(aReviewGraphic);
$row.find(".bReviewGraphic").html(bReviewGraphic);
$row.find(".cReviewGraphic").html(cReviewGraphic);
$row.find(".dReviewGraphic").html(dReviewGraphic);
$row.find(".NewModiDReviewGraphic").html(NewModiDReviewGraphic);
$documentListtable.append($row);
});
}
I am changing the graphics in the tables as intended, the data is being displayed as desired... but I cannot figure out how to perform a count. It seems like the rows are being read one at a time and being put into the HTML table one after the other and that all comparisons are being done row by row. I say that because my alert(messages) are being triggered for each row of data pulled in from the sharepoint list.
Is there a way to store this data in an array locally... surely there is some way to do this but I am new enough to this that I don't even know the right questions to ask...
Also the 18000000 in the if statement is the 1/1/1970 test date that I am using to currently test with as I found that any fields that were blank in the sharepoint list would cause the query to quit returning any rows after that. My solution was to use the 1/1/1970 as the default value and use it the same as leaving the field blank. I am sure that this is a crude method to work a round a problem that is easy to fix but it was all I could come up with.
Any help would be appreciated...
Steve
I try to understand... My suggestion is to store all your html into a variable and then inject the code into the table.
// somewhere you should have your HTML code
// <table id="templates"></table>
$(document).ready(function () {
$().SPServices({
operation: "GetListItems",
async: false,
CAMLRowLimit: 20,
listName: "Announcements",
completefunc: FirstFunc
});
});
function FirstFunc(xData, Status) {
var index = 0;
$documentListtable = $("#tableFirstFunc");
// create a variable where to store the html code
var htmlData = "";
// go thru the data received by the query
$(xData.responseXML).find("z\\:row, row").each(function () {
// we look at one row
var LOTOSPLink =$(this).attr("ows_LOTODocLink");
var _Title = $(this).attr("ows_Title");
var ahref = "<a href='" + LOTOSPLink + "'>";
var anchor = "</a>"
var Titles = ahref + _Title + anchor
//Start of AReview
var _AReview = $(this).attr("ows_AReview");
var astartDateTime = $(this).attr("ows_AReview");
var astartDate = $(this).attr("ows_AReview").split(" ")[0];
var astartTime = $(this).attr("ows_AReview").split(" ")[1];
var astartDateParts = astartDate.split("-");
var aSPDYear = astartDateParts[0];
var aSPDMonth = astartDateParts[1];
var aSPDDay = astartDateParts[2];
var aSPDJoin = aSPDMonth+'/'+aSPDDay+'/'+aSPDYear;
var astartTimeParts = astartTime.split(":");
var aSPTHour = astartTimeParts[0];
var aSPTMin = astartTimeParts[1];
var aSPTSec = astartTimeParts[2];
//Combine SharePoint Date & Time split parts back together in JS Date Object
//format and than convert to millisecons to compare dates
var aReviewGraphic = "";
// I don't understand why you use this variable that hasn't been initialized...
if (aSPDTValue === 18000000) {
aReviewGraphic='<img src="sites/Somesite/NAGlassyButton20.png>';
}
else if(aSPDTValue >= firstDCMonth && aSPDTValue < lastDCMonth) {
aReviewGraphic='<img src="/sites/Somesite/GreenButtNew20.png>';
}
else if(aSPDTValue >= firstDCYear && aSPDTValue < firstDCMonth) {
aReviewGraphic='<img src="/sites/Somesite//GreenButtOld20.png>';
}
else if(aSPDTValue < firstDCYear) {
aReviewGraphic='<img src="/sites/Somesite/RedButt20.png>';
}
htmlData += '<tr><td class="Titles">'+Titles+'</td><td class="aReviewGraphic">'+aReviewGraphic+'</td><td class="bReviewGraphic">'+bReviewGraphic+'</td><td class="cReviewGraphic">'+cReviewGraphic+'</td><td class="dReviewGraphic">'+dReviewGraphic+'</td><td class="NewModiDReviewGraphic">'+NewModiDReviewGraphic+'</td></tr>';
// you can increment your index if you want
index++;
});
alert("There are "+index+" rows");
// add the HTML data into the table
$documentListtable.append(htmlData);
}