Overview
When I moved to a new position a few months back, the team that I shifted to had just started using web2project for managing and tracking project activity. It comes with the ability to setup various custom fields and do all sorts of project manage-y things that I try to avoid and let the PMPs deal with.
But despite all of the features of web2project, my peers still wanted more than it offers out of the box. There are a number of ways in which it is lacking flexibility or configurable options that my teammates need. I needed to address their concerns while avoiding altering the PHP source code of the application as much as possible. Doing so will make it easier to deploy official upgrades to the application while retaining our customizations.
So I created a tweaks.js javascript file and simply modified ui.class.php script to output a script tag to include it on all pages. I added the output for this just after where it loads the base.js file. We are not yet running the latest version here, but it seems like the most recent code has moved things around. This change will need to be included in the CAppUI.class.php in the latest vesrion of web2project. Since I’m using jQuery as well, I also modified the PHP file to include that before my tweaks.js.
// Load the basic javascript used by all modules. echo '<script type="text/javascript" src="'.$base.'js/base.js"></script>'; // additionally load jquery echo '<script type="text/javascript" src="'.$base.'lib/jquery/jquery.js"></script>'; // load an additional tweak script file and numeric restrictor echo '<script type="text/javascript" src="'.$base.'js/tweaks.js"></script>';
The help button tweak
One other thing I did since coming on to this team is to setup an internal MediaWiki based wiki. We decided to write articles about all things useful for our team in this wiki. This will include the help information for using web2project. The tweak I created finds the Help button by the text and then replaces the functionality of the anchor tag that handles the click event when you click the button.
I also decided to make it easy to add additional help overrides for different pages throughout the site. The code implements some logic to walk a structure where you define alternative help URLs and a set of matching criteria. It takes this matching criteria and checks against the query string to see if an alternative should be used instead.
// Source: http://jquery-howto.blogspot.com/2009/09/get-url-parameters-values-with-jquery.html function getUrlVars() { var vars = [], hash; var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); for(var i = 0; i < hashes.length; i++) { hash = hashes[i].split('='); vars.push(hash[0]); vars[hash[0]] = hash[1]; } return vars; } function setHelpUrl() { // Default replace help URL var url = 'http://wikiserver/wiki/Web2project'; // Possible substitution URLs based on matching items in the query string var substitutions = [ { "url": 'http://wikiserver/wiki/Web2project_project_fields', "match": {"m": "projects", "a": true} }, { "url": 'http://wikiserver/wiki/Web2project_projects', "match": {"m": ["projects", 'undefined']} }, { "url": 'http://wikiserver/wiki/Web2project_users', "match": {"a": ["viewuser", "addedituser"]} }, { "url": 'http://wikiserver/wiki/Web2project_tasks', "match": {"m": "tasks"} } ]; // See if we should use a substitution URL instead var vars = getUrlVars(); $.each(substitutions, function(subIdx, sub){ // Assume matched until we can't match something in the substitution description var matched = true; // Test all the properties of the substitution match set $.each(sub.match, function(queryParm, parmValue){ // If it's an array then match any entry if(parmValue instanceof Array) { // If the query parameter is not in the match array if($.inArray(vars[queryParm], parmValue) == -1) { matched = false; return false; } } // Boolean means to test for the presence or absence of the parameter else if('boolean' == typeof parmValue) { // Make sure the presence matches the match value (must-be-present == true, must-be-absent == false) if(parmValue == ('undefined' == typeof vars[queryParm])) { matched = false; return false; } } // Otherwise, require a simple value match else { if(vars[queryParm] !== parmValue) { matched = false; return false; } } }) // If still matched then use the URL from this subsitution item if(matched) { url = sub.url; return false; } }) console.log('Overriding Help URL: ' + url); // Alter Help button to display help article $('span').filter ( // Find the help button by span containing the text Help function(){return($(this).text()=='Help');}) // Remove the existing onclick handler from the parent <a> tag .parent().removeAttr('onclick') // Remove any other existing event handler .unbind('click') // Bind a new click handler to redirect the help button to the wiki article .click(function(){ window.open(url); return false; } ); }
And then the final thing is to just include a call to run the setHelpUrl function at the end of your tweaks.js file.
$(document).ready(function(){ // Override the Help button URL on all pages setHelpUrl(); });
After that, clicking on the Help button on any of the pages will cause it to route to a URL of your choosing. All without having to really modify the PHP code (other than that one thing to include the .js).
Lead web2project developer here..
First of all, welcome aboard. If you have any feedback, tips, or annoyances, please let me know. We treat the FAQ as a list of things that should be fixed and I’m always happy to add more.. well, not happy exactly, but along those lines. 😉
Next, instead of using the hardcoded include, you may be able to include your tweaks.js via the addFooterJavascriptFile method on the AppUI class. Its purpose is to allow modules to include their own js files, but it should work as you plan. Plus that should be upgrade safe.
Longer term, you should see a *huge* amount of refactoring in the pending v3.0 release. In terms of OO-purity, it’s pretty solid but the real goal behind that is to allow module developers to write way less code and just use core functionality *if* they follow the naming conventions. I’ve updated some of my modules and have deleted upwards of 20-40% of the code.
Anyway, I’m happy to talk details. Feel free to drop me a note.