Re-trigger event from event - events

Here's a search box module (heavily sanitised to satisfy boss). It all works, apart from the more event. I get the results, they appear, and the "load more" div appears.
On clicking more i would like the search event to rerun. In more, i do some trivial session calculations which i need to pass to the search event, which works. The click() does not.
I've tried moving the more event outside of the search event, without success.
This fiddle seems to work, albeit with the node ID instead.
define([
'dojo/dom',
'dojo/dom-construct',
'dojo/on',
'dojo/query'
'dojo/domReady!'
], function(
dom,
domConstruct,
on,
query
) {
var search = {
display: function(){
sb = '<div id="searchWrapper" class="searchWrapper"><h3>Search</h3>
<input id="searchString" type="text" />';
sb += '<h3>Search</h3><select id="sBy">';
sb += '<option value="0">Choose...</option>';
sb += '<option value="f">Foo</option>';
sb += '<option value="b">Bar</option>';
sb += '<option value="fb">Foo & Bar</option>';
sb += '</select>';
sb += '<div class="searchBtn">
<button type="button" id="search">Search</button></div>';
sb += '</div>';
domConstruct.place(sb, dom.byId('body'), 1);
on(dom.byId('search'), 'click', function(e){
var r = thisIsWhereDataIsRetrieved(params, whatever);
// r is the response from the db call
if(typeof r === 'object'){
var sr = 'here are the results!';
for (var result in r) {
sr += 'this particular result';
}
if(r.length === 50) {
sr += '<div id="more" class="more">Load More</div>';
}
domConstruct.place(sr, dom.byId('searchWrapper'), 'last');
}
on(query('.more'), 'click', function(e){
// get next results having done stuff
// to track the state of the search, which works
dom.byId('search').click(); <<<<< not working
});
});
}
}
return search;
});
EDIT: I got around this by re-calling thisIsWhereDataIsRetrieved inside the more event and appending the next results before the more node, but it still seems as though it'd be better to do what i can't!
EDIT2: added more node!

You need to use something else than an anonymous function.
For instance, something like this:
(note you may need to have a better construction than the actual method, using query may have side effects if you do not clean properly the dom. I encourage you to write a proper widget and to use attach-points)
define([
'dojo/dom',
'dojo/dom-construct',
'dojo/on',
'dojo/query'
'dojo/domReady!'
], function(
dom,
domConstruct,
on,
query
) {
var search = {
display: function() {
sb = '<div id="searchWrapper" class="searchWrapper"><h3>Search</h3>
<input id="searchString" type="text" />';
sb += '<h3>Search</h3><select id="sBy">';
sb += '<option value="0">Choose...</option>';
sb += '<option value="f">Foo</option>';
sb += '<option value="b">Bar</option>';
sb += '<option value="fb">Foo & Bar</option>';
sb += '</select>';
sb += '<div class="searchBtn">
<button type="button" id="search">Search</button></div>';
sb += '</div>';
domConstruct.place(sb, dom.byId('body'), 1);
var onSearchClick = function(e) {
var r = thisIsWhereDataIsRetrieved(params, whatever);
// r is the response from the db call
if (typeof r === 'object') {
var sr = 'here are the results!';
for (var result in r) {
sr += 'this particular result';
}
if (r.length === 50) {
sr += '<div id="more" class="more">Load More</div>';
}
domConstruct.place(sr, dom.byId('searchWrapper'), 'last');
}
on(query('.more'), 'click', function(e) {
// get next results having done stuff
// to track the state of the search, which works
onSearchClick();
});
}
on(dom.byId('search'), 'click', function(e) {
// get next results having done stuff
// to track the state of the search, which works
onSearchClick();
});
}
}
return search;
});

Related

AJAX Dynamic Buttons

Does anyone have suggestions on how to complete the following assignment? I've listed the instructions from the teacher below along with my JavaScript code. Thanks in advance!
Instructions:
The primary task is to dynamically generate the "genre" buttons that are currently hardcoded into the correlating HTML file.
The genre buttons should work the same way the hardcoded buttons currently work meaning they should have an event listener attached to them that should display podcasts from the ajax response that match the genre that was clicked.
JavaScript Code:
/**
* Ajax GET requester
*
*/
function get(url){
// Return a new promise.
return new Promise(function (resolve, reject){
// Do the usual XHR stuff
var req = new XMLHttpRequest();
req.open('GET', 'js/data.json');
req.onload = function(){
// This is called even on 404 etc
// so check the status
if(req.status === 200){
// Resolve the promise with the response text
resolve(req.response);
}else{
// Otherwise reject with the status text
// which will hopefully be a meaningful error
reject(Error(req.statusText));
}
};
// Make the request
req.send();
});
}
function get_podcasts(genre){
var url = 'js/data.json';
get(url).then(function (response){
var body = document.getElementById('mainContent');
response = JSON.parse(response);
if(response.results.length > 0){
body.innerHTML = '';
for(var i = 0; i < response.results.length; i++ ){
if(response.results[i].primaryGenreName === genre ){
var image = '<img src="' + response.results[i].artworkUrl100 + '">';
var image = document.createElement('img');
image.src = response.results[i].artworkUrl100;
body.appendChild(image);
body.innerHTML += '<div>' + response.results[i].trackName + '</div>' ;
}
}
}else{
body.innerHTML = 'No results found.';
}
console.log(response);
}, function (error){
console.log('No hits Found');
});
}
window.onload = function(){
//create an array with all button names
var genreNames = ['TV & Film', 'News & Politics', 'Society & Culture', 'Music', 'Hobbies'];
//loop through the array
for(var i = 0; i < genreNames.length; i++){
//create button element called "TV and Film" or whatever
var dynamicButtons = document.createElement('BUTTON');
var buttonText = document.createTextNode(genreNames);
//add it to the DOM (document)
dynamicButtons.appendChild(buttonText);
document.body.appendChild(dynamicButtons);
}
/*
for(i =0; i <= response.results.length; i++) {
for (key in response.results[i].primaryGenreName) {
if(response.results[i].primaryGenreName.hasOwnProperty(key)) {
output += '<li><button type="button">' + response.results[i].primaryGenreName + '</button></li>';
var update = document.getElementById('genres');
update.innerHTML = output;
}
}
}
*/
};

Google Map doesn't appear on load

I am developing an app where I use 2 API's a.k.a Instagram API and Google Map API. Using AJAX, I get the first set of Images filtered by a tag name. In the 1st set we receive 20 images. Among the received images, the images that have the latitude and longitude info (geotagged images) are displayed on the map.
Now the first time when my page loads, I cannot see the map. But when I press the load more button to get the next set of images, the Map works fine showing my previous images too.
Here is the code for what happens on page load:
$( window ).load(function() {
$.ajax({
type: "GET",
url: "https://api.instagram.com/v1/tags/nyc/media/recent?client_id=02e****",
dataType:'JSONP',
success: function(result) {
onAction(result, 2, tag);
instaMap(result, 2, from);
}
});
});
These are the functions being called:
/**
* [initialize description]
* Initialize the map with markers showing all photos that are geotagged.
*/
var initialize = function(markers) {
var bounds = new google.maps.LatLngBounds(),
mapOptions = {
scrollwheel: false,
mapTypeId: 'roadmap',
center: new google.maps.LatLng(22.50, 6.50),
minZoom: 2
},
gmarkers = [],
map,
positions,
markCluster;
markers = remDuplicate(markers);
// Info Window Content
var infoWindowContent = [];
for (var j = 0; j < markers.length; j++ ) {
var content = [
'<div class="info_content">' +
'<h3>' + markers[j][2] + '</h3>' +
'<a href="' + markers[j][3] + '" target="_blank">' +
'<img src="' + markers[j][4] + '" style="z-index:99999">' + '</a>' +
'</div>'
];
infoWindowContent.push(content);
}
// Display a map on the page
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
map.setTilt(45);
// Display multiple markers on a map
var oms = new OverlappingMarkerSpiderfier(map);
var infoWindow = new google.maps.InfoWindow(), marker, i;
// Loop through our array of markers & place each one on the map
for( i = 0; i < markers.length; i++ ) {
positions = new google.maps.LatLng(markers[i][0], markers[i][1]);
marker = new google.maps.Marker({
position: positions,
map: map,
animation:google.maps.Animation.BOUNCE,
title: markers[i][2]
});
oms.addMarker(marker);
// Allow each marker to have an info window
google.maps.event.addListener(marker, 'click', (function(marker, i) {
return function() {
infoWindow.close();
infoWindow.setContent(infoWindowContent[i][0]);
infoWindow.open(map, marker);
map.setCenter(marker.getPosition());
};
})(marker, i));
gmarkers.push(marker);
}
google.maps.event.addListener(map, 'click', function() {
infoWindow.setMap(null);
});
markCluster = new MarkerClusterer(map, gmarkers);
// Override our map zoom level once our fitBounds function runs (Make sure it only runs once)
var boundsListener = google.maps.event.addListener((map), 'bounds_changed', function(event) {
map.setZoom(2);
google.maps.event.removeListener(boundsListener);
});
};
/**
* [onAction]
* OnAction() function helps in loading non-geotagged pics.
*
* #param {[type]} result [Result retruned from the Instagram API in json format]
* #param {[type]} likey [hearts the user has entered as per which the posts will be filtered]
*/
var onAction = function (result, likey, tag) {
$('.load-pics').remove();
if (result.pagination.next_url) {
paginate = removeURLParameter(result.pagination.next_url, 'count');
}
$.each(result, function(key, value) {
if (key === 'data') {
$.each(value, function(index, val) {
liked = val.likes.count;
link = val.link;
imgUrl = val.images.low_resolution.url;
locations = val.location;
if (liked >= likey) {
if (locations === null) {
output = '<li class="img-wrap">' + '<div class="main-img">' +
'<a href="' + link + '" target="_blank">' +
'<img src="' + imgUrl + '" ><span class="hover-lay"></span></a>' +'<p>' +
'<span class="heart"></span><span class="likes-no">' + liked + '</span>' +
'<span class="comment-box"></span><span class="comment-no">' +
val.comments.count + '</span> ' + '</p>' + '</div>' +
'<div class="img-bottom-part">'+ '' + '<div class="headin-hastag">' +
'by ' + '<h2>Sebastien Dekoninck</h2>#hello <span>#kanye</span> #helloagain #tagsgohere</div>'
+'</div></li>';
$('#instafeed').append(output);
}
}
});
}
});
if ($('#instafeed').children().length === 0) {
alert('There are no pics with ' + likey + ' likes or #' + tag + ' was not found.');
} else {
// $('.not-geo').remove();
// $('#instafeed').before('<button class="not-geo">Click To See Images That Are Not Geotagged <img src="assets/imgs/down.png" ></button>');
}
$('#instafeed').append('<div class="load-pics"><button id="show-more">Show more <span></span></button> </div>');
};
/**
* [instaMap]
* instaMap() will be the function which will deal with all map based functionalities.
*/
var instaMap = function(result, likey, from) {
$('.load-mark').remove();
if (result.pagination.next_url) {
pagiMap = removeURLParameter(result.pagination.next_url, 'count');
}
$.each(result, function(key, value) {
if (key === 'data') {
$.each(value, function(index, val) {
liked = val.likes.count;
link = val.link;
imgUrl = val.images.low_resolution.url;
locations = val.location;
if (liked >= likey) {
if (locations && locations.latitude !== null) {
tempArr = [
locations.latitude,
locations.longitude,
val.user.username,
val.link,
val.images.low_resolution.url
];
mark.push(tempArr);
}
}
});
}
});
if (mark.length) {
initialize(mark);
$('.map-parent-wrapper').append('<div class="load-mark"><button id="show-mark">See More </button></div>');
} else {
alert('No geotagged pics found in the retrieved set. Click see more');
$('.map-parent-wrapper').append('<div class="load-mark"><button id="show-mark">See More </button></div>');
}
};
I have created a See More button to retrieve the next set of images and load those on the Map. When clicking see more, everything seems to work fine. Not sure why it's happening so. Console.log does not show any error. Also, all the values I feed does flow appropriately. I even tried clearing cache. Not sure, why it's happening.
If instaMap is the function which is going to handle all your map based functionality, it has to be the one that loads map in your $( window ).load function ();
Otherwise, if you want Google maps to load on initial window load you need to put below in there:
google.maps.event.addDomListener(window, 'load', initialize);

AJAX Jquery: execution order of events

I have a webpage with different elements (a list of links and two select boxes) connected between them. Clicking on them may affect one of the other element and all of their values contribuite to update a value to show on the page.
So, the code is this:
$(document).ready(function() {
var someVar = '';
$("select#size").bind('change', function() {
someVar = $(this).val();
console.log('first');
});
my_change();
console.log('second' + someVar);
});
function my_change() {
$.getJSON("photos/change_product", {json_stuff}, function(data) {
var options = [];
for (var i = 0; i < data.length; i++) {
options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>');
}
$("select#size").trigger('change');
$("select#options").html(options.join('')).trigger('change');
})
};
};
When I load the page the my_change function is called. It does some stuff and then triggers a change event on a select-box. I need to update a value using what's inside this select box and only then let the execution to proceed. So what I need this code to do would be to print 'first', and then 'second' with the value of the variable. What actually happen is that it prints 'second' 'first'.
I think it's because I'm doing asynchronous calls. What can I do?
There's several ways to do this.
You could use jQuery $.when and call the console.log after the ajax response finishes.
$(document).ready(function() {
var someVar = '';
$("select#size").bind('change', function() {
someVar = $(this).val();
console.log('first');
});
$.when( my_change() ).then(function(){
console.log('second' + someVar);
});
});
function my_change() {
return $.getJSON("photos/change_product", {json_stuff}, function(data) {
var options = [];
for (var i = 0; i < data.length; i++) {
options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>');
}
$("select#size").trigger('change');
$("select#options").html(options.join('')).trigger('change');
})
};
};
Or you could add a callback argument to the my_change(callback) function.
$(document).ready(function() {
var someVar = '';
$("select#size").bind('change', function() {
someVar = $(this).val();
console.log('first');
});
my_change(function(){ console.log('second' + someVar) } );
});
function my_change(callback) {
return $.getJSON("photos/change_product", {json_stuff}, function(data) {
var options = [];
for (var i = 0; i < data.length; i++) {
options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>');
}
$("select#size").trigger('change');
if( typeof callback !== 'undefined' && typeof callback === 'function' )
callback();
$("select#options").html(options.join('')).trigger('change');
})
};
};
The 'second' console.log() is being called first since the asynchronous $.getJSON() call waits for the response from the server before firing its callback function. You could save the jqXHR object to a variable and then use that to run your 'second' consone.log() with $.when():
$(function() {
var someVar = '';
$("#size").on('change', function() {//on() is the same as bind() here
someVar = $(this).val();
console.log('first');
});
//save the jQuery XHR object from your $.getJSON request
var jqXHR = my_change();
//when the above jQuery XHR object resolves, it will fire the second console.log
$.when(jqXHR).then(function () {
console.log('second' + someVar);
});
});
function my_change() {
//here we return the jQuery XHR object for the $.getJSON request so we can run code once it resolves
return $.getJSON("photos/change_product", {json_stuff}, function(data) {
var options = [];
for (var i = 0; i < data.length; i++) {
options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>');
}
$("#size").trigger('change');
$("#options").html(options.join('')).trigger('change');
})
};
Here is documentation for $.when(): http://api.jquery.com/jquery.when
A quick side-note: it is generally slower to add a tag-type to a selector, especially when you are selecting IDs as that is already a very fast method of selecting elements.
Any code that relies on the response of the getJSON must be placed in, or called from, the getJSON callback.
That's what a callback is for.
You should note that your my_change function will not have access to the someVar variable because it is local to the ready() callback.
To remedy this, move the my_change function inside the ready() callback.
Or just pass a function directly to my_change.
my_change(function() {
console.log('second' + someVar);
});
And have the getJSON callback invoke the function.
function my_change( func ) {
$.getJSON("photos/change_product", {json_stuff}, function(data) {
var options = [];
for (var i = 0; i < data.length; i++) {
options.push('<option value="' + data[i].id + '">' + data[i].label + '</option>');
}
$("select#size").trigger('change');
$("select#options").html(options.join('')).trigger('change');
func();
});
}

jQuery pagination kills my toggle switches

My page shows posts stored in my Database through a loop. Each post is paired with a like and dislike button. The page has two master controls switches that show/hide all liked posts and show/hide all dislike posts.
This all works perfectly. I am now trying to paginate said posts while still keeping the above functions intact. This is proving difficult. In short, if I click on a div with class "like" var value is set to "1" and ajax fires, storing that value in my database and returns a success message. The same happens for dislike with the difference being that var value is set to "0".
If the user chooses to hide all liked posts, they do indeed hide but no other posts pop up in their places. I'd like it for the pagination to ALWAYS display X results per page even after some posts get toggled. As it is, If I hide 3 of 5 posts, only 2 posts remain instead of having 3 next posts come in.
imtech_pager.js looks for a div called "contained" and looks inside it for all divs with class "z". These divs then get paginated. This does work. It's just that it causes the above problem.
likedislike.js (toggling x number of posts doesn't result in pulling in the next x number of posts):
$(document).ready(function() {
likestatus = 1;
dislikestatus = 1;
$(document).on("click", ".like", function(){
postID = $(this).attr('id').replace('like_', '');
// Declare variables
value = '1';
myajax();
return false;
});
$(document).on("click", ".dislike", function(){
postID = $(this).attr('id').replace('dislike_', '');
// Declare variables
value = '0';
myajax();
return false;
});
function myajax(){
// Send values to database
$.ajax({
url: 'check.php',
//check.php receives the values sent to it and stores them in the database
type: 'POST',
data: 'postID=' + postID + '&value=' + value,
success: function(result) {
$('#Message_' + postID).html('').html(result).prependTo('#post_' + postID);
if (result.indexOf("No") < 0){ //If return doesn't contain string "No", do this
if (value == 1){ //If post is liked, do this
$('#post_' + postID).removeClass('dislike').addClass('like');
$('#dislikebtn_' + postID).removeClass('dislikeimgon').addClass('dislikeimgoff');
$('#likebtn_' + postID).removeClass('likeimgoff').addClass('likeimgon');
// If Hide Liked checkbox is on, toggle the post
if (likestatus % 2 == 0) {
$('#post_' + postID).toggle();
}
} else if (value == 0){ //If post is disliked, do this
$('#post_' + postID).removeClass('like').addClass('dislike');
$('#likebtn_' + postID).removeClass('likeimgon').addClass('likeimgoff');
$('#dislikebtn_' + postID).removeClass('dislikeimgoff').addClass('dislikeimgon');
// If Hide Disliked checkbox is on, toggle the post
if (dislikestatus % 2 == 0) {
$('#post_' + postID).toggle();
}
}
}
}
});
}
//When Hide Liked checkbox clicked, toggle all Liked posts.
$('#show_likes').on('click', function() {
countlikes = $('[id^=post_].like').length;
if (countlikes >0) {
likestatus++;
$('[id^=post_].like').toggle();
if (likestatus % 2 == 0) {
$('#hidelikedbtn').removeClass('hidelikedimgoff').addClass('hidelikedimgon');
} else {
$('#hidelikedbtn').removeClass('hidelikedimgon').addClass('hidelikedimgoff');
}
}
return false;
});
//When Hide Disliked checkbox clicked, toggle all Disliked posts.
$('#show_dislikes').on('click', function() {
countdislikes = $('[id^=post_].dislike').length;
if (countdislikes >0) {
dislikestatus++;
$('[id^=post_].dislike').toggle();
if (dislikestatus % 2 == 0) {
$('#hidedislikedbtn').removeClass('hidedislikedimgoff').addClass('hidedislikedimgon');
} else {
$('#hidedislikedbtn').removeClass('hidedislikedimgon').addClass('hidedislikedimgoff');
}
}
return false;
});
});
imtech_pager.js (this paginates all divs with class "z" - works fine)
var Imtech = {};
Imtech.Pager = function() {
this.paragraphsPerPage = 3;
this.currentPage = 1;
this.pagingControlsContainer = '#pagingControls';
this.pagingContainerPath = '#contained';
this.numPages = function() {
var numPages = 0;
if (this.paragraphs != null && this.paragraphsPerPage != null) {
numPages = Math.ceil(this.paragraphs.length / this.paragraphsPerPage);
}
return numPages;
};
this.showPage = function(page) {
this.currentPage = page;
var html = '';
this.paragraphs.slice((page-1) * this.paragraphsPerPage,
((page-1)*this.paragraphsPerPage) + this.paragraphsPerPage).each(function() {
html += '<div>' + $(this).html() + '</div>';
});
$(this.pagingContainerPath).html(html);
renderControls(this.pagingControlsContainer, this.currentPage, this.numPages());
}
var renderControls = function(container, currentPage, numPages) {
var pagingControls = 'Page: <ul>';
for (var i = 1; i <= numPages; i++) {
if (i != currentPage) {
pagingControls += '<li>' + i + '</li>';
} else {
pagingControls += '<li>' + i + '</li>';
}
}
pagingControls += '</ul>';
$(container).html(pagingControls);
}
}
index.php (displays all the divs and buttons)
<div id="content">
<div id="mastercontrols">
<div id="show_likes" style="position:absolute;">
<a id="hidelikedbtn" class="hidelikedimgoff" href="#"><span></span></a>
</div>
<div id="show_dislikes" style="position:absolute; right: 0em;">
<a id="hidedislikedbtn" class="hidedislikedimgoff" href="#"><span></span></a>
</div>
</div>
<div id="contained">
<?php
$data = mysql_query("SELECT * FROM Posts") or die(mysql_error());
while($row = mysql_fetch_array( $data )){
?>
<div class="z">
<div id="post_<?php echo $row['postID']; ?>" class="post">
<div id="post_<?php echo $row['postID']; ?>_inside" class="inside">
<div id="like_<?php echo $row['postID']; ?>" class="like" style="position:absolute; right: 2.5em;">
<a id="likebtn_<?php echo $row['postID']; ?>" class="likeimgoff" href="#"><span></span></a>
</div>
<div id="dislike_<?php echo $row['postID']; ?>" class="dislike" style="position:absolute; right: 0em;">
<a id="dislikebtn_<?php echo $row['postID']; ?>" class="dislikeimgoff" href="#"><span></span></a>
</div>
<b><?php echo $row['Title']; ?></b><br>
<?php echo $row['Description']; ?><br>
<div id="postleft">
</div>
<div id="postright">
</div>
</div>
</div>
<div id="Message_<?php echo $row['postID']; ?>" class="reminder"></div>
</div>
<?php
}
?>
</div>
<div id="pagingControls"></div>
</div>
<script type="text/javascript">
var pager = new Imtech.Pager();
$(document).ready(function() {
pager.paragraphsPerPage = 5; // set amount elements per page
pager.pagingContainer = $('#container'); // set of main container
pager.paragraphs = $('div.z', pager.pagingContainer); // set of required containers
pager.showPage(1);
});
</script>
So any ideas? This perplexes me to no end! The variables are all different, everything formats properly. The divs do get paginated and the pagination buttons (page 1, 2, 3, etc) all work. There's just something inside imtech_pager.js that stops the rest of my code from working as it should.
Again:
Toggling some posts does not result in repopulating the paginated pages. (Hiding 3 of 5 posts results in leaving 2 posts on the page instead of bringing in the next 3 posts for a total of 5 posts on the page).
I think the issue is probably that the elements are being added and removed from the DOM which is then making them lose their handlers. You should be able to just delegate the events.
Since you are using 1.7, I believe the syntax would be:
$(document).on("click", ".dislike", function(){
instead of
$('.dislike').on('click', function() {
This is the equivilent to live pre-1.7. You can refine the delegation for better performance by replacing document with a more specific selector which is the parent of all of the elements you are trying to attach the handler to, but which is not being added and removed.

Inline editing with AJAX - how do I create multiple editable areas on the same page?

I found a tutorial on how to create editable regions on a page using AJAX.
This is great, except it was written for a single element with a unique ID. I'd like to be able to click on multiple elements on the same page and have them also be editable (e.g., I'd like to alter the script below so it works not with a single element, but with multiple elements of a particular class).
Here is my HTML:
<h2>Edit This</h2>
<p class="edit">This is some editable content</p>
<p class="edit">This is some more editable content</p>
<p class="edit">I could do this all day</p>
Here is the JS file I'm working with (I updated the script per Rex's answer below): This script is, unfortunately, not working - can anyone point me in the right direction?
Event.observe(window, 'load', init, false);
function init() {
makeEditable('edit');
}
function makeEditable(className) {
var editElements = document.getElementsByClassName(className);
for(var i=0;i<editElements.length;i++) {
Event.observe(editElements[i], 'click', function(){edit($(className))}, false);
Event.observe(editElements[i], 'mouseover', function(){showAsEditable($(className))}, false);
Event.observe(editElements[i], 'mouseout', function(){showAsEditable($(className), true)}, false);
}
}
function showAsEditable(obj, clear) {
if (!clear) {
Element.addClassName(obj, 'editable');
} else {
Element.removeClassName(obj, 'editable');
}
}
function edit(obj) {
Element.hide(obj);
var textarea ='<div id="' + obj.id + '_editor"><textarea cols="60" rows="4" name="' + obj.id + '" id="' + obj.id + '_edit">' + obj.innerHTML + '</textarea>';
var button = '<input type="button" value="SAVE" id="' + obj.id + '_save"/> OR <input type="button" value="CANCEL" id="' + obj.id + '_cancel"/></div>';
new Insertion.After(obj, textarea+button);
Event.observe(obj.id+'_save', 'click', function(){saveChanges(obj)}, false);
Event.observe(obj.id+'_cancel', 'click', function(){cleanUp(obj)}, false);
}
function cleanUp(obj, keepEditable) {
Element.remove(obj.id+'_editor');
Element.show(obj);
if (!keepEditable) showAsEditable(obj, true);
}
function saveChanges(obj) {
var new_content = escape($F(obj.id+'_edit'));
obj.preUpdate = obj.innerHTML // stow contents prior to saving in case of an error
obj.innerHTML = "Saving…";
cleanUp(obj, true);
var success = function(t){editComplete(t, obj);}
var failure = function(t){editFailed(t, obj);}
var url = 'http://portal.3roadsmedia.com/scripts/edit.php';
var pars = 'id=' + obj.id + '&content=' + new_content + '&pre=' + obj.preUpdate;
var myAjax = new Ajax.Request(url, {method:'post',
postBody:pars, onSuccess:success, onFailure:failure});
}
function editComplete(t, obj) {
obj.innerHTML = t.responseText;
showAsEditable(obj, true);
}
function editFailed(t, obj) {
obj.innerHTML = 'Sorry, the update failed.';
cleanUp(obj);
}
The Event.observe method currently attaches to a single element with the ID specified. You should change this to iterate over a collection of elements located by classname and attach to each of them. According to the Prototype documentation, you can provide an element object as the first parameter, instead of an ID.
Currently, id is a string:
function makeEditable(id) {
Event.observe(id, 'click', function(){edit($(id))}, false);
//...
Which means Event.observe is attaching to the click event of the element with the ID provided. You want to attach to all elements with a class. Try:
function makeEditable(className) {
var editElements = document.getElementsByClassName(className);
for(var i=0;i<editElements.length;i++) {
Event.observe(editElements[i], 'click', function()
//...
}
//...

Resources