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.
Presentation on how to chat with PDF using ChatGPT code interpreter
SilverStripe CMS JavaScript Refactoring
1. SILVERSTRIPE CMS
JAVASCRIPT REFACTORING
The jsparty is over!
Friday, 28 August 2009
2. SCOPE
• JavaScript library upgrade, no more forks
• CMS JavaScript cleanup
Rewrite 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
3. 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
4. GOODBYE JSPARTY
• Merged external libraries
to cms/thirdparty and sapphire/thirdparty
Friday, 28 August 2009
5. 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
6. THE DARK AGES
class 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
7. BEST PRACTICES
• Don’t claim global properties
• Assume element collections
• Encapsulate: jQuery.concrete, jQuery plugin,
jQueryUI widget (in this order)
Friday, 28 August 2009
8. ENCAPSULATE: EXAMPLE
Simple Highlight jQuery Plugin
// 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);
Friday, 28 August 2009
9. BEST PRACTICES
• Useplain 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
10. STATE: EXAMPLE
Simple Form Changetracking
State in CSS $('form :input').bind('change', function(e) {
$(this.form).addClass('isChanged');
});
properties $('form').bind('submit', function(e) {
if($(this).hasClass('isChanged')) return false;
});
$('form :input').bind('change', function(e) {
State in DOM $(this.form).data('isChanged', true);
});
$('form').bind('submit', function(e) {
(through jQuery.data()) if($(this).data('isChanged')) return false;
});
Friday, 28 August 2009
11. BEST PRACTICES
• Ajax responses should default to HTML
Makes it easier to write unobtrusive markup and use SilverStripe templating
• Use HTTP metadata to transport state and additional data
Example: 404 HTTP status code to return “Not Found”
Example: Custom “X-Status” header for more detailed UI status
• Return JSON if HTML is not feasible
Example: Update several tree nodes after CMS batch actions
Alternative: Inspect the returned DOM for more structured data like id attributes
• For AJAX and parameter transmission, <form> is your friend
Friday, 28 August 2009
12. AJAX: EXAMPLE
Simple Serverside Autocomplete for Page Titles
<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>
MyController.ss
Using jQuery.metadata,
but could be a plain SilverStripe Form as well
<ul>
<% control Results %>
<li id="Result-$ID">$Title</li>
<% end_control %>
</ul>
AutoComplete.ss
Friday, 28 August 2009
13. 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
14. 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
15. 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
16. RESOURCES
Documentation (unreleased)
http://doc.silverstripe.com/doku.php?id=2.4:javascript
Source (unreleased, pre 2.4 alpha)
http://github.com/chillu/sapphire/tree/jsrewrite
http://github.com/chillu/cms/tree/jsrewrite
Friday, 28 August 2009