I'm working on a calculator that takes an expression such as (5+4) and evaluates it by passing the buttons pressed to an array, and then building a parse tree from the data in the array.
What's interesting/strange, is that my code won't push the value of the right parenthesis to the array. Here is my code, could someone help me out?
The console.log activeButton shows that is the value of the button being pressed, but even when I placed calcArray.push() outside the if statements it would not push ) to an array.
$(document).ready(function(){
var calcArray = new Array();
$("input").click(function(){
var activeButton = this.value;
console.log(activeButton);
if(!isNaN(activeButton))
{
calcArray.push(parseInt(activeButton));
console.log(calcArray);
}
else if(activeButton === "=")
{
evaluate(buildTree(calcArray));
calcArray = [];
}
else
{
calcArray.push(activeButton);
}
});
});
The BuildTree code:
function BinaryTree(root) {
this.root = root;
this.activeNode = root;
}
function Node(element){
this.element = element;
this.parent;
this.rightChild;
this.leftChild;
this.setLeft = function(node){
this.leftChild = node;
node.parent = this;
};
this.setRight = function(node){
this.rightChild = node;
node.parent = this;
};
}
//methods
var buildTree = function(array)
{
var tree = new BinaryTree(new Node(null));
for(var i = 0; i < array.length; i++)
{
var newNode = new Node(array[i]);
if(array[i] == "(")
{
newNode.element = null;
tree.activeNode.setLeft(newNode);
tree.activeNode = newNode;
}
else if(array[i] == "+" || array[i] == "-" || array[i] == "/" || array[i] == "*")
{
tree.activeNode.element = newNode.element;
tree.activeNode.setRight(new Node(null));
tree.activeNode = tree.activeNode.rightChild;
}
else if(array[i] == ")")
{
if(tree.activeNode.parent == null)
{
;
}
else
{
tree.activeNode = tree.activeNode.parent;
tree.root = tree.activeNode;
}
}
else
{
tree.activeNode.element = newNode.element;
tree.activeNode = tree.activeNode.parent;
}
}
return tree.activeNode;
}
var evaluate = function(node){
var newNode1, newNode2;
newNode1 = new Node(null);
newNode1.parent = node;
newNode2 = new Node(null);
newNode2.parent = node;
if(node.leftChild == null && node.rightChild == null)
return node.element;
else{
newNode1.element = evaluate(node.leftChild);
newNode2.element = evaluate(node.rightChild);
if(newNode1.parent.element == "+")
{
return Number(newNode1.element) + Number(newNode2.element);
}
if(newNode1.parent.element == "-")
{
return newNode1.element - newNode2.element;
}
if(newNode1.parent.element == "*")
{
return newNode1.element * newNode2.element;
}
else
{
return newNode1.element / newNode2.element;
}
}
};
I just tried this out using your code and it worked fine passing the value as a string:
function pushButton (value) {
var activeButton = value;
console.log(activeButton);
if(!isNaN(activeButton))
{
calcArray.push(parseInt(activeButton));
console.log(calcArray);
}
else if(activeButton === "=")
{
evaluate(buildTree(calcArray));
calcArray = [];
}
else
{
calcArray.push(activeButton);
}
};
You aren't ever printing out the array in the last case (which is where the right paren would go), so are you sure it's not on the array and you just aren't seeing the visual feedback?
If so, we need to see more of your code. Try and setup a jsfiddle.
Related
I am building a JavaScript snippet that I am using to check which CSS classes are NOT in use on a page. Here is the code:
function httpGet(theUrl) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
function getAllClasses() {
//get inline css classes
let headContent = document.getElementsByTagName('head')[0].innerHTML;
let classes = getAllCSSClasses(headContent);
//get external linraties
let csses = document.querySelectorAll('link[rel="stylesheet"]');
for (i = 0; i < csses.length; ++i) {
if (csses[i].href && csses[i].href.indexOf("cookieconsent") == -1){
let styledata = httpGet(csses[i].href);
let cclasses = getAllCSSClasses(styledata);
if ( cclasses instanceof Array )
classes = classes.concat( cclasses );
else
classes.push( cclasses );
//console.log(csses[i].href)
//classes = Object.assign([], classes, cclasses);
//console.log(classes)
//classes.concat(cclasses);
}
}
return classes;
}
function getAllCSSClasses(cssdata) {
var re = /\.[a-zA-Z_][\w-_]*[^\.\s\{#:\,;]/g;
var m;
let classes = [];
do {
m = re.exec(cssdata);
if (m) {
for(let key in m) {
if(
(typeof m[key] == "string") &&
(classes.indexOf(m[key]) == -1) &&
(m[key].indexOf(".") == 0)
)
classes.push(m[key].replace(/\s/g, " "));
}
}
} while (m);
return classes;
}
function getHTMLUsedClasses() {
var elements = document.getElementsByTagName('*');
var unique = function (list, x) {
if (x != "" && list.indexOf(x) === -1) {
list.push(x);
}
return list;
};
var htmlclasses = [].reduce.call(elements, function (acc, e) {
if (typeof e.className == "string"){
return [].slice.call(e.classList).reduce(unique, acc);
} else {
return [];
}
}, []);
return htmlclasses;
}
function getUndefinedClasses(cssclasses, htmlclasses) {
var undefinedclasses = [];
for (let key in htmlclasses) {
if(cssclasses.indexOf("." + htmlclasses[key]) == -1 ) {
undefinedclasses.push(htmlclasses[key]);
}
}
return undefinedclasses;
}
var cssclasses = getAllClasses();
var htmlclasses = getHTMLUsedClasses();
var un = getUndefinedClasses(cssclasses, htmlclasses);
console.log(un )
//copy(un);
Now, the problem is in getHTMLUsedClasses, it doesn't work well.
For example, HTML has an 'img-responsive' class, but the output doesn't show it
var unique = function (list, x) {
if (x != "" && list.indexOf(x) === -1) {
//img-responsive here exists
list.push(x);
}
return list;
};
but:
var htmlclasses = [].reduce.call(elements, function (acc, e) {
if (typeof e.className == "string"){
return [].slice.call(e.classList).reduce(unique, acc);
} else {
return [];
}
}, []);
//doesn't exists in the final htmlclasses
return htmlclasses;
So I am guessing that [].slice.call(e.classList).reduce(unique, acc) is not working well. I don't quite understand what 'reduce' is doing here (I took this from another example). Can anyone explain?
I think I've found what was the issue. I read that "reduce() does not execute the function for array elements without values." and some classes can come empty so "return [];" will destroy all that is in the array so far. And instead I think that I have to return accumulator like this:
function getHTMLUsedClasses() {
var elements = document.getElementsByTagName('*');
var unique = function (list, x) {
if (x && list.indexOf(x) === -1) {
list.push(x);
}
return list;
};
var htmlclasses = [].reduce.call(elements, function (acc, e) {
if (e.classList.length > 0){
return [].slice.call(e.classList).reduce(unique, acc);
} else {
return acc;
}
}, []);
return htmlclasses;
}
Now the resulting array looks much better, I have in it "img-responsive".
Here is the whole code again:
function httpGet(theUrl) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open( "GET", theUrl, false ); // false for synchronous request
xmlHttp.send( null );
return xmlHttp.responseText;
}
function getAllClasses() {
//get inline css classes
let headContent = document.getElementsByTagName('head')[0].innerHTML;
let classes = getAllCSSClasses(headContent);
//get external linraties
let csses = document.querySelectorAll('link[rel="stylesheet"]');
for (i = 0; i < csses.length; ++i) {
if (csses[i].href && csses[i].href.indexOf("cookieconsent") == -1){
let styledata = httpGet(csses[i].href);
let cclasses = getAllCSSClasses(styledata);
if ( cclasses instanceof Array )
classes = classes.concat( cclasses );
else
classes.push( cclasses );
}
}
return classes;
}
function getAllCSSClasses(cssdata) {
var re = /\.[a-zA-Z_][\w-_]*[^\.\s\{#:\,;]/g;
var m;
let classes = [];
do {
m = re.exec(cssdata);
if (m) {
for(let key in m) {
if(
(typeof m[key] == "string") &&
(classes.indexOf(m[key]) == -1) &&
(m[key].indexOf(".") == 0)
)
classes.push(m[key].replace(/\s/g, " "));
}
}
} while (m);
return classes;
}
function getHTMLUsedClasses() {
var elements = document.getElementsByTagName('*');
var unique = function (list, x) {
if (x && list.indexOf(x) === -1) {
list.push(x);
}
return list;
};
var htmlclasses = [].reduce.call(elements, function (acc, e) {
if (e.classList.length > 0){
return [].slice.call(e.classList).reduce(unique, acc);
} else {
return acc;
}
}, []);
return htmlclasses;
}
function getUndefinedClasses(cssclasses, htmlclasses) {
var undefinedclasses = [];
for (let key in htmlclasses) {
if(cssclasses.indexOf("." + htmlclasses[key]) == -1 ) {
undefinedclasses.push(htmlclasses[key]);
}
}
return undefinedclasses;
}
//console.log(cssclasses)
var cssclasses = getAllClasses();
var htmlclasses = getHTMLUsedClasses();
var un = getUndefinedClasses(cssclasses, htmlclasses);
console.log(un )
//copy(un);
I have no idea why I'm getting this error, I'm using trie.js from github and trying to use the add function, but it says that trie.add isn't a function.
var longestWord = function(words) {
console.log('test');
let trie = new Trie();
trie.add("test");
console.log(trie);
};
longestWord('testing');
function Trie() {
this.head = {
key : ''
, children: {}
}
}
Trie.prototype.add = function(key) {
var curNode = this.head
, newNode = null
, curChar = key.slice(0,1);
key = key.slice(1);
while(typeof curNode.children[curChar] !== "undefined"
&& curChar.length > 0){
curNode = curNode.children[curChar];
curChar = key.slice(0,1);
key = key.slice(1);
}
while(curChar.length > 0) {
newNode = {
key : curChar
, value : key.length === 0 ? null : undefined
, children : {}
};
curNode.children[curChar] = newNode;
curNode = newNode;
curChar = key.slice(0,1);
key = key.slice(1);
}
};
Trie.prototype.search = function(key) {
var curNode = this.head
, curChar = key.slice(0,1)
, d = 0;
key = key.slice(1);
while(typeof curNode.children[curChar] !== "undefined" && curChar.length > 0){
curNode = curNode.children[curChar];
curChar = key.slice(0,1);
key = key.slice(1);
d += 1;
}
if (curNode.value === null && key.length === 0) {
return d;
} else {
return -1;
}
}
Trie.prototype.remove = function(key) {
var d = this.search(key);
if (d > -1){
removeH(this.head, key, d);
}
}
function removeH(node, key, depth) {
if (depth === 0 && Object.keys(node.children).length === 0){
return true;
}
var curChar = key.slice(0,1);
if (removeH(node.children[curChar], key.slice(1), depth-1)) {
delete node.children[curChar];
if (Object.keys(node.children).length === 0) {
return true;
} else {
return false;
}
} else {
return false;
}
}
All the code I added myself is before function Trie(). The rest of it is from this github repo: https://gist.github.com/alexandervasyuk/b12c3d2c306539decb2a#file-trie-js
You are calling new Trie before adding prototypes to it.
This is working version:
https://jsbin.com/jokekuw/3/edit?js,output
var longestWord = function(words) {
console.log('test');
let trie = new Trie();
trie.add("test");
};
function Trie() {
this.head = {
key : ''
, children: {}
}
}
Your code should be moved to after the Trie declaration and prototype initialization.
The Trie constructor function (Trie) declaration will be hoisted to the top of the code block. Your code can therefore be successful in instantiating a new object with it. However, at the time you try to use the object, the Trie prototype has not yet been initialized. The prototype initialization statements are just ordinary statements, so they will be executed after your call to longestWord().
Thus if you move everything of yours that is currently before function Trie ... to the end of the overall code block, it should work (barring other errors).
I am trying to convert the XML to JSON.Here am facing challenge my xml have #attributes name as "value" in all tag. while convert into xml to JSON i am using the below code.
var xml = "<Message><id value="123"></id><type value="Test"></type></Message>"
var json = XMLtoJSON(xml, ["type", "space", "xmlns", "html"]);
var result = JSON.stringify(json)
function XMLtoJSON(xml, ignored) {
var r, children = xml.*, attributes = xml.#*, length = children.length();
if(length == 0) {
r = xml.toString();
} else if(length == 1) {
var text = xml.text().toString();
if(text) {
r = text;
}
}
if(r == undefined) {
r = {};
for each (var child in children) {
var name = child.localName();
var json = XMLtoJSON(child, ignored);
var value = r[name];
if(value) {
if(value.length) {
value.push(json);
} else {
r[name] = [value, json]
}
} else {
r[name] = json;
}
}
}
if(attributes.length()) {
var a = {}, c = 0;
for each (var attribute in attributes) {
var name = attribute.localName();
if(ignored && ignored.indexOf(name) == -1) {
a["_" + name] = attribute.toString();
c ++;
}
}
if(c) {
if(r) a._ = r;
return a;
}
}
return r;
}
Input XML :
<Message><id value="123"></id><type value="Test"></type></Message>
Actual Output:
{"id":{"_value":"123"},"type":{"_value":"Test"}}
Expected Output:
{"id":"123","type":"Test"}
Guide me where am missing the part to get the expected output.
Regards,
nkn1189
do you think if you do this way will work for you?
put your actual output from that parser to this function:
function convertToExpectedOutput(obj){
var result = {}
for (var i in obj){
if (i == "_value")
return obj[i];
else
result[i] = convertToExpectedOutput(obj[i])
}
return result;
}
convertToExpectedOutput(actualOutput)
So, for your array, hange the convertToExpectedOutput to this way and it will give the expected result:
function convertToExpectedOutput(obj){
var result = {}
for (var i in obj){
if (i == "_value")
return obj[i];
else
if (Array.isArray(obj[i])){
result[i] = [];
arr = obj[i]
for (var j in arr)
result[i].push(convertToExpectedOutput(arr[j]))
}
else
result[i] = convertToExpectedOutput(obj[i])
}
return result;
}
I can across this very useful angular filter. I wanted to alter it so it removes any items that aren't explicitly filtered for. Right now if any key has a property which isn't recognized it ignores they key entirely. Essentially I want items filtered out if a key's property isn't present. For instance if $scope.searchName doesn't match it should be removed by the filter.
I got the filter here.
https://stackoverflow.com/a/21169596/2292822
<div ng-repeat="item in filtered = (items | filterMultiple:queryBy)>
Here is the relevant scope variables and filter
$scope.queryBy = {name:$scope.searchName, y1:$scope.selectedYear,y2:$scope.selectedYear,y3:$scope.selectedYear,y4:$scope.selectedYear};
myApp.filter('filterMultiple',['$filter',function ($filter) {return function (items, keyObj) {
var filterObj = {
data:items,
filteredData:[],
applyFilter : function(obj,key){
var fData = [];
if (this.filteredData.length == 0)
this.filteredData = this.data;
if (obj){
var fObj = {};
if (!angular.isArray(obj)){
fObj[key] = obj;
fData = fData.concat($filter('filter')(this.filteredData,fObj));
} else if (angular.isArray(obj)){
if (obj.length > 0){
for (var i=0;i<obj.length;i++){
if (angular.isDefined(obj[i])){
fObj[key] = obj[i];
fData = fData.concat($filter('filter')(this.filteredData,fObj));
}
}
}
}
if (fData.length > 0){
this.filteredData = fData;
}
}
}
};
if (keyObj){
angular.forEach(keyObj,function(obj,key){
filterObj.applyFilter(obj,key);
});
}
return filterObj.filteredData;}}]);
I made a few changes to the code, it works for me now, hopefully it works for you too!
myApp.filter('filterMultiple',['$filter',function ($filter) {return function (items, keyObj) {
var x = false;
var filterObj = {
data:items,
filteredData:[],
applyFilter : function(obj,key){
var fData = [];
if (this.filteredData.length == 0 && x == false)
this.filteredData = this.data;
if (obj){
var fObj = {};
if (!angular.isArray(obj)){
fObj[key] = obj;
fData = fData.concat($filter('filter')(this.filteredData,fObj));
} else if (angular.isArray(obj)){
if (obj.length > 0){
for (var i=0;i<obj.length;i++){
if (angular.isDefined(obj[i])){
fObj[key] = obj[i];
fData = fData.concat($filter('filter')(this.filteredData,fObj));
}
}
}
}
if (fData.length > 0){
this.filteredData = fData;
}
if (fData.length == 0) {
if(obj!= "" && obj!= undefined)
{
this.filteredData = fData;
x = true;
}
}
}
}
};
if (keyObj){
angular.forEach(keyObj,function(obj,key){
filterObj.applyFilter(obj,key);
});
}
return filterObj.filteredData;}}]);
I have a javascript file for history management. It is not supported by chrome when i am trying to navigate to back page with back button in the browser.I can see the url change but it doesnt go to preceeding page.
BrowserHistoryUtils = {
addEvent: function(elm, evType, fn, useCapture) {
useCapture = useCapture || false;
if (elm.addEventListener) {
elm.addEventListener(evType, fn, useCapture);
return true;
}
else if (elm.attachEvent) {
var r = elm.attachEvent('on' + evType, fn);
return r;
}
else {
elm['on' + evType] = fn;
}
}
}
BrowserHistory = (function() {
// type of browser
var browser = {
ie: false,
firefox: false,
safari: false,
opera: false,
version: -1
};
// if setDefaultURL has been called, our first clue
// that the SWF is ready and listening
//var swfReady = false;
// the URL we'll send to the SWF once it is ready
//var pendingURL = '';
// Default app state URL to use when no fragment ID present
var defaultHash = '';
// Last-known app state URL
var currentHref = document.location.href;
// Initial URL (used only by IE)
var initialHref = document.location.href;
// Initial URL (used only by IE)
var initialHash = document.location.hash;
// History frame source URL prefix (used only by IE)
var historyFrameSourcePrefix = 'history/historyFrame.html?';
// History maintenance (used only by Safari)
var currentHistoryLength = -1;
var historyHash = [];
var initialState = createState(initialHref, initialHref + '#' + initialHash, initialHash);
var backStack = [];
var forwardStack = [];
var currentObjectId = null;
//UserAgent detection
var useragent = navigator.userAgent.toLowerCase();
if (useragent.indexOf("opera") != -1) {
browser.opera = true;
} else if (useragent.indexOf("msie") != -1) {
browser.ie = true;
browser.version = parseFloat(useragent.substring(useragent.indexOf('msie') + 4));
} else if (useragent.indexOf("safari") != -1) {
browser.safari = true;
browser.version = parseFloat(useragent.substring(useragent.indexOf('safari') + 7));
} else if (useragent.indexOf("gecko") != -1) {
browser.firefox = true;
}
if (browser.ie == true && browser.version == 7) {
window["_ie_firstload"] = false;
}
// Accessor functions for obtaining specific elements of the page.
function getHistoryFrame()
{
return document.getElementById('ie_historyFrame');
}
function getAnchorElement()
{
return document.getElementById('firefox_anchorDiv');
}
function getFormElement()
{
return document.getElementById('safari_formDiv');
}
function getRememberElement()
{
return document.getElementById("safari_remember_field");
}
// Get the Flash player object for performing ExternalInterface callbacks.
// Updated for changes to SWFObject2.
function getPlayer(id) {
if (id && document.getElementById(id)) {
var r = document.getElementById(id);
if (typeof r.SetVariable != "undefined") {
return r;
}
else {
var o = r.getElementsByTagName("object");
var e = r.getElementsByTagName("embed");
if (o.length > 0 && typeof o[0].SetVariable != "undefined") {
return o[0];
}
else if (e.length > 0 && typeof e[0].SetVariable != "undefined") {
return e[0];
}
}
}
else {
var o = document.getElementsByTagName("object");
var e = document.getElementsByTagName("embed");
if (e.length > 0 && typeof e[0].SetVariable != "undefined") {
return e[0];
}
else if (o.length > 0 && typeof o[0].SetVariable != "undefined") {
return o[0];
}
else if (o.length > 1 && typeof o[1].SetVariable != "undefined") {
return o[1];
}
}
return undefined;
}
function getPlayers() {
var players = [];
if (players.length == 0) {
var tmp = document.getElementsByTagName('object');
players = tmp;
}
if (players.length == 0 || players[0].object == null) {
var tmp = document.getElementsByTagName('embed');
players = tmp;
}
return players;
}
function getIframeHash() {
var doc = getHistoryFrame().contentWindow.document;
var hash = String(doc.location.search);
if (hash.length == 1 && hash.charAt(0) == "?") {
hash = "";
}
else if (hash.length >= 2 && hash.charAt(0) == "?") {
hash = hash.substring(1);
}
return hash;
}
/* Get the current location hash excluding the '#' symbol. */
function getHash() {
// It would be nice if we could use document.location.hash here,
// but it's faulty sometimes.
var idx = document.location.href.indexOf('#');
return (idx >= 0) ? document.location.href.substr(idx+1) : '';
}
/* Get the current location hash excluding the '#' symbol. */
function setHash(hash) {
// It would be nice if we could use document.location.hash here,
// but it's faulty sometimes.
if (hash == '') hash = '#'
document.location.hash = hash;
}
function createState(baseUrl, newUrl, flexAppUrl) {
return { 'baseUrl': baseUrl, 'newUrl': newUrl, 'flexAppUrl': flexAppUrl, 'title': null };
}
/* Add a history entry to the browser.
* baseUrl: the portion of the location prior to the '#'
* newUrl: the entire new URL, including '#' and following fragment
* flexAppUrl: the portion of the location following the '#' only
*/
function addHistoryEntry(baseUrl, newUrl, flexAppUrl) {
//delete all the history entries
forwardStack = [];
if (browser.ie) {
//Check to see if we are being asked to do a navigate for the first
//history entry, and if so ignore, because it's coming from the creation
//of the history iframe
if (flexAppUrl == defaultHash && document.location.href == initialHref && window['_ie_firstload']) {
currentHref = initialHref;
return;
}
if ((!flexAppUrl || flexAppUrl == defaultHash) && window['_ie_firstload']) {
newUrl = baseUrl + '#' + defaultHash;
flexAppUrl = defaultHash;
} else {
// for IE, tell the history frame to go somewhere without a '#'
// in order to get this entry into the browser history.
getHistoryFrame().src = historyFrameSourcePrefix + flexAppUrl;
}
setHash(flexAppUrl);
} else {
//ADR
if (backStack.length == 0 && initialState.flexAppUrl == flexAppUrl) {
initialState = createState(baseUrl, newUrl, flexAppUrl);
} else if(backStack.length > 0 && backStack[backStack.length - 1].flexAppUrl == flexAppUrl) {
backStack[backStack.length - 1] = createState(baseUrl, newUrl, flexAppUrl);
}
if (browser.safari) {
// for Safari, submit a form whose action points to the desired URL
if (browser.version <= 419.3) {
var file = window.location.pathname.toString();
file = file.substring(file.lastIndexOf("/")+1);
getFormElement().innerHTML = '<form name="historyForm" action="'+file+'#' + flexAppUrl + '" method="GET"></form>';
//get the current elements and add them to the form
var qs = window.location.search.substring(1);
var qs_arr = qs.split("&");
for (var i = 0; i < qs_arr.length; i++) {
var tmp = qs_arr[i].split("=");
var elem = document.createElement("input");
elem.type = "hidden";
elem.name = tmp[0];
elem.value = tmp[1];
document.forms.historyForm.appendChild(elem);
}
document.forms.historyForm.submit();
} else {
top.location.hash = flexAppUrl;
}
// We also have to maintain the history by hand for Safari
historyHash[history.length] = flexAppUrl;
_storeStates();
} else {
// Otherwise, write an anchor into the page and tell the browser to go there
addAnchor(flexAppUrl);
setHash(flexAppUrl);
}
}
backStack.push(createState(baseUrl, newUrl, flexAppUrl));
}
function _storeStates() {
if (browser.safari) {
getRememberElement().value = historyHash.join(",");
}
}
function handleBackButton() {
//The "current" page is always at the top of the history stack.
var current = backStack.pop();
if (!current) { return; }
var last = backStack[backStack.length - 1];
if (!last && backStack.length == 0){
last = initialState;
}
forwardStack.push(current);
}
function handleForwardButton() {
//summary: private method. Do not call this directly.
var last = forwardStack.pop();
if (!last) { return; }
backStack.push(last);
}
function handleArbitraryUrl() {
//delete all the history entries
forwardStack = [];
}
/* Called periodically to poll to see if we need to detect navigation that has occurred */
function checkForUrlChange() {
if (browser.ie) {
if (currentHref != document.location.href && currentHref + '#' != document.location.href) {
//This occurs when the user has navigated to a specific URL
//within the app, and didn't use browser back/forward
//IE seems to have a bug where it stops updating the URL it
//shows the end-user at this point, but programatically it
//appears to be correct. Do a full app reload to get around
//this issue.
if (browser.version < 7) {
currentHref = document.location.href;
document.location.reload();
} else {
if (getHash() != getIframeHash()) {
// this.iframe.src = this.blankURL + hash;
var sourceToSet = historyFrameSourcePrefix + getHash();
getHistoryFrame().src = sourceToSet;
}
}
}
}
if (browser.safari) {
// For Safari, we have to check to see if history.length changed.
if (currentHistoryLength >= 0 && history.length != currentHistoryLength) {
//alert("did change: " + history.length + ", " + historyHash.length + "|" + historyHash[history.length] + "|>" + historyHash.join("|"));
// If it did change, then we have to look the old state up
// in our hand-maintained array since document.location.hash
// won't have changed, then call back into BrowserManager.
currentHistoryLength = history.length;
var flexAppUrl = historyHash[currentHistoryLength];
if (flexAppUrl == '') {
//flexAppUrl = defaultHash;
}
//ADR: to fix multiple
if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
var pl = getPlayers();
for (var i = 0; i < pl.length; i++) {
pl[i].browserURLChange(flexAppUrl);
}
} else {
getPlayer().browserURLChange(flexAppUrl);
}
_storeStates();
}
}
if (browser.firefox) {
if (currentHref != document.location.href) {
var bsl = backStack.length;
var urlActions = {
back: false,
forward: false,
set: false
}
if ((window.location.hash == initialHash || window.location.href == initialHref) && (bsl == 1)) {
urlActions.back = true;
// FIXME: could this ever be a forward button?
// we can't clear it because we still need to check for forwards. Ugg.
// clearInterval(this.locationTimer);
handleBackButton();
}
// first check to see if we could have gone forward. We always halt on
// a no-hash item.
if (forwardStack.length > 0) {
if (forwardStack[forwardStack.length-1].flexAppUrl == getHash()) {
urlActions.forward = true;
handleForwardButton();
}
}
// ok, that didn't work, try someplace back in the history stack
if ((bsl >= 2) && (backStack[bsl - 2])) {
if (backStack[bsl - 2].flexAppUrl == getHash()) {
urlActions.back = true;
handleBackButton();
}
}
if (!urlActions.back && !urlActions.forward) {
var foundInStacks = {
back: -1,
forward: -1
}
for (var i = 0; i < backStack.length; i++) {
if (backStack[i].flexAppUrl == getHash() && i != (bsl - 2)) {
arbitraryUrl = true;
foundInStacks.back = i;
}
}
for (var i = 0; i < forwardStack.length; i++) {
if (forwardStack[i].flexAppUrl == getHash() && i != (bsl - 2)) {
arbitraryUrl = true;
foundInStacks.forward = i;
}
}
handleArbitraryUrl();
}
// Firefox changed; do a callback into BrowserManager to tell it.
currentHref = document.location.href;
var flexAppUrl = getHash();
if (flexAppUrl == '') {
//flexAppUrl = defaultHash;
}
//ADR: to fix multiple
if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
var pl = getPlayers();
for (var i = 0; i < pl.length; i++) {
pl[i].browserURLChange(flexAppUrl);
}
} else {
getPlayer().browserURLChange(flexAppUrl);
}
}
}
//setTimeout(checkForUrlChange, 50);
}
/* Write an anchor into the page to legitimize it as a URL for Firefox et al. */
function addAnchor(flexAppUrl)
{
if (document.getElementsByName(flexAppUrl).length == 0) {
getAnchorElement().innerHTML += "<a name='" + flexAppUrl + "'>" + flexAppUrl + "</a>";
}
}
var _initialize = function () {
if (browser.ie)
{
var scripts = document.getElementsByTagName('script');
for (var i = 0, s; s = scripts[i]; i++) {
if (s.src.indexOf("history.js") > -1) {
var iframe_location = (new String(s.src)).replace("history.js", "historyFrame.html");
}
}
historyFrameSourcePrefix = iframe_location + "?";
var src = historyFrameSourcePrefix;
var iframe = document.createElement("iframe");
iframe.id = 'ie_historyFrame';
iframe.name = 'ie_historyFrame';
//iframe.src = historyFrameSourcePrefix;
try {
document.body.appendChild(iframe);
} catch(e) {
setTimeout(function() {
document.body.appendChild(iframe);
}, 0);
}
}
if (browser.safari)
{
var rememberDiv = document.createElement("div");
rememberDiv.id = 'safari_rememberDiv';
document.body.appendChild(rememberDiv);
rememberDiv.innerHTML = '<input type="text" id="safari_remember_field" style="width: 500px;">';
var formDiv = document.createElement("div");
formDiv.id = 'safari_formDiv';
document.body.appendChild(formDiv);
var reloader_content = document.createElement('div');
reloader_content.id = 'safarireloader';
var scripts = document.getElementsByTagName('script');
for (var i = 0, s; s = scripts[i]; i++) {
if (s.src.indexOf("history.js") > -1) {
html = (new String(s.src)).replace(".js", ".html");
}
}
reloader_content.innerHTML = '<iframe id="safarireloader-iframe" src="about:blank" frameborder="no" scrolling="no"></iframe>';
document.body.appendChild(reloader_content);
reloader_content.style.position = 'absolute';
reloader_content.style.left = reloader_content.style.top = '-9999px';
iframe = reloader_content.getElementsByTagName('iframe')[0];
if (document.getElementById("safari_remember_field").value != "" ) {
historyHash = document.getElementById("safari_remember_field").value.split(",");
}
}
if (browser.firefox)
{
var anchorDiv = document.createElement("div");
anchorDiv.id = 'firefox_anchorDiv';
document.body.appendChild(anchorDiv);
}
//setTimeout(checkForUrlChange, 50);
}
return {
historyHash: historyHash,
backStack: function() { return backStack; },
forwardStack: function() { return forwardStack },
getPlayer: getPlayer,
initialize: function(src) {
_initialize(src);
},
setURL: function(url) {
document.location.href = url;
},
getURL: function() {
return document.location.href;
},
getTitle: function() {
return document.title;
},
setTitle: function(title) {
try {
backStack[backStack.length - 1].title = title;
} catch(e) { }
//if on safari, set the title to be the empty string.
if (browser.safari) {
if (title == "") {
try {
var tmp = window.location.href.toString();
title = tmp.substring((tmp.lastIndexOf("/")+1), tmp.lastIndexOf("#"));
} catch(e) {
title = "";
}
}
}
document.title = title;
},
setDefaultURL: function(def)
{
defaultHash = def;
def = getHash();
//trailing ? is important else an extra frame gets added to the history
//when navigating back to the first page. Alternatively could check
//in history frame navigation to compare # and ?.
if (browser.ie)
{
window['_ie_firstload'] = true;
var sourceToSet = historyFrameSourcePrefix + def;
var func = function() {
getHistoryFrame().src = sourceToSet;
window.location.replace("#" + def);
setInterval(checkForUrlChange, 50);
}
try {
func();
} catch(e) {
window.setTimeout(function() { func(); }, 0);
}
}
if (browser.safari)
{
currentHistoryLength = history.length;
if (historyHash.length == 0) {
historyHash[currentHistoryLength] = def;
var newloc = "#" + def;
window.location.replace(newloc);
} else {
//alert(historyHash[historyHash.length-1]);
}
//setHash(def);
setInterval(checkForUrlChange, 50);
}
if (browser.firefox || browser.opera)
{
var reg = new RegExp("#" + def + "$");
if (window.location.toString().match(reg)) {
} else {
var newloc ="#" + def;
window.location.replace(newloc);
}
setInterval(checkForUrlChange, 50);
//setHash(def);
}
},
/* Set the current browser URL; called from inside BrowserManager to propagate
* the application state out to the container.
*/
setBrowserURL: function(flexAppUrl, objectId) {
if (browser.ie && typeof objectId != "undefined") {
currentObjectId = objectId;
}
//fromIframe = fromIframe || false;
//fromFlex = fromFlex || false;
//alert("setBrowserURL: " + flexAppUrl);
//flexAppUrl = (flexAppUrl == "") ? defaultHash : flexAppUrl ;
var pos = document.location.href.indexOf('#');
var baseUrl = pos != -1 ? document.location.href.substr(0, pos) : document.location.href;
var newUrl = baseUrl + '#' + flexAppUrl;
if (document.location.href != newUrl && document.location.href + '#' != newUrl) {
currentHref = newUrl;
addHistoryEntry(baseUrl, newUrl, flexAppUrl);
currentHistoryLength = history.length;
}
return false;
},
browserURLChange: function(flexAppUrl) {
var objectId = null;
if (browser.ie && currentObjectId != null) {
objectId = currentObjectId;
}
pendingURL = '';
if (typeof BrowserHistory_multiple != "undefined" && BrowserHistory_multiple == true) {
var pl = getPlayers();
for (var i = 0; i < pl.length; i++) {
try {
pl[i].browserURLChange(flexAppUrl);
} catch(e) { }
}
} else {
try {
getPlayer(objectId).browserURLChange(flexAppUrl);
} catch(e) { }
}
currentObjectId = null;
}
}
})();
// Initialization
// Automated unit testing and other diagnostics
function setURL(url)
{
document.location.href = url;
}
function backButton()
{
history.back();
}
function forwardButton()
{
history.forward();
}
function goForwardOrBackInHistory(step)
{
history.go(step);
}
//BrowserHistoryUtils.addEvent(window, "load", function() { BrowserHistory.initialize(); });
(function(i) {
var u =navigator.userAgent;var e=/*#cc_on!#*/false;
var st = setTimeout;
if(/webkit/i.test(u)){
st(function(){
var dr=document.readyState;
if(dr=="loaded"||dr=="complete"){i()}
else{st(arguments.callee,10);}},10);
} else if((/mozilla/i.test(u)&&!/(compati)/.test(u)) || (/opera/i.test(u))){
document.addEventListener("DOMContentLoaded",i,false);
} else if(e){
(function(){
var t=document.createElement('doc:rdy');
try{t.doScroll('left');
i();t=null;
}catch(e){st(arguments.callee,0);}})();
} else{
window.onload=i;
}
})( function() {BrowserHistory.initialize();} );
The script doesn't support chrome. Read through it in most of the functions like checkForUrlChange() it looks at the name of the browser to decide what to do.
Because chrome and safari are both based on webkit, you can try to change the line useragent.indexOf("safari") != -1 to useragent.indexOf("safari") != -1 || useragent.indexOf("chrome") != -1 to see if that works.
If not, try using unfocus history keeper. It supports Chrome.
(http://www.unfocus.com/projects/historykeeper/)