YOU ARE DOWNLOADING DOCUMENT

Please tick the box to continue:

Transcript
Page 1: SilverStripe CMS JavaScript Refactoring

SILVERSTRIPE CMS JAVASCRIPT REFACTORING

The jsparty is over!

Friday, 28 August 2009

Page 2: SilverStripe CMS JavaScript Refactoring

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

Page 3: SilverStripe CMS JavaScript Refactoring

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

Page 4: SilverStripe CMS JavaScript Refactoring

GOODBYE JSPARTY

• Merged external librariesto cms/thirdparty and sapphire/thirdparty

Friday, 28 August 2009

Page 5: SilverStripe CMS JavaScript Refactoring

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

Page 6: SilverStripe CMS JavaScript Refactoring

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

Page 7: SilverStripe CMS JavaScript Refactoring

BEST PRACTICES

• Don’t claim global properties

• Assume element collections

• Encapsulate: jQuery.concrete, jQuery plugin, jQueryUI widget (in this order)

Friday, 28 August 2009

Page 8: SilverStripe CMS JavaScript Refactoring

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

Page 9: SilverStripe CMS JavaScript Refactoring

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

Page 10: SilverStripe CMS JavaScript Refactoring

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

Page 11: SilverStripe CMS JavaScript Refactoring

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

Page 12: SilverStripe CMS JavaScript Refactoring

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

Page 13: SilverStripe CMS JavaScript Refactoring

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

Page 14: SilverStripe CMS JavaScript Refactoring

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

Page 15: SilverStripe CMS JavaScript Refactoring

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

Page 16: SilverStripe CMS JavaScript Refactoring

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


Related Documents