SilverStripe CMS JavaScript Refactoring

Post on 17-May-2015

2837 Views

Category:

Technology

5 Downloads

Preview:

Click to see full reader

DESCRIPTION

Outlines the refactoring effort of the SilverStripe CMS codebase, which was an internal project at SilverStripe Ltd. mid 2009. The main objective was to simplify CMS extensions for intermediate frontend/backend developers. In practice this meant a lot of housekeeping, and the consistent usage of jQuery and jQuery UI over PrototypeJS.

Transcript

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

top related