Top Banner
SILVERSTRIPE CMS JAVASCRIPT REFACTORING The jsparty is over! Friday, 28 August 2009
16

SilverStripe CMS JavaScript Refactoring

May 17, 2015

Download

Technology

Ingo Schommer

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.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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