millermedeiros / hasher Goto Github PK
View Code? Open in Web Editor NEWBrowser history manager for rich media websites
Browser history manager for rich media websites
change code structure so queryUtils also make part of Hasher object.. maybe inside namespace Hasher.queryUtils
instead of millermedeiros.queryUtils
.
It breaks on decodeURI ("malformed URI sequence"), and if I encode % to %25 before setting hash, %25 becomes %2525 (double encoded).
happened on unit test and also changing values coming from Flash multiple times without user interaction.
I have a use case where I'd like my fragment identifiers to represent actual file names on disc, and in some weird cases those can contain octet sequences that don't decode as UTF-8. In other words I'd like to be able to pass an already percent-encoded string to setHash
and to somehow be able to access the unprocecessed fragment identifier when it changes. Would you consider that out of scope for this library?
not sure if it is a good idea, don't know what will happen with non-latin chars and if users really want this option, maybe add it on a way that can be easily removed.
do something similar to a trim at the beginning and end of string
Hi. Is there a way process ALL hash changes before the browser sets the hash? Right now I use the following function:
function parseHash(newHash, oldHash){
hasher.prependHash = '!/';
hasher.replaceHash(newHash);
}
It works but the hash flashes for an instant (mere ms.) in the URL bar; that is, first the original hash is set (e.g., "#25") and then it is prepended and replaced (e.g., "#!/25").
Thanks.
add option to append/prepend values to the hash (to avoid conflicts with HTML elements IDs and also for "cosmetic" reasons), probably default both to '/'.
some methods are way too big (specially init
and stop
), extract logic from those methods and create new functions.
also check comments on source code and improve code structure so we don't need comments to explain what the code is doing.
PS: comments used to describe bugfixes shouldn't be removed.
Hi there!
First of all, great lib!
It would be nice if it was made available on npm/ender. Crossroads and signals already are, given that Hasher works hand in hand with them, it would be a logical move to make ender package building easier :).
Thanks!
just a proxy to document.location.replace()
which accepts paths fragments, it will change hash value without keeping old value in the history record...
how to do it right now: document.location.replace('#/foo/bar')
proposed change: hasher.replaceHash('foo', 'bar')
and hasher.replaceHash('foo/bar')
PS: add unit tests (not sure how all browsers behaves when setting hash value through location.replace
)
not sure what is the best approach and if it's really a good idea...
maybe add a public property dispatchChange:Boolean
so user can make multiple changes without dispatching change event.. or maybe add a parameter isSilent
to the setHash
method.
the drawback of using the parameter is that on the AS3 Class setHash
is a "real setter", so it can't have parameters.
after calling: Hasher.setHash('Spêçïãl/Chårs FTW');
Safari throws an URIError
each time _getWindowHash()
is called.
this happens because of decodeURIComponent()
, for some strange reason it doesn't work with the string "Sp%EA%E7%EF%E3l/Ch%E5rs%20FTW";
add VERSION constant to the Hasher object.
it was a poor design decision to dispatch the signals as soon as the user calls setHash
, events should always be async to avoid headaches (avoid cases where user might not expect something to happen in between).
prependHash
is enough to avoid conflicts with HTMLElements IDs.
create an AMD module wrapper and add it to the build task..
Hi,
I'm trying to replace our current client-side routing with crossroads and hasher but I've run into an issue where the routes are called more than once on click. I'm wrapping crossroads and hasher as follow
parse_hash = (new_hash, old_hash) ->
console.log("parse_hash: #{new_hash}")
crossroads.parse(new_hash)
$ ->
crossroads.routed.add (request, data) -> console.log("crossroads.routed: #{request}", data)
hasher.initialized.add(parse_hash)
hasher.changed.add(parse_hash)
hasher.init()
console.log('Router initialized!')
The actual routes are configured as follows
crossroads.addRoute 'sites/{site}', (site) -> hasher.replaceHash "sites/#{site}/overview"
crossroads.addRoute 'sites/{site}/{report}', (site, report) -> console.log('done?')
When clicking on on a link that triggers this JQuery snippet
$(document.body).on('click', '#main-menu #context-menu .site-link', function(e) {
e.preventDefault()
link = $(e.target)
href = link.attr('href').substring(3)
text = link.text()
console.log('Updating router to ' + href)
hesher.replaceHash(href)
});
The routing runs more than once as you can see from the following log
Updating router to sites/example.com
router.update: sites/example.com
parse_hash: sites/example.com
parse_hash: sites/example.com/overview
done?
crossroads.routed: sites/example.com/overview
crossroads.routed: sites/example.com
parse_hash: sites/example.com
parse_hash: sites/example.com/overview
done?
crossroads.routed: sites/example.com/overview
crossroads.routed: sites/example.com
I only noticed the issue because our app was making duplicate Ajax requests.
Would appreciate some input about what could be going on. I believe it's a problem with hasher.replaceHash since if I manually update the URL in the browser, it doesn't run twice.
you can see the page title on the browser history but it doesn't update to the correct value after navigating to that page.
events are still dispatched but for some reason hash value on the URL doesn't update. don't think it's a important issue since IE6 is "dying" and nobody sets hash values manually, it also doesn't break applications since the events are still dispatched.
Would be great to have same as crossroads.ignoreState flag to forced dispatch
allow multiple segments at once and merge values later like: hasher.setHash('foo', 'bar', 'ipsum')
- since we have appendHash
, prependHash
and separator
it makes way more sense to pass each segment as a different param than to concat the string manually...
Hi,
What's the best way to reload the current hash? hasher.replace(hasher.getHash()) doesn't work. I want to rerender the current route without a page reload after an ajax-request has completed.
Thanks
Have you considered packaging your project as a nuget package?
revise API to make sure all methods are useful and still makes sense.
change the way separator works (instead of being a param on getHashAsArray to be a public property).
thinking that the best approach to Hasher.stop
is to just stop listening to the changes on the hash (manually and back/forward button) but still dispatch changes made using Hasher.setHash
.
It seems History.js is doing the same thing as your project? Is there anyway anything missing from History.js that you need, as I'll be glad to extend it for your use cases :)
PS. Awesome logo!
unit tests are currently a huge mess... clean it up and split plugins from normal tests.
currently there is only option to get the "real query string" (just after file name), Lucas said that some people use query strings inside the hash to make it easier to retrieve params/values..
maybe change structure of queryUtils to allow getting query from any string (not just from "location.search"..)
see: millermedeiros/js-signals#29 - since hasher may be already initialized it would be good to use an asynchronous signal.
remove js-signals from hasher.js since user may be already using a different version of js-signals and it can cause conflicts and/or increase file size without a reason.
IE8 has some issues while setting a hash value that contains "?" while accessing a local file (it also adds it before the hash but without setting the location.search), it breaks the history stack, so back() and forward() doesn't work as expected.
PS: It works fine online.
If setHash is called, and the resulting changed signal calls replaceHash, then replaceHash replaces the previous history entry instead of the new history entry.
For example: Hash fragment is /, and setHash('/a') is called. Crossroads.js is used to redirect '/a' to '/a/b' (by calling replaceHash). The history after doing this should be '/', '/a/b', but instead, '/' is replaced with '/a/b', so the history is '/a/b', '/a/b'.
It looks like this is caused by setHash and replaceHash updating window.location after calling _registerChange. (setHash's _registerChange triggers replaceHash, and replaceHash replaces window.location before setHash can update window.location.) If they instead updated window.location first, then that would fix this issue (but may raise other issues; I'm not familiar enough with the code and with browser implementations to know).
For now, I'm using this function as a workaround.
function setHashWithPossibleRedirect(hash)
{
var old_hash = window.location.hash.replace(/^#/, '');
hasher.changed.active = false;
hasher.setHash(hash);
hasher.changed.active = true;
hasher.changed.dispatch(hash, old_hash);
}
e.g: "/" for readability
Hasher fails to work in IE9 (and probably IE8; untested) if IE9's Compatibility View is enabled.
From what I can tell, the problem is that, in compatibility mode, IE8 and IE9 report that 'onhashchange' is enabled but don't actually use it. See https://github.com/greggoryhz/MooTools-onHashChange-Event/issues/1 for more details.
Adding this check just below Hasher's private variables initialization seems to fix it:
if (_isIE && _isHashChangeSupported && document.documentMode < 8) {
_isHashChangeSupported = false;
_isLegacyIE = true;
}
I'm not sure why it's failing yet, but I did come across this comment on stack overflow: @xkit explained to me a good feature test to work around the fact that although IE7 doesn't support onhashchange it would still return true for existence inference such as if("onhashchange" in window){/code/} when using IE7 Standard Document Mode in IE8.
It is indeed identifying my IE7 app as supporting Hash Change, although its not working.
from issue #56:
By the way: Right now setting the fragment identifier to #/%F8 in the browser's address bar while hasher is running causes a URIError because decodeURIComponent is called without being wrapped in a try...catch. I would call that a bug.
as described.
So.. w/ out that, it fires 2x for me.
So I added the code from your docs to turn it of.
Does not work. I had to update hasher and signals (to 1.0 - cdnjs has older version only).
Still no work!
I guess since it's async or something. Still fires 2x.
So we need a working setHashSilently.
And it should be a built in function so it's tested.
Please hit me up when you want to work on it. I can hack code to make it happen.
ps: I tried many routers, this works best - I'll show you the private beta site privately.
improve EventDispatcher to block dispatch of specific event types.
probably just overload setHash()
instead of just removing listeners dispose all signals.
since it's an edge-case and the workaround is to use an empty HTML document for the iframe that syncs the document.domain
of both sides I won't implement it.
thinking about adding a '/' before any hash value to avoid conflicts, it fixes the problem but I'm not sure if it's a good idea since depending on the application that may be the desired result.
I've found an issue while trying to do some kind of redirects using your lib.
Test code is this:
function log(msg) {
var elem = document.createElement('div');
elem.innerHTML = msg;
document.body.appendChild(elem);
}
var hashChangeHandler = function(newHash) {
if (newHash === '') {
log('changing hash to "one"');
hasher.replaceHash('one');
} else if (newHash === 'one') {
log('changing hash to "two"');
hasher.replaceHash('two');
} else {
log('hash changed to "two"');
}
};
hasher.initialized.add(function(hash) {
log('inited event fired with hash "' + hash + '"');
hashChangeHandler(hash);
});
hasher.changed.add(function(hash) {
log('changed event fired with hash "' + hash + '"');
hashChangeHandler(hash);
});
window.onload = function() {
hasher.init();
};
Here i'm doing some redirects in "hasher.changed" event using "hasher.replaceHash" method.
So if we'll go to the page containing this script using empty hash, the output will be this:
inited event fired with hash ""
changing hash to "one"
changed event fired with hash "one"
changing hash to "two"
changed event fired with hash "two"
hash changed to "two"
changed event fired with hash "one"
changing hash to "two"
changed event fired with hash "two"
hash changed to "two"
So you can see there are unnecessary change events fired in this case.
This is because of this line in "hasher.setHash" and "hasher.replaceHash" methods in your code:
_registerChange(path); //avoid breaking the application if for some reason `location.hash` don't change
As for me, there is no need to call "_registerChange" in these functions because it will be called by "hashchange" event listener.
I think there is no circumstances when the hash won't change.
You can see it at http://grunin-ya.ru/sandbox/hasher-issue.html
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.