Disable button until tabs have been read - php

I have some tabs which have been created using Javascript and Mootools, my client wants the 'next button' at the bottom of the page to be disabled, until the tabs have been read(clicked). The page is dynamic (created with PHP and MySQL) and there could be two tabs or three, depending on the set-up. I am struggling today to think of the best solution.
Any help more than welcome...

view example working on jsfiddle:
http://www.jsfiddle.net/dimitar/THMxa/
it can work with some classes and logic added to tab clicks and next click.
// fade out next button and set it to disabled, then define the event to check state.
document.id("next").store("disabled", true).set("opacity", .5).addEvent("click", function() {
if (this.retrieve("disabled")) {
alert("please view all tabs first!");
// console.log(document.getElement("div.notclicked"));
return;
}
// insert code here that goes next.
alert("allowed to run");
});
// this is pseudo - you probably already have a function that assigns events on your tabs to change
document.getElements("div.tabs").each(function(tab) {
// first tab may already be open so no click needed
if (!tab.hasClass("clicked"))
tab.addClass("notclicked");
// add click event
tab.addEvent("click", function() {
if (document.getElement("div.notclicked"))
this.addClass("clicked").removeClass("notclicked");
// check again if that was the last one, if so, enable next button...
if (!document.getElement("div.notclicked"))
document.id("next").store("disabled", false).fade("in"); // or whatever
// regular code for tabs here...
});
});

Since the number of tabs is dynamic, I'd probably use an attribute on the tab's header/label/whatever indicating that it has not been read, and then when the tab's header/label/whatever is clicked, I'd change that attribute to indicate that it had been read and then trigger a function that may enable the button depending on whether all the other tabs had been read.
I'm not a MooTools person, but IIRC it's a fork of Prototype (although it's been a while and they've probably diverged). The click handler could look something like this in Prototype:
$$('.tabClass').invoke('observe', 'click', function(event) {
this.setAttribute("data-read", "Y");
if ($$('.tabClass[data-read=N]').length == 0) {
$('buttonId').disabled = false;
}
});
...where $$ is Prototype's "search the DOM for elements matching this CSS selector" function and $ is Prototype's "get me the element with this ID". The invoke there just calls observe for each matching element (you could do this with event delegation instead), and I think observe is fairly self-evident. :-)
The code above makes these assumptions:
Your tab header or whatever has the class "tabClass".
You've created the tables with the attribute "data-read" set to "N" (e.g., <div class="tabClass" data=read="N"> or similar). The data- prefix is to be HTML5-friendly. (Yes, we're finally allowed to put any old arbitrary attribute name on elements if we want to! We just have to prefix them with data-.)
The button has an ID, "buttonId"
The button starts off disabled
Edit Or use a marker class if you prefer, all tabs start out with class="tabClass unread":
$$('.tabClass').invoke('observe', 'click', function(event) {
this.removeClassName("unread");
if ($$('.tabClass.unread').length == 0) {
$('buttonId').disabled = false;
}
});
Double-check that MooTools supports the ".tabClass.unread" selector (it really should, I'm just saying, check). Some implementations may work more quickly with class-based selectors than attribute-based ones.

You should disable the button where you send the request to load the content,
and enable it from the callback that handles the returned content.

I would add a class to the tab when it's clicked - like "clicked". Also, check if the 'click' is the last tab, so..
$('myElement').set('class', 'clicked');
then get all of the tab elements (a elements i assume) and count them.
Then get all of the tab elements with class "clicked"
If they match, they were all 'clicked'.

Related

Two problems regarding AJAX

I created a page which gets filled by a php databasequery (all rows are being read from the MySQL-table and written to the table in HTML). All 10 seconds the same PHP-script gets requested by jQuery AJAX and should refresh the current table content. The return-value of this function will then be used to change the table HTML-value.
There are some buttons in the table. When they're clicked, they toggle from on to off (or vice versa) and another PHP-file gets called with AJAX, which then controls 433MHz wireless sockets via shell commands. Purpose of these 10-seconds ajax-refresh is to synchronize the button with the actual state of the electrical socket (which is saved in the MySQL-database).
$(document).ready(function(){
$(".toggle").click(function() {
if($(this).hasClass("ein")) {
$(this).removeClass("ein");
$(this).html("aus");
$.post("various/executeCode.php", {transmitted:true, id:$(this).attr('id'), toggle:'0'}, function(result) {
});
} else {
$(this).addClass("ein");
$(this).html("ein");
$.post("various/executeCode.php", {transmitted:true, id:$(this).attr('id'), toggle:'1'}, function(result) {
});
}
});
});
window.setInterval("reloadPage()", 5000);
function reloadPage()
{
$.get('various/reloadPage.php', function(data) {
$("#content").html(data);
});
}
$stmt = $dbh->query("SELECT * FROM `funksteckdosen`");
$row = $stmt->fetchAll(PDO::FETCH_ASSOC);
foreach($row as $r)
{
echo "<tr>";
echo " <td>" . $r['name'] . "</td>";
echo " <td><button id='" . $r['id'] . "' class='toggle" . ($r['toggle'] == 0 ? "" : " ein") . "'>"
. ($r['toggle'] == 0 ? "aus" : " ein") . "</button></td>";
echo "</tr>";
}
Now I have the following problem: As soon as the page gets refreshed by AJAX the first time, the buttons stop working. Javascript doesn't execute the click()-function anymore. Why is that?
Problem 2:
The content of the table gets deleted and replaced by the new one. Am I somehow possible to fade new lines (or the button background-color) in, instead of just showing them? That would be the final touch.
I hope you understood my explanations.
The click handlers don't work anymore because the new buttons never had the handlers attached to them. When you attach a handler like this:
$(".toggle").click(function() {
What jQuery does is find all of the currently existing .toggle elements and, for each one, add that function as a handler. Since the new ones are added later via an AJAX call, they're not included in that set and, thus, never have that function attached to them.
The way jQuery address this is with the .on() function. The structure of using is it very similar:
$('body').on('.toggle', 'click', function() {
The difference here is the element which is actually getting the click event bound to the function. With this, the click event is actually being added to the body tag, which isn't changing from the AJAX call. Any unchanging common parent for the dynamic elements will work, 'body' and document are usually used as defaults since they're pretty top-level.
When any child element raises a click event, that event continues up all of the parent elements. So it eventually reaches a common parent, such as 'body'. The .on() function then also has a second selector as its first argument. That selector filters the originating elements of the click event before calling the function.
Benefits of using this approach include:
There's only one event handler function attached to a single common parent, instead of many attached to many elements, which can be a performance improvement on large or complex pages.
Child elements added to the common parent element later in the page's lifespan are still handled, since they will still send their click events to the parent regardless of when they were added. (This is the immediate benefit in your situation.)
As for fading in the content, if I understand the effect you're looking to achieve, you can try something like fading out what's already there, removing it, adding the new content, and then fading it in. Maybe something like this:
$.get('various/reloadPage.php', function(data) {
$('#content').fadeOut(400, function() {
$("#content").html(data);
$('#content').fadeIn();
});
});
There might be newer structures to accomplish this same thing with the relatively newer "promises" model, but essentially what this does is fade the content out and then include a call-back function to call when it's finished fading out. That call-back function replaces the HTML and then fades it back in. Depending on the structure of your HTML you might need to fade out/in a parent element instead of the one I'm targeting, but hopefully you get the idea here and can tweak it until it looks right.
Problem 1: The click event handler is bound to the initial toggle class elements but dynamically created events are not bound.
Try using live() or on() to bind dynamically created elements. See: Event binding on dynamically created elements?
Problem 2: #content is replaced when using html()
Try using append() to add data into an existing element. Using html() will replace the contents of the element.
I have chained a hide() and a fadeIn() to animate the append.
$('#content').append(data).hide().fadeIn(1000);

jQuery jEditables submitting on Tab

I'm creating an inline editable table using jQuery and the editable plug-in.
It works well so far but will only submit and save to the database upon pressing ENTER. I found a thread on here which helped me to tab between boxes but it doesn't submit the data when TAB is pressed.
My code that allows me to switch between boxes is as follows:
$('.editScheduleRow').bind('keydown', function(evt) {
if (evt.keyCode==9) {
var nextBox='';
var currentBoxIndex=$(".editScheduleRow").index(this);
if (currentBoxIndex == ($(".editScheduleRow").length-1)) {
nextBox=$(".editScheduleRow:first"); //last box, go to first
} else {
nextBox=$(".editScheduleRow").eq(currentBoxIndex+1); //Next box in line
}
$(this).find("input").blur();
$(nextBox).click(); //Go to assigned next box
return false; //Suppress normal tab
};
});
To submit using ENTER I use this:
$(".editScheduleRow").editable("../../includes/ajax/save-schedule-row.php", {
"submitdata": function ( value, settings ) {
return { fieldname: this.getAttribute('fieldname'), rowID: this.getAttribute('id') };
},
});
I also found a thread with a suggestion but it didn't work for me: jEditable submit on TAB as well as ENTER
Please let me know if you need any more information.
My original answer was based on reading the documentation of jQuery Editable, which is a jQuery extension that is similarly named, but not the same as jEditable from the question. Let's try again with the correct library.
The problem is that you are moving the focus away from the input box when pressing tab, but when the focus is moved away from it, it doesn't save the contents. To illustrate this, try this: click one of the fields and edit it, then click elsewhere on the document. You'll see that the value in the table - and this is what you where simulating using the blur() jQuery function on the element.
There are (again) two ways to solve this problem. First, we can modify what the program does when a field loses focus:
[..]
"submitdata": function ( value, settings ) {
return { fieldname: this.getAttribute('fieldname'), rowID: this.getAttribute('id')
};
"onblur": "submit";
},
[..]
This has the effect that when doing the experiment I described above to help you understand why it wasn't working, you'll now also see that it gets saved. This may not be what you want. In that case, you can instead make sure that you trigger a submit instead of a blur:
replace this line:
$(this).find("input").blur();
by this one:
$(this).find("form").submit();
Now the experiment will no longer cause the value to be changed, but it's no longer an accurate simulation of what we're doing and when pressing tab the value will be changed.

What is the best way to go about creating a page of stickies with savable and retrievable content?

I have had a look at sticky notes with php and jquery and jStickyNote, and while both seem to look pretty nifty they lack some elements I am after. I haven't been able to find a way to allow particular users to modify the stickies they create, nor have I found a good way to save their stickies into my database. I am, and would like to keep using php, mysql and jquery. I have thought with the first link that I could just save the image created into a folder and save the url into that database but then I cannot go back and allow the user to change the content of the sticky. With the second link there does not seem to be support for saving the sticky at all. I'd also like to create a function where adding stickies to a message board (for everyone to see) does so in a randomly placed way that looks natural. Any ideas for either of these problems?
Here is some javascript that should help:
// Called when the edit (A) button is pressed
function edit(event, editButton)
{
// Get existing title and change element to textarea
var stickyTitle = $(editButton).parent().find('p.stickyTitle');
var textareaTitle = $(document.createElement('textarea')).addClass('textareaTitle');
$(textareaTitle).text(stickyTitle.html());
// Get existing description and change element to textarea
var stickyDescription = $(editButton).parent().find('p.stickyDescription');
var textareaDescription = $(document.createElement('textarea')).addClass('textareaDescription');
$(textareaDescription).text(stickyDescription.html());
// Create save button
var saveButton = $(document.createElement('div')).addClass('jSticky-create');
// Add save button, then replace title, then replace description, then remove edit button
$(editButton).before(saveButton);
$(editButton).parent().find('p.stickyTitle').before(textareaTitle).remove();
$(editButton).parent().find('p.stickyDescription').before(textareaDescription).remove();
$(editButton).remove();
// Set description textarea focus and set button actions
textareaTitle.focus();
setActions();
}
// Called when the save (tick) button is pressed
function save(event, saveButton)
{
// Get existing title and change element to paragraph
var textareaTitle = $(saveButton).parent().find('textarea.textareaTitle');
var stickyTitle = $(document.createElement('p')).addClass('stickyTitle');
var newTitleValue = textareaTitle.val();
$(stickyTitle).html(newTitleValue);
// Get existing description and change element to paragraph
var textareaDescription = $(saveButton).parent().find('textarea.textareaDescription');
var stickyDescription = $(document.createElement('p')).addClass('stickyDescription');
var newDescriptionValue = textareaDescription.val();
$(stickyDescription).html(newDescriptionValue);
// Create edit button
var editButton = $(document.createElement('div')).addClass('jSticky-edit');
// Add edit button, then replace title, then replace description, then remove save button
$(saveButton).before(editButton);
$(saveButton).parent().find('textarea.textareaTitle').before(stickyTitle).remove();
$(saveButton).parent().find('textarea.textareaDescription').before(stickyDescription).remove();
$(saveButton).remove();
// Set button actions
setActions();
// Add the object to the ads div
$('#ads').append(object);
// Update your database here
// by calling the saveAd.php
}
function setActions()
{
// call these after changes are made to anything
$('.jSticky-create').unbind('click').click(function(e)
{
save(e, this);
});
$('.jSticky-edit').unbind('click').click(function(e)
{
edit(e, this);
});
$('.jSticky-delete').unbind('click').click(function(e)
{
remove(e, this);
});
}
function remove(event, deleteButton)
{
var stickyMaster = $(deleteButton).parent();
$(stickyMaster).remove();
//then call savead.php with delete parameter
}
Have you looked at any of the code? I took a really quick look at jStickyNote.
Basically, the "sticky note" is a css-styled, text area (that is surround by a div element).
If you want users to be able to save sticky notes/edit past notes, here's what I'd recommend:
Add some button to each note that says "Save" or with a similar meaning.
When a user clicks the "Save" button, you'll need to grab the text from that specific textarea element and then save that text to a database.
With that said, you'll probably need to design some sort of database with a user table and sticknote table. The sticknote table can have a foreign key to the user table.
You'll also want to add some sort of login functionality to your site and then load the correct sticky notes for the authenticated user.
Good Luck!
You can have a look at http://sticky.appspot.com - the code has been released by the google appengine team.
Sorry for not going into specifics, but you could modify the plugin code to load a php script whenever a save button is clicked (or the box is moved, or even on keyup) with $.ajax(), passing it the horizontal and vertical positions and content of the note ( say, $("#note-content").text() ) and have the script plug those things into a database with a MySQL query. Just serialize your data and send it away. This gets more complicated if you want let your users have multiple notes, but start with one. Where is you hangup, exactly? I would be more specific, but I'm not sure what you already know.
I was thinking earlier about adding this feature to an app I'm working on. The thing is, I don't like those plugins. It should be very simple to write your own though. Let me know if you need help with something specifically.

retrieve window.location.hash url in php

I am using a jquery tabbed interface here http://www.imashdigital.com/#2 and would like to return the tab number in php.
Ideally I would like to run a javascript function (on a timer) that continually updates a global php variable with the current tab.
Based on this php value, 1 through to 4, I will then load a different sidebar.
I would be grateful for any help and some code examples as I am a novice.
Kind regards
Jonathan
The part of an URI that comes after the hash is never sent to the server. There is no way that PHP can access it. Use a querystring parameter ($_GET) instead. Or use client side scripting (javascript).
I would suggest you do not run a timer but instead attach the $.post to the event "tab activation". This will make any tab change applied in real time and it won't trigger needless requests.
I have used tabbed panels in a couple recent projects, and the solution I've used is the following:
HTML
<ul class="tabs">
<li>English</li>
<li>Français</li>
</ul>
<div class="panel" id="en_en"><!-- Content --></div>
<div class="panel" id="fr_fr"><!-- Content --></div>
jQuery
// the currently selected tab, or a default tab (don't forget to prepend the #)
var tab = location.hash || '#en_en';
// register a click handler on all the tabs
$('ul.tabs a').click(function(event){
event.preventDefault(); // prevents the browser from scrolling to the anchor
// hide all panels, then use the link's href attribute to find
// the matching panel, and make it visible
// you can, of course, use whatever animation you like
$('div.panel').hide().filter( $(this).attr('href') ).show();
).filter('[href*='+tab+']').click();
// above: in case of refreshing/bookmarking: find the tab link that contains
// the current location.hash, and fire its click handler
It works well because the server-side code doesn't need to know which tab is selected, but it also supports refreshing or bookmarking a specific tab without requiring the user select the tab again.

jquery hide problem

I use this to toggle my div elements, and hide all them when the DOM is ready...
$('div[class*="showhide"]').hide();
$('input:image').click( function() {
var nr = $(this).attr('id').substr(7,2);
$('div.showhide' + nr).toggle(400);
});
I have dynamically created div elements with class showhide0;showhide1;showhide2...etc...
Inside the DIV tags I have search boxes.
First when page is loaded all DIV tags hide.
I toggle one of them to show.
Start a search, so the page is reloaded with the result of the query.
Of course all DIV is hide again, because the page is reloaded. Unfortunately...
Is it possible to not hide again after I searched for something? It would be nice when I open the page, all the divs are hidden, but after then just when I toggle it...
If you need a specific element or elements to stay visible upon a page reload, then you're going to need to do something to maintain state across requests, and then modify your jQuery to utilize that state information when initializing the visible state of the elements.
This can be done in numerous ways which include but are not necessarily limited to
Include it in the query string
Include it in the URL hash
Use a cookie
Well, yeah, you just don't run the initial hide() if there's a search request. I'd just exclude that line from the output if, on the PHP level, you know you're executing a search.
We do something similar to this where I work.
We opted instead of have the class name just be hide for all elements and instead have the ids named.
So, we'd have it something like:
<div id="hide1" class="hide"> </div>
along with this CSS to hide all those divs by default
.hide {
display: none;
}
Finally, we use something like this to show them:
$('input:image').click( function() {
var nr = $(this).attr('id').substr(7,2);
$('#hide' + nr).toggle(400);
});
}
This works because of CSS precedence rules. The toggle()/hide()/show() method overrides the hide class's style.
As for the unhiding part, if you pass the ID to unhide to your script, you can parse it and unhide the appropriate div.
You can read and process the query string from window.location.search. Unfortunately, you then have to manually parse it or use a plugin, such as jQuery Query String Object or jQuery URL Utils.
var id = $.query.get('unhide_id'); // This is using Query String Object
$('#' + id).show(400);

Categories