Today I'm using the built-in cookies of the jsTree in order to preserve user navigations in the tree.
on node click in the tree the user is redirected to the corresponding page in my site and the clicked node is selected/highlighted thanks to the jsTree cookies integration.
Now, I would like to to select/highlight nodes in the tree also based on a navigation among the web site, i.e., a link in the site might also be a node in the tree, for example, a grid of rows that also appears in the tree.
The question is how can I do this 'manually' node selection/highlighting and I also think that I should know from where the user arrived to the page, from the tree or from some other link in the site.
Thanks,
I already built a complete approach for this using jsTree, hashchange event and actual real SEO-able URLs so this would fit into your idea quite simply and you could toss your cookies but not in a bad way. This also works with bookmarking and arriving from a URL as it looks through the nodes then matches the links to select the node. This is best with AJAX though as it should be when possible.
I'm commenting this for you so you can understand it. The working example is here www.kitgui.com/docs that shows all the content.
$(function () {
// used to remove double reload since hash and click are intertwined
var cancelHashChange = false,
// method sets the selector based off of URL input
setSelector = function (path) {
var startIndex = path.indexOf('/docs');
if (startIndex > -1) {
path = path.substr(startIndex);
}
path = path.replace('/docs', '').replace('/', '');
if ($.trim(path) === '') { path = 'overview'; }
return '.' + path;
};
// sets theme without the folders, plain jane
$('.doc-nav').jstree({
"themes": {
"theme": "classic",
"dots": true,
"icons": false
}
}).bind("loaded.jstree", function (event, data) {
// when loaded sets initial state based off of priority hash first OR url
if (window.location.hash) { // if hash defined then set tree state
$.jstree._focused().select_node(selector);
$(setSelector(window.location.hash.substr(1)) + ' a:first').trigger('click');
} else { // otherwise base state off of URL
$.jstree._focused().select_node(setSelector(window.location.pathname));
}
});
// all links within the content area if referring to tree will affect tree
// and jump to content instead of refreshing page
$('.doc-nav a').live('click', function (ev) {
var $ph = $('<div />'), href = $(this).attr('href');
ev.preventDefault();
cancelHashChange = true;
// sets state of hash
window.location = '#' + $(this).attr('href');
$('.doc-content').fadeOut('fast');
// jQuery magic load method gets remote content (John Resig is the man!!!)
$ph.load($(this).attr('href') + ' .doc-content', function () {
cancelHashChange = false;
$('.doc-content').fadeOut('fast', function () {
$('.doc-content').html($ph.find('.doc-content').html()).fadeIn('fast');
});
});
});
// if doc content is clicked and has referring tree content,
// affect state of tree and change tree content instead of doing link
$('.doc-content a').live('click', function (ev) {
ev.preventDefault();
if ($(this).attr('href').indexOf('docs/') > -1) {
$.jstree._focused().select_node(setSelector($(this).attr('href')));
$(setSelector($(this).attr('href')) + ' a:first').trigger('click', false);
}
});
// if back/forward are used, maintain state of tree as if it was being clicked
// refers to previously defined click event to avoid double-duty
// but requires ensuring no double loading
window.onhashchange = function () {
if (cancelHashChange) { cancelHashChange = false; return; }
$.jstree._focused().select_node(setSelector(window.location.hash.substr(1)));
$(setSelector(window.location.hash.substr(1)) + ' a:first').trigger('click', false);
};
$('#top-doc-link').closest('li').addClass('active');
});
Feel free to ask me if you have more questions.
Related
The case:
I use dojo to request a page and load it into a div ( view ).
The problem:
The content that gets loaded into a form contains a dojo form and relevant objects, textbox, etc... how can I controller these widgets? I believe the current way I am working around the issue is sloppy and could be more refined.
Comments are in the code to help explain the issue I have. Please let me know your thoughts.
function (parser, domAttr, util, ready, dom, on, request, domStyle, registry, TextBox) {
//This prepares the doc main html page We are looking for a click of a menu option to load in thats pages pages content
ready(function () {
//Look for click of menu option
on(dom.byId('steps'), "a:click", function(e) {
event.preventDefault();
//Get the div we are going to load the page into
var view = domAttr.get(this, "data-view");
// function that loads the page contents
load_page(view);
});
});
function load_page(view) {
//First I see if this page already has widgets and destroy them
//We do this so users can toggle between menu items
// If we do not we get id already registered
var widgets = dojo.query("[widgetId]", dom.byId('apply-view')).map(dijit.byNode);
dojo.forEach(widgets, function(w){
w.destroyRecursive();
});
//get the html page we are going to user for the menu item
request.post("/apply_steps/"+view, {
data: {
id: 2
}
}).then(
function(response){
//Add the content and parse the page
var parentNode = dom.byId('apply-view');
parentNode.innerHTML = response;
parser.parse(parentNode);
//This is where it is sloppy
//What I would prefer is to load a new js file the controlls the content that was just loaded
//What happens now is I create a traffic director to tell the code what main function to use
controller_director(view);
},
function(error){
util.myAlert(0, 'Page not found', 'system-alert');
});
}
function controller_director(view) {
//based on the view switch the function
switch(view) {
case 'screening_questions':
screening_questions();
break;
}
}
function screening_questions() {
//Now we are controlling the page and its widgets
// How would I get this info into a seperate js file that i would load along with the ajax call??
ready(function () {
on(dom.byId('loginForm'), "submit", function(e) {
event.preventDefault();
var formLogin = registry.byId('loginForm');
authenticate();
});
});
this.authenticate = function() {
var formLogin = registry.byId('loginForm');
if (formLogin.validate()) return;
}
}
});
Ok, so I need some insight into working with History.js and jQuery.
I have it set up and working (just not quite as you'd expect).
What I have is as follows:
$(function() {
var History = window.History;
if ( !History.enabled ) {
return false;
}
// Capture all the links to push their url to the history stack and trigger the StateChange Event
$('.ajax-link').click(function(e) {
e.preventDefault();
var url = this.href; //Tells us which page to load
var id = $(this).data('passid'); //Pass ID -- the ID in which to save in our state object
e.preventDefault();
console.log('url: '+url+' id:'+id);
History.pushState({ 'passid' : id }, $(this).text(), url);
});
History.Adapter.bind(window, 'statechange', function() {
console.log('state changed');
var State = History.getState(),
id = State.data.editid; //the ID passed, if available
$.get(State.url,
{ id: State.data.passid },
function(response) {
$('#subContent').fadeOut(200, function(){
var newContent = $(response).find('#subContent').html();
$('#subContent').html(newContent);
var scripts = $('script');
scripts.each(function(i) {
jQuery.globalEval($(this).text());
});
$('#subContent').fadeIn(200);
});
});
});
}); //end dom ready
It works as you'd expect as far as changing the url, passing the ID, changing the content. My question is this:
If I press back/forward on my browser a couple times the subContent section will basically fadeIn/fadeOut multiple times.
Any insight is appreciated. Thanks
===================================================
Edit: The problem was in my calling all of my <script> and Eval them on each statechange. By adding a class="no-reload" to the history controlling script tag I was able to do:
var scripts = $('script').not('.no-reload');
This got rid of the problem and it now works as intended. Figure I will leave this here in case anyone else runs into the same issue as I did.
The problem was in my calling of all of my <script> and Eval them on each statechange. By adding a class="no-reload" to the history controlling script tag I was able to do:
var scripts = $('script').not('.no-reload');
This got rid of the problem and it now works as intended. Figure I will leave this here in case anyone else runs into the same issue as I did.
I have a dijit tree that when a node is clicked it loads an html page in the center content page. One of the html pages is a login page and I'd like to check a cookie to see if they have already logged on, so I can set the page appropriately if the page gets re-loaded. Is there a way to check for a cookie on page load, or perhaps a better method than this? Thanks
my code for the tree is:
TOCSet: function (TOCStore) {
var myModel = new ObjectStoreModel({
store: TOCStore,
query: { root: true }
});
// Create the Tree.
var tree = new Tree({
model: myModel,
onClick: function (item, node, evt) {
// Get the URL from the item, and navigate to it
evt.preventDefault();
var href = item.url;
registry.byId('Content').set('href', href); //set the page on node clicks
}
});
tree.placeAt("TOC");
tree.startup();
ready(function () {
registry.byId("Content").set("href", "Login.htm");//set the login page at start
});
}
I set the cookie using "dojo/cookie" after successful login
function SetLoginCookie(lia) {
cookie("LoggedInAs", lia);
}
and then used "dojo/ready" to check for the cookie when the page reloads
ready(function () {
var lia = cookie("LoggedInAs");
alert(lia + " is logged in");
});
I am using this code:
$(function () {
// For each .bbq widget, keep a data object containing a mapping of
// url-to-container for caching purposes.
$('.bbq').each(function () {
$(this).data('bbq', {
cache: {
// If url is '' (no fragment), display this div's content.
'': $(this).find('.bbq-default')
}
});
});
// For all links inside a .bbq widget, push the appropriate state onto the
// history when clicked.
$('.bbq a[href^=#]').live('click', function (e) {
var state = {},
// Get the id of this .bbq widget.
id = $(this).closest('.bbq').attr('id'),
// Get the url from the link's href attribute, stripping any leading #.
url = $(this).attr('href').replace(/^#/, '');
// Set the state!
state[id] = url;
$.bbq.pushState(state);
// And finally, prevent the default link click behavior by returning false.
return false;
});
// Bind an event to window.onhashchange that, when the history state changes,
// iterates over all .bbq widgets, getting their appropriate url from the
// current state. If that .bbq widget's url has changed, display either our
// cached content or fetch new content to be displayed.
$(window).bind('hashchange', function (e) {
// Iterate over all .bbq widgets.
$('.bbq').each(function () {
var that = $(this),
// Get the stored data for this .bbq widget.
data = that.data('bbq'),
// Get the url for this .bbq widget from the hash, based on the
// appropriate id property. In jQuery 1.4, you should use e.getState()
// instead of $.bbq.getState().
url = $.bbq.getState(that.attr('id')) || '';
// If the url hasn't changed, do nothing and skip to the next .bbq widget.
if (data.url === url) { return; }
// Store the url for the next time around.
data.url = url;
// Remove .bbq-current class from any previously "current" link(s).
that.find('a.bbq-current').removeClass('bbq-current');
// Hide any visible ajax content.
that.find('.bbq-content').children(':visible').hide();
// Add .bbq-current class to "current" nav link(s), only if url isn't empty.
url && that.find('a[href="#' + url + '"]').addClass('bbq-current');
if (data.cache[url]) {
// Since the widget is already in the cache, it doesn't need to be
// created, so instead of creating it again, let's just show it!
data.cache[url].show();
} else {
// Show "loading" content while AJAX content loads.
that.find('.bbq-loading').show();
// Create container for this url's content and store a reference to it in
// the cache.
data.cache[url] = $('<div class="bbq-item"/>')
// Append the content container to the parent container.
.appendTo(that.find('.bbq-content'))
// Load external content via AJAX. Note that in order to keep this
// example streamlined, only the content in .infobox is shown. You'll
// want to change this based on your needs.
.load(url, function () {
// Content loaded, hide "loading" content.
that.find('.bbq-loading').hide();
});
}
});
})
// Since the event is only triggered when the hash changes, we need to trigger
// the event now, to handle the hash the page may have loaded with.
$(window).trigger('hashchange');
});
from here: http://benalman.com/code/projects/jquery-bbq/examples/fragment-advanced/
It is caching the dynamically loaded content. I want to expire this cache after every 10 seconds. I am not so pro at JQuery. How can I achieve this? Please help!
UPDATE
I tried this code:
<script type="text/javascript" src="jquery.timer.js"></script>
<script type="text/javascript">
var timer = $.timer(function () {
$('.bbq').removeData('.bbq-content');
});
timer.set({ time: 5000, autostart: true });
</script>
The code is reaching $('.bbq').removeData('.bbq-content'); line every 5 seconds, but its not clearing the cache. Unable to show updated results. Please help!
You don't need to clear cached data every 10 seconds; you just need to check whether the cached data is older than 10 seconds before showing it.
First, we need a place to save timestamps for each piece of cached data. Replace the first chunk of code with this:
$('.bbq').each(function () {
$(this).data('bbq', {
cache: {
// If url is '' (no fragment), display this div's content.
'': $(this).find('.bbq-default')
},
cacheTimes: {} // <-- this line is new (plus the comma above)
});
});
Then, when a hashchange event occurs, we need the current time:
// Bind an event to window.onhashchange that, when the history state changes,
// iterates over all .bbq widgets, getting their appropriate url from the
// current state. If that .bbq widget's url has changed, display either our
// cached content or fetch new content to be displayed.
$(window).bind('hashchange', function (e) {
var now = (new Date()).getTime(); // <-- this line is new
// Iterate over all .bbq widgets.
$('.bbq').each(function () {
And for each widget, we check if enough time has elapsed to invalidate the cache:
// Get the url for this .bbq widget from the hash, based on the
// appropriate id property. In jQuery 1.4, you should use e.getState()
// instead of $.bbq.getState().
url = $.bbq.getState(that.attr('id')) || '';
// this chunk is new
if (url !== '' && now - (data.cacheTimes[url] || 0) > 10000) { // 10 seconds
data.url = null;
if (data.cache[url]) {
data.cache[url].remove();
data.cache[url] = null;
}
}
// If the url hasn't changed, do nothing and skip to the next .bbq widget.
if (data.url === url) { return; }
When fetching data, we remember the current time:
// Show "loading" content while AJAX content loads.
that.find('.bbq-loading').show();
data.cacheTimes[url] = now; // <-- this line is new
// Create container for this url's content and store a reference to it in
// the cache.
data.cache[url] = $('<div class="bbq-item"/>')
I have this bxslider code.
$(function(){
$('#slider1').bxSlider({
infiniteLoop: false,
hideControlOnEnd: true
});
});
and ihave this ajax code:
$(function () {
$.get('/Scripts/PagedList/PagedList.Mvc.Template.html', function (pagerTemplate) { // get template for pager
// create our pager control object
var pagedList = $.pagedList(
$.template(null, pagerTemplate), // convert into compiled template
function(pageNumber){
return '/home/ajax/#' + pageNumber; // give the pager control the url for loading this page
},
{ pagesToDisplay: 10 } // optional page render options
);
function showNamesAndPagerControl(p) {
$.getJSON("/home/ajaxpage", { page: p ? p : 1 }, function (data) { // default to page 1
$("#namesList")
.attr("start", data.pager.FirstItemOnPage) // update the <li> numbers
.html($("#namesTemplate").tmpl(data.names)); // show the names for this page
$("#namesPager").html(pagedList.render(data.pager)); // update the pager control
}).error(function () {
// if we hit an error (such as a 404), try loading the first page
if (p !== 1) // don't do this if we just tried to load the first page
showNamesAndPagerControl(1);
});
}
// get current url hash (ex: "#3" for page 3)
var hash = window.location.hash;
if (hash)
hash = hash.slice(1); // chop off the leading "#"
// load whatever the currently requested page is
showNamesAndPagerControl(hash);
$(".PagedList-pager a").live("click", function (ev) {
ev.preventDefault(); // don't let the page actually navigate
var pageNumber = $(this).data('page'); // load the pagenumber from the link's data-pager attribute
showNamesAndPagerControl(pageNumber);
window.location.hash = pageNumber; // update the url hash
});
});
});
I want to integrate this ajax to bxslider.
how can i do it?
To use this with ajax is depending on how your data comes back from your server. If it's coming back and has already been formatted on the server side, then you should be able to just do:
$.getJSON({
success:function(data){
$(data).appendTo($('wherever'));
$(data).find('#yourItem').bxSlider();
}
}
If it's not formatted server side, then you just have to format it in your javascript and then apply bxSlider() to it. I feel like maybe I'm not quite getting your question?
If you're still having problems feel free to clarify a little more if you're struggling with the ajax portion of it, or applying the bxslider more.