Because of the high demand of Drupal work out there, I have decided to quit my job and go freelance full time!
Starting September 3rd, I will be available for more work. It will also give me more time to focus on my modules in Drupal contrib, Eventbrite and Subversion. I am also looking forward to getting more involved with Redmine and getting some much needed plugins created.
So please look forward to more drupal module work coming from my next of the woods!
I needed a donation form that would make it easy for users to select between a subscription or a one time donation. With a little jQuery love the magic happens.
First we include jquery and the jquery validate plugin. Then we setup a radio box to select between subscription and one time donation.
After the validation is successfull when the form is submitted, post the data via ajax to a php script which will enter the data in our local database. Then we return true and submit the form which will send the data to paypal. Here are all the scripts.
Javascript:
<script type="text/javascript" src="jquery-1.2.6.min.js"></script>
<script type="text/javascript" src="jquery.validate.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$('#amountDiv').hide();
$('input:radio[name=giftType]').click(function() {
if ($(this).attr("id")==='chooseMonthly') {
$("#oneTimeGiftDiv").hide();
$("#amountDiv").show();
$("#extraDetails").html('<input type="hidden" name="cmd" value="_xclick-subscriptions"><input type="hidden" name="currency_code" value="USD"><input type="hidden" name="src" value="1"><input type="hidden" name="p3" value="1"><input type="hidden" name="t3" value="M"><input type="hidden" name="sra" value="1">');
} else {
$("#amountDiv").hide();
$("#oneTimeGiftDiv").show();
$("#extraDetails").html('<input type="hidden" name="cmd" value="_donations">');
}
});$("#contactForm").validate({
submitHandler: function(form) {
$.post("paypal.php",$("#contactForm").serialize(), function (data, textStatus) {
if(data == true){
form.submit();
} else {
$("#statusMsg").html(data);
}
}, "json");
},rules: {
fname: "required",
lname: "required",
email: {
required: true,
email: true
},
email_confirm: {
required: true,
equalTo: "#email"
},
Captcha: {
required: true
}
}
});$('#email_confirm').change(function(){
$("#contactForm").validate().element('#email_confirm');
});
});
</script>
Php to save your data:
<?php
if(isset($_POST['submitted_btn'])){
unset($_POST['business']);
unset($_POST['lc']);
unset($_POST['item_name']);
unset($_POST['item_number']);
unset($_POST['no_note']);
unset($_POST['no_shipping']);
unset($_POST['rm']);
unset($_POST['return']);
unset($_POST['currency_code']);
unset($_POST['cmd']);
unset($_POST['submitted_btn']);
foreach($_POST as $key => $value){
$message .= $key.": ".$value."\n";
}// post data to database here if you want!
if(mail("email@example.com", "New Donation", $message, "From: email@example.com")){
print json_encode(true);
} else {
print json_encode(false);
}
}
?>
Html form:
<form id="contactForm" action="https://www.paypal.com/cgi-bin/webscr" method="post">
<div id="statusMsg"></div>
<h3>Your Information</h3>
<label for="first_name">First Name</label>
<input name="first_name" type="text" id="first_name" />
<label for="last_name">Last Name</label>
<input name="last_name" type="text" id="last_name" />
<label for="email">Email</label>
<input name="email" id="email" type="text" />
<label for="email_confirm">Confirm Email</label>
<input name="email_confirm" id="email_confirm" type="text" />
<label for="night_phone_a">Phone</label>
<input name="night_phone_a" id="night_phone_a" type="text"/>
<label for="address1">Address</label>
<input name="addr1" id="address1" type="text" />
<label for="address2">Address Cont.</label>
<input name="addr2" id="address2" type="text"/>
<label for="city">City</label>
<input name="city" id="city" type="text" />
<label for="state">State</label>
<input name="state" id="state" type="text" size="5" maxlength="2"/>
<label for="zip">ZIP/Postal Code</label>
<input name="zip" id="zip" type="text" size="10" maxlength="5" />
<h3>Donation Information</h3>
<div class="formDiv">
<input type="radio" name="giftType" value="One Time Gift" id="chooseOneTime" checked="checked" />One Time Gift of:
<input type="radio" name="giftType" value="Monthly Gift" id="chooseMonthly" />Monthly Gift of:</div>
<div class="formDiv" id="oneTimeGiftDiv">
<select name="amount" id="amount">
<option value="1000" selected="selected">$1000</option>
<option value="500">$500</option>
<option value="250">$250</option>
<option value="100">$100</option>
<option value="50">$50</option>
<option value="35">$35</option>
</select>
</div>
<div class="formDiv" id="amountDiv">
<input type="text" id="a3" name="a3" size="10" maxlength="5" class="textFields state_zip" />
</div>
<input type="hidden" name="business" value="email@paypalemail.com">
<input type="hidden" name="lc" value="US">
<input type="hidden" name="item_name" value="Donation">
<input type="hidden" name="item_number" value="donation">
<input type="hidden" name="no_note" value="1">
<input type="hidden" name="no_shipping" value="1">
<input type="hidden" name="rm" value="1">
<input type="hidden" name="return" value="http://example.com/thanks.php">
<input type="hidden" name="currency_code" value="USD">
<span id="extraDetails">
<input type="hidden" name="cmd" value="_donations">
</span>
</form>
There you have it. Put it all together and you have a pretty donation form with options for your users.
Who knew!! Apparently mozilla and this guy.
After finishing hours of development on a mapping application at work and finally working all the bugs out, I open it up in IE only to have it crumb to it's knees at the first sign of indexOf. Well thankfully there are people smarter than me out there who had a nifty prototype I just had to throw in to make the application come back to life:
if(!Array.indexOf){
Array.prototype.indexOf = function(obj){
for(var i=0; i<this.length; i++){
if(this[i]==obj){
return i;
}
}
return -1;
}
}
I am an avid user of Redmine project management system on all of my freelance websites. I can't imagine how I managed my projects before. IMHO it is single best collaboration tool to use with my clients. There is sum functionality however that I just didn't want my clients to be able to manipulate. For example, when a client creates a new issue, I don't want them to have the ability to assign the ticket to a specific user. More than that, there were other little bits of html I wish I could just hit for clients. So my solution was to hack redmine!!!
Now, I am not a rails developer in the least, and if there is a way to do this other than I am describing, please let me know!
So the first step is create a new "Client" role. Pretty straight forward. The next part is the actual hackery. Not being native to rails apps, it took me a while to find the views folder that outputs the html for the application. I found the output for the issue form in /app/views/issues/_form.rhtml
From there all I need to add is:
<% if role.name != "Client" %>
[html i don't want clients to see]
<% end %>
And when ever a user with the Client role hits that page, that html will not appear! Presto! The actual hidden fields in the _from.rhtml would be:
<% role = User.current.role_for_project(@project) %>
<% if role.name != "Client" %>
<div class="splitcontentleft">
<% if @issue.new_record? || @allowed_statuses.any? %>
<p><%= f.select :status_id, (@allowed_statuses.collect {|p| [p.name, p.id]}), :required => true %></p>
<% else %>
<p><label><%= l(:field_status) %></label> <%= @issue.status.name %></p>
<% end %><p><%= f.select :priority_id, (@priorities.collect {|p| [p.name, p.id]}), :required => true %></p>
<p><%= f.select :assigned_to_id, (@issue.assignable_users.collect {|m| [m.name, m.id]}), :include_blank => true %></p>
<% unless @project.issue_categories.empty? %>
<p><%= f.select :category_id, (@project.issue_categories.collect {|c| [c.name, c.id]}), :include_blank => true %>
<%= prompt_to_remote(l(:label_issue_category_new),
l(:label_issue_category_new), 'category[name]',
{:controller => 'projects', :action => 'add_issue_category', :id => @project},
:class => 'small', :tabindex => 199) if authorize_for('projects', 'add_issue_category') %></p>
<% end %>
<%= content_tag('p', f.select(:fixed_version_id,
(@project.versions.sort.collect {|v| [v.name, v.id]}),
{ :include_blank => true })) unless @project.versions.empty? %>
</div><div class="splitcontentright">
<p><%= f.text_field :start_date, :size => 10 %><%= calendar_for('issue_start_date') %></p>
<p><%= f.text_field :due_date, :size => 10 %><%= calendar_for('issue_due_date') %></p>
<p><%= f.text_field :estimated_hours, :size => 3 %> <%= l(:field_hours) %></p>
<p><%= f.select :done_ratio, ((0..10).to_a.collect {|r| ["#{r*10} %", r*10] }) %></p>
</div>
<% end %>
And now the user can't set the assign to, category, start date, end date, hours, or estimated done. Only actual developers and managers should be able to set those.
So there you have it. If you know a better way to override this view without hacking it please let me know.
I have told you all that I would post this a while ago so here it is. This is the class I use to dynamically grab data via amfphp programmatically in actionscript 3 without needing to create a remote object mxml node.
package com.mrconnerton.proxy
{
import flash.events.EventDispatcher;
import flash.events.IEventDispatcher;
import flash.external.ExternalInterface;import mx.core.Application;
import mx.messaging.ChannelSet;
import mx.messaging.channels.AMFChannel;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.Operation;
import mx.rpc.remoting.RemoteObject;[Event(name="result", type="mx.rpc.events.ResultEvent")]
[Event(name="fault", type="mx.rpc.events.FaultEvent")]public class RemoteService extends EventDispatcher implements IEventDispatcher
{
private var channelSet:ChannelSet = new ChannelSet();
private var channel:AMFChannel;
private var service:RemoteObject = new RemoteObject();
private var operation:Operation;
private var _source:String;
private var _method:String;
private var _faultAt:String;
private var url:String = ExternalInterface.call("window.location.href.toString");
private var gateway:String = "amfphp/gateway.php";public function RemoteService(source:String, method:String):void {
channel = new AMFChannel("amfphp", url+gateway);
_source = source;
_method = method;operation = new Operation(service);
channelSet.addChannel(channel);
service.destination = "amfphp";
service.channelSet = channelSet;
service.source = _source;
}
public function send(...args):void {
service.getOperation(_method).addEventListener(ResultEvent.RESULT, resultHandler);
service.getOperation(_method).addEventListener(FaultEvent.FAULT, faultHandler);
var func:Function = service.getOperation(_method).send;
func.apply(service.getOperation(_method), args);
}public function resultHandler(event:ResultEvent):void {
service.getOperation(_method).removeEventListener(ResultEvent.RESULT, resultHandler);
service.getOperation(_method).removeEventListener(FaultEvent.FAULT, faultHandler);
dispatchEvent(event);
}
public function faultHandler(event:FaultEvent):void {
service.getOperation(_method).removeEventListener(ResultEvent.RESULT, resultHandler);
service.getOperation(_method).removeEventListener(FaultEvent.FAULT, faultHandler);
dispatchEvent(event);
}
}
}
Then anywhere in your flex (or flash) application you want to call an amfphp method you use:
private function loadNode():void {
var rs:RemoteService = new RemoteService('node','load');
rs.addEventListener(ResultEvent.RESULT, onNodeLoad);
rs.addEventListener(ResultEvent.RESULT, function(event:ResultEvent):void {
rs.removeEventListener(ResultEvent.RESULT, arguments.callee);
var node:Object = event.result;
// Do stuff with node
}
rs.addEventListener(FaultEvent.FAULT, function(event:FaultEvent):void {
rs.removeEventListener(FaultEvent.FAULT, arguments.callee);
// AAAAHHHH!!!!!!!!
}
rs.send();
}
What is Drupal?
Drupal - a completely free, open source content management system that many organizations are using today to provide for their needs. Drupal's many features and add-ons allow it to be used for a variety of website needs. Drupal is a good choice for today's organizations of any size because it is free, easy, and incredibly flexible.













