SilverStripe CMS JavaScript Refactoring
-
Upload
ingo-schommer -
Category
Technology
-
view
2.837 -
download
5
description
Transcript of SilverStripe CMS JavaScript Refactoring
SILVERSTRIPE CMS JAVASCRIPT REFACTORING
The jsparty is over!
Friday, 28 August 2009
SCOPE
• JavaScript library upgrade, no more forks
• CMS JavaScript cleanupRewrite in jQuery where feasible
• CMS PHP Controller simplification
• More solid UI components with jQuery UI and plugins
• CSS Architecture for easier customization
• Not a large-scale CMS redesign
Friday, 28 August 2009
LIBRARIES
• Prototype 1.4rc3 to jQuery 1.3
• Random UI code and ancient libs to jQuery UI 1.7
• Custom behaviour.js to jQuery.concrete
• External libraries managed by Piston (piston.rubyforge.org/) instead of svn:externals
Friday, 28 August 2009
GOODBYE JSPARTY
• Merged external librariesto cms/thirdparty and sapphire/thirdparty
Friday, 28 August 2009
THE DARK AGES
function hover_over() { Element.addClassName(this, 'over');}function hover_out() { Element.removeClassName(this, 'over');}
hover_behaviour = { onmouseover : hover_over, onmouseout : hover_out}jsparty/hover.js
Friday, 28 August 2009
THE DARK AGESclass LeftAndMain {
// ... public function returnItemToUser($p) { // ... $response = <<<JS var tree = $('sitetree'); var newNode = tree.createTreeNode("$id", "$treeTitle", "{$p->class}{$hasChildren} {$singleInstanceCSSClass}"); node = tree.getTreeNodeByIdx($parentID); if(!node) { node = tree.getTreeNodeByIdx(0); } node.open(); node.appendTreeNode(newNode); newNode.selectTreeNode(); JS; FormResponse::add($response); FormResponse::add($this->hideSingleInstanceOnlyFromCreateFieldJS($p)); return FormResponse::respond(); }}
cms/code/LeftAndMain.php (excerpt)
Friday, 28 August 2009
BEST PRACTICES
• Don’t claim global properties
• Assume element collections
• Encapsulate: jQuery.concrete, jQuery plugin, jQueryUI widget (in this order)
Friday, 28 August 2009
ENCAPSULATE: EXAMPLE
// create closure(function($) { // plugin definition $.fn.hilight = function(options) { // build main options before element iteration var opts = $.extend({}, $.fn.hilight.defaults, options); // iterate and reformat each matched element return this.each(function() { $this = $(this); // build element specific options var o = $.meta ? $.extend({}, opts, $this.data()) : opts; // update element styles $this.css({backgroundColor: o.background,color: o.foreground}); }); }; // plugin defaults $.fn.hilight.defaults = {foreground: "red",background: "yellow"};// end of closure})(jQuery);
Simple Highlight jQuery Plugin
Friday, 28 August 2009
BEST PRACTICES
• Use plain HTML, jQuery.data() and jQuery.metadata to encode initial state and (some) configuration
• Better than building “object cathedrals” in most cases
Friday, 28 August 2009
STATE: EXAMPLE
$('form :input').bind('change', function(e) { $(this.form).addClass('isChanged');});$('form').bind('submit', function(e) { if($(this).hasClass('isChanged')) return false;});
Simple Form Changetracking
$('form :input').bind('change', function(e) { $(this.form).data('isChanged', true);});$('form').bind('submit', function(e) { if($(this).data('isChanged')) return false;});
State in CSS properties
State in DOM(through jQuery.data())
Friday, 28 August 2009
BEST PRACTICES
• Ajax responses should default to HTMLMakes it easier to write unobtrusive markup and use SilverStripe templating
• Use HTTP metadata to transport state and additional dataExample: 404 HTTP status code to return “Not Found”Example: Custom “X-Status” header for more detailed UI status
• Return JSON if HTML is not feasibleExample: Update several tree nodes after CMS batch actionsAlternative: Inspect the returned DOM for more structured data like id attributes
• For AJAX and parameter transmission, <form> is your friend
Friday, 28 August 2009
AJAX: EXAMPLE
<form action"#"> <div class="autocomplete {url:'MyController/autocomplete'}"> <input type="text" name="title" /> <div class="results" style="display: none;"> </div> <input type="submit" value="action_autocomplete" /></form>
<ul><% control Results %> <li id="Result-$ID">$Title</li><% end_control %></ul>
MyController.ss
AutoComplete.ss
Simple Serverside Autocomplete for Page Titles
Using jQuery.metadata,but could be a plain SilverStripe Form as well
Friday, 28 August 2009
AJAX: EXAMPLE
class MyController { function autocomplete($request) { $SQL_title = Convert::raw2sql($request->getVar('title')); $results = DataObject::get("Page", "Title LIKE '%$SQL_title%'"); if(!$results) return new HTTPResponse("Not found", 404); // Use HTTPResponse to pass custom status messages $this->response->setStatusCode(200, "Found " . $results->Count() . " elements"); // render all results with a custom template $vd = new ViewableData(); return $vd->customise(array( "Results" => $results ))->renderWith('AutoComplete'); }}
MyController.php
Friday, 28 August 2009
AJAX: EXAMPLE
$('.autocomplete input').live('change', function() { var resultsEl = $(this).siblings('.results'); resultsEl.load( // get form action, using the jQuery.metadata plugin $(this).parent().metadata().url, // submit all form values $(this.form).serialize(), // callback after data is loaded function(data, status) { resultsEl.show(); // optional: get all record IDs from the new HTML var ids = jQuery('.results').find('li').map(function() { return $(this).attr('id').replace(/Record\-/,''); }); } );});
MyController.js
Friday, 28 August 2009
BEST PRACTICES
• Use events and observation for component communication
• Use composition for synchronous, two-way communicatoin
• Use callbacks to allow for customization
• Don’t overuse prototypical inheritance and pseudo-classes
• Only expose public APIs where necessary (through jQuery.concrete)
Friday, 28 August 2009
RESOURCES
http://doc.silverstripe.com/doku.php?id=2.4:javascript
http://github.com/chillu/sapphire/tree/jsrewrite
http://github.com/chillu/cms/tree/jsrewrite
Documentation (unreleased)
Source (unreleased, pre 2.4 alpha)
Friday, 28 August 2009