I am trying to bring back the folder id of any bookmark folder which has a title matching a given string.
Problem is it doesn't return back folder ids when the text is the same :C
This is my code:
chrome.bookmarks.getTree(function(bookmarks)
{
search_for_url(bookmarks, "herpaderp");
});
function search_for_title(bookmarks, title)
{
for(i=0; i < bookmarks.length; i++)
{
if(bookmarks[i].url != null && bookmarks[i].title == title)
{
// Totally found a folder that matches!
return bookmarks[i].id;
}
else
{
if(bookmarks[i].children)
{
// inception recursive stuff to get into the next layer of children
return search_for_title(bookmarks[i].children, title);
}
}
}
// No results :C
return false;
}
There are two problems with your search_for_title function.
The variable i must be local. To make it a local variable, you have to use var i = 0 instead of i = 0 in the for statement.
search_for_title returns false when it can't find a bookmark that has the specified title, but you still need to look into the next item, so after recursively calling search_for_title, you return the return value only if the bookmark has been found. Otherwise, search should be continued instead of returning false.
Here's the code I tested to run correctly:
function search_for_title(bookmarks, title)
{
for(var i=0; i < bookmarks.length; i++)
{
if(bookmarks[i].url != null && bookmarks[i].title == title)
{
// Totally found a folder that matches!
return bookmarks[i].id;
}
else
{
if(bookmarks[i].children)
{
// inception recursive stuff to get into the next layer of children
var id = search_for_title(bookmarks[i].children, title);
if(id)
return id;
}
}
}
// No results :C
return false;
}
Related
So, I have a question. I'm currently working an an education program that teaches basics on cell organelles. I have lines pointing to each organelle, in which I want to have the user be able to input what each organelle name is (like a diagram). When the user has completed the work properly, I will display the next button.
However, in order to give the user the ability to proceed, I need a way of tracking whether or not a student's answers are correct. I am using parameter passing for this.
I would like to be able to return either true/false. If all answers are returned true, the user may advance. If even one answer is wrong, a message displays.
How do I use parameter passing to determine if a users answers are right/wrong? The textfields are in an array as well...
Here is the code.
Thanks!
-Zero;
import flash.events.MouseEvent;
var organelleInput:Array=[F18nucleolusInput_txt, F18nucleusInput_txt, F18erInput_txt, F18golgiInput_txt, F18vacuoleInput_txt, F18chloroplastInput_txt, F18lysosomeInput_txt, F18mitochondriaInput_txt];
F18next_btn.visible=false;
F18next_btn.addEventListener(MouseEvent.CLICK, F18goToFrameNineteen);
F18back_btn.addEventListener(MouseEvent.CLICK, F18goToFrameSix);
checkMyWork_btn.addEventListener(MouseEvent.CLICK, checkAnswers);
function checkAnswers(event:MouseEvent):void
{
var answer:String;
var correctAnswers:Boolean;
var incorrectAnswers:Boolean;
answer = organelleInput[i];
correctAnswers=checkCorrectAnswers(answer);
for(var j:int=0; j<organelleInput.length; j++)
{
organelleInput[j].restrict="a-z";
if(correctAnswers==true)
{
F18output_txt.text="Well done!";
F18next_btn.visible=true;
checkMyWork_btn.visible==false;
}
if(correctAnswers==false)
{
F18output_txt.text="One of them seems to be wrong. Try again.";
}
}
}
function F18goToFrameNineteen(event:MouseEvent):void{
gotoAndStop(19);
}
function F18goToFrameSix(event:MouseEvent):void{
gotoAndStop(6);
}
function checkCorrectAnswers(s:String):Boolean
{
if(F18nucleolusInput_txt.text=="nucleolus"){
return true;
}
return false;
if(F18nucleusInput_txt.text=="nucleus"){
return true;
}
return false;
if((F18erInput_txt.text=="endoplasmic reticulum")||(F18erInput_txt.text=="er")){
return true;
}
return false;
if((F18golgiInput_txt.text=="golgi body")||(F18golgiInput_txt.text=="golgi apparatus")){
return true;
}
return false;
if((F18mitochondriaInput_txt.text=="mitochondria")||(F18mitochondriaInput_txt.text=="mitochondrion")){
return true;
}
return false;
if((F18lysosomeInput_txt.text=="lysosome")||(F18lysosomeInput_txt.text=="lysosomes")){
return true;
}
return false;
if(F18vacuoleInput_txt.text=="vacuole"){
return true;
}
return false;
if((F18chloroplastInput_txt.text=="chloroplast")||(F18chloroplastInput_txt.text=="chloroplasts")){
return true;
}
return false;
}
You can check Array of TextFields vs Array of Arrays:
var Correct:Array = [
["nucleolus"],
["nucleus"],
["golgi body", "golgi apparatus"],
["mitochondria", "mitochondrion"]
];
var Answers:Array = [T1, T2, T3, T4];
// Returns true if all answers are correct.
function allCorrect():Boolean
{
for (var i:int = 0; i < Answers.length; i++)
if (!oneCorrect(Answers[i], Correct[i]))
return false;
return true;
}
// Returns true if answer is on the Array of correct answers.
function oneCorrect(source:TextField, target:Array):Boolean
{
return target.indexOf(source.text.toLowerCase()) > -1;
}
Since this is always false:
doc.getBody().getParagraphs()[0] == doc.getBody().getParagraphs()[0]
How do you test element equality in Apps-Script?
I'm not entirely sure if you are comparing the contents or the position. Let's assume you can compare the contents with getAsText().
To compare the position, it's fairly easy to create an element index (the path at which an element appears in a document).
/**
* create a path in document serial for an element
* #param {Document.Element} element an element
* #param {string} [path=''] the path so far
* #return {string} the path
*/
function pathInDocument (element,path) {
path = path || "" ;
var parent = element.getParent();
if (parent) {
path = pathInDocument( parent , Utilities.formatString ( '%04d.%s', parent.getChildIndex(element),path ));
}
return path;
};
which can be called like this
var path = pathInDocument(element);
and will return something like
0000.0001.0004....etc
If the paths of two elements are the same, they appear in the same position in the document and are therefore the same element.
For an example of using this (in this case to sort bookmarks) see https://ramblings.mcpher.com/google-docs/sorting-bookmarks-in-a-document/
Eventually I came up with a solution for comparing elements.
first of all let me point that this code works and returns true:
var paragraphs = doc.getBody().getParagraphs();
Logger.log(paragraphs[0] == paragraphs[0]);
that is because you are comparing the same element from an array. The way you did in the question, you had two different arrays of paragraphs.
However there are situations when you can not do that, because you may not be comparing paragraphs, or you don't even know what elements you have.
What I do is create a path to the elements all the way up to the body section of the Document. If the paths are equal, you have the same elements.
function bodyPath(el, path) {
path = path? path: [];
var parent = el.getParent();
var index = parent.getChildIndex(el);
path.push(index);
var parentType = parent.getType();
if (parentType !== DocumentApp.ElementType.BODY_SECTION) {
path = bodyPath(parent, path);
} else {
return path;
};
return path;
};
function isSameElement(element1, element2) {
var path1 = bodyPath(element1);
var path2 = bodyPath(element2);
if (path1.length == path2.length) {
for (var i=0; i<path1.length; i++) {
if (path1[i] !== path2[i]) {
return false;
};
};
} else {
return false;
};
return true;
};
This method has proved itself quite fast. Any additions are welcome!
I wrote a recursive solution to avoid string comparison and short-circuit the path walk. Note that you can always convert to loops if you're not happy with the stack dependency of recursion.
function isSameElement(elem1, elem2) {
if (!elem1 && !elem2) return true;
if (!elem1 || !elem2) return false;
var p1=elem1.getParent();
var p2=elem2.getParent();
if (!p1 && !p2) {
return true;
} else if (!p1 || !p2) {
return false;
} else if (p1.getChildIndex(elem1)==p2.getChildIndex(elem2)){
return isSameElement(p1,p2);
} else {
return false;
}
}
I tried it and its always false, for some reason the method returns different objects.
In this case you are comparing the objects and not the content of the objects which indeed are different. You could get the content of the object with .getText(), then this comparison would return true.
So basically I would like to create a function that when alerted, returns the URL from an array (in this case the array is declared as 'websites'). The function has two parameters 'websites' and 'searchTerm'.
I'm struggling to make the function behave, so that when i type yahoo or google or bing in the searchTerm parameter for the function; I want it to return the corresponding URL.
Any help or support would be greatly appreciated.
Sorry if I have not made myself clear in my explanation, if this is the case, let me know and I will try and be clearer in my explanation.
Thanks in advance!
Try something more like:
var websites = {google: 'www.google.com', yahoo: 'www.yahoo.com'};
function filterURL(websites,searchTerm)
{
return websites[searchTerm] || 'www.defaultsearchwebstirehere.com';
}
** Update following comment **
Build up your websites object like so (where input is your array of key values seperated by pipe characters):
var websites = {};
for (var i = 0; i < input.length; i++) {
var siteToSearchTerm = input[i].split('|');
websites[siteToSearchTerm[1]] = siteToSearchTerm[0];
}
Here is how:
var websites = ["www.google.com|Google" , "www.yahoo.com|Yahoo" , "www.bing.com|Bing"];
function filterURL(websites,searchTerm)
{
for (var i = 0; i < websites.length; i++) {
if (websites[i].split('|')[1] === searchTerm) {
return websites[i].split('|')[0];
}
}
}
Working Example
You can also validate and improve function:
function filterURL(websites,searchTerm)
{
if (typeof websites != 'Array' || ! searchTerm) return false;
for (var i = 0; i < websites.length; i++) {
if (websites[i].split('|')[1] === searchTerm) {
return websites[i].split('|')[0];
}
}
return false;
}
Why not just use an object?
var websites = {
Google: 'www.google.com',
Yahoo: 'www.yahoo.com'
};
function filterURL(sites, searchTerm) {
if (sites[searchTerm]) {
return sites[searchTerm];
} else {
// What do you want to do when it can't be found?
}
}
alert(filterURL(websites, 'Google')); // alerts 'www.google.com'
You should really be using a hash-table like structure so that you don't have to search through the whole array every time. Something like this:
var websites = {
"Google": "www.google.com",
"Yahoo": "www.yahoo.com",
"Bing": "www.bing.com"
};
function filterURL(websites, searchTerm) {
if (websites[searchTerm] !== undefined)
return websites[searchTerm];
else
return null;
}
I'm not sure why you want to use an array for this, as what you're really doing fits a key-value pair better; however, here's how I'd do it:
function filterURL(websites, searchTerm) {
var i = 0,
parts;
for (i = 0; i < websites.length; i++) {
parts = websites[i].split("|");
if (parts[1].toLowerCase() === searchTerm) {
return parts[0];
}
}
}
But consider if you used a proper JavaScript Object instead:
var websites = {
Google: "www.google.com",
Yahoo: "www.yahoo.com",
Bing: "www.bing.com"
}
// Now it's much simpler:
function filterURL(websites, searchTerm) {
// key has first letter capitalized…
return websites[searchTerm.charAt(0).toUpperCase() + searchTerm.slice(1).toLowerCase()];
}
how to compare two arraycollection
collectionArray1 = ({first: 'Dave', last: 'Matthews'},...........n values
collectionArray = ({first: 'Dave', last: 'Matthews'},...........n values
how to compare..if equal just alert nochange if not alert chaged
If you just want to know if they are different from each other, meaning by length, order or individual items, you can do the following, which first checks to see if the lengths are different, then checks to see if the individual elements are different. This isn't terribly reusable, it's left as an exercise for the reader to split this apart into cleaner chunks :)
public function foo(coll1:ArrayCollection, coll2:ArrayCollection):void {
if (coll1.length == coll2.length) {
for (var i:int = 0; i < coll1.length; i++) {
if (coll1[i].first != coll2[i].first || coll1[i].last != coll2[i].last) {
Alert.show("Different");
return;
}
}
}
Alert.show("Same");
}
/* elements need to implement valueOf
public function valueOf():Object{}
*/
public static function equalsByValueOf(
first:ArrayCollection,
seconde:ArrayCollection):Boolean{
if((first==null) != (seconde==null) ){
return false;
}else if(!first && !seconde){
return false;
}
if(first.length!=seconde.length){
return false;
}
var commonLength:int = first.length;
var dictionary:Dictionary = new Dictionary();
for(var i:int=0;i<commonLength;i++){
var item1:Object = first.getItemAt(i);
var item2:Object = seconde.getItemAt(i);
dictionary[item1.valueOf()]=i;
dictionary[item2.valueOf()]=i;
}
var count:int = 0;
for (var key:Object in dictionary)
{
count++;
}
return count==commonLength;
}
/* valueOf sample
* something like javaObject.hashCode()
* use non changing fields(recommended)
*/
public function valueOf():Object{
return "_"+nonChangeField1+"_"+nonChangeField2+"...";
}
I was going to say this.
if(collectionArray === collectionArray1)
But that wont work (not triple = signs). As === is used to see classes.
I would write a function called check if object exists in array.
Create an array to hold elements that are not found. eg notFound
in Collection1 go through all the element and see if they exist in Collection2, if an element does not exist, add it to the notFound array. Use the function your created in step1
Now check Collection2, if an element is not found add it to the notFound array.
There is no 5.
Dude, use the mx.utils.ObjectUtil... the creators of actionscript have already thought about this.
ObjectUtil.compare(collection1, collection2) == 0;
This is my grid of nodes:
I'm moving an object around on it using the A* pathfinding algorithm. It generally works OK, but it sometimes acts wrongly:
When moving from 3 to 1, it correctly goes via 2. When going from 1 to 3 however, it goes via 4.
When moving between 3 and 5, it goes via 4 in either direction instead of the shorter way via 6
What can be wrong? Here's my code (AS3):
public static function getPath(from:Point, to:Point, grid:NodeGrid):PointLine {
// get target node
var target:NodeGridNode = grid.getClosestNodeObj(to.x, to.y);
var backtrace:Map = new Map();
var openList:LinkedSet = new LinkedSet();
var closedList:LinkedSet = new LinkedSet();
// begin with first node
openList.add(grid.getClosestNodeObj(from.x, from.y));
// start A*
var curNode:NodeGridNode;
while (openList.size != 0) {
// pick a new current node
if (openList.size == 1) {
curNode = NodeGridNode(openList.first);
}
else {
// find cheapest node in open list
var minScore:Number = Number.MAX_VALUE;
var minNext:NodeGridNode;
openList.iterate(function(next:NodeGridNode, i:int):int {
var score:Number = curNode.distanceTo(next) + next.distanceTo(target);
if (score < minScore) {
minScore = score;
minNext = next;
return LinkedSet.BREAK;
}
return 0;
});
curNode = minNext;
}
// have not reached
if (curNode == target) break;
else {
// move to closed
openList.remove(curNode);
closedList.add(curNode);
// put connected nodes on open list
for each (var adjNode:NodeGridNode in curNode.connects) {
if (!openList.contains(adjNode) && !closedList.contains(adjNode)) {
openList.add(adjNode);
backtrace.put(adjNode, curNode);
}
}
}
}
// make path
var pathPoints:Vector.<Point> = new Vector.<Point>();
pathPoints.push(to);
while(curNode != null) {
pathPoints.unshift(curNode.location);
curNode = backtrace.read(curNode);
}
pathPoints.unshift(from);
return new PointLine(pathPoints);
}
NodeGridNode::distanceTo()
public function distanceTo(o:NodeGridNode):Number {
var dx:Number = location.x - o.location.x;
var dy:Number = location.y - o.location.y;
return Math.sqrt(dx*dx + dy*dy);
}
The problem I see here is the line
if (!openList.contains(adjNode) && !closedList.contains(adjNode))
It may be the case that an adjNode may be easier(shorter) to reach through the current node although it was reached from another node previously which means it is in the openList.
Found the bug:
openList.iterate(function(next:NodeGridNode, i:int):int {
var score:Number = curNode.distanceTo(next) + next.distanceTo(target);
if (score < minScore) {
minScore = score;
minNext = next;
return LinkedSet.BREAK;
}
return 0;
});
The return LinkedSet.BREAK (which acts like a break statement in a regular loop) should not be there. It causes the first node in the open list to be selected always, instead of the cheapest one.