SlideShare una empresa de Scribd logo
1 de 30
Descargar para leer sin conexión
Resource Registries 
Ramon Navarro Bosch & Rob Gietema
Ramon Navarro Bosch 
• Iskra.CAT 
• Member Plone Foundation 
• FWT member
Rob Gietema 
• Four Digits 
• Plone Foundation Member
Current State 
<?xml version="1.0"?> 
<object name="portal_javascripts" meta_type="JavaScripts Registry"> 
<javascript compression="safe" 
authenticated="True" 
id="hello-world.js" 
insert-after="*" 
/> 
</object> 
<?xml version="1.0"?> 
<object name="portal_css"> 
<stylesheet title="" 
id="hello-world.css" 
media="screen" 
rel="stylesheet" rendering="link" 
cacheable="True" 
compression="safe" 
cookable="True" 
enabled="1" 
expression="" 
insert-before="print.css" /> 
</object> 
• JS Registry 
• CSS Registry 
• Tools
Limitations 
• JS & CSS have evolved 
• Dependency management 
• Precompiling (LESS / SASS) 
• Versioning 
• Mockup
RequireJS 
<!DOCTYPE html> 
<html> 
<head> 
<script data-main="app" src="lib/require.js"></script> 
</head> 
<body> 
<h1>Hello World</h1> 
</body> 
• Include require.js </html> 
// File: app.js 
// For any third party dependencies, like jQuery, place them in the lib folder. 
! 
// Configure loading modules from the lib directory, 
// except for 'app' ones, which are in a sibling 
// directory. 
requirejs.config({ 
baseUrl: 'lib', 
paths: { 
app: '../app' 
} 
}); 
! 
// Start loading the main app file. Put all of 
// your application logic in there. 
requirejs(['app/main']); 
• Add all your dependencies 
in Javascript 
• Async loading of files and 
modules
GRUNT 
module.exports = function(grunt) { 
! 
grunt.initConfig({ 
pkg: grunt.file.readJSON('package.json'), 
concat: { 
options: { 
separator: ';' 
}, 
dist: { 
src: ['src/**/*.js'], 
dest: 'dist/<%= pkg.name %>.js' 
} 
}, 
qunit: { 
files: ['test/**/*.html'] 
}, 
watch: { 
files: ['<%= jshint.files %>'], 
tasks: ['jshint', 'qunit'] 
} 
}); 
! 
grunt.loadNpmTasks('grunt-contrib-qunit'); 
grunt.loadNpmTasks('grunt-contrib-watch'); 
grunt.loadNpmTasks('grunt-contrib-concat'); 
! 
grunt.registerTask('test', ['jshint', 'qunit']); 
! 
grunt.registerTask('default', ['qunit', 'concat']); 
! 
}; 
• Task runner 
• Run tests, concat, minimize, 
JSHint etc
NPM 
npm install (with no args in a package dir) 
npm install <tarball file> 
npm install <tarball url> 
npm install <folder> 
npm install [@<scope>/]<name> [--save|--save-dev|--save-optional] [--save-exact] 
npm install [@<scope>/]<name>@<tag> 
npm install [@<scope>/]<name>@<version> 
npm install [@<scope>/]<name>@<version range> 
npm i (with any of the previous argument usage) 
• Node.js package manager 
• Dependencies 
• Versioning
Bower 
{ 
"name": "my-project", 
"version": "1.0.0", 
"main": "path/to/main.js", 
"ignore": [ 
".jshintrc", 
"**/*.txt" 
], 
"dependencies": { 
"<name>": "<version>", 
"<name>": "<folder>", 
"<name>": "<package>" 
}, 
"devDependencies": { 
"<test-framework-name>": "<version>" 
} 
} 
• Javascript package manager 
• Dependencies 
• Versioning
LESS / SASS 
@base: #f938ab; 
! 
.box-shadow(@style, @c) when (iscolor(@c)) { 
-webkit-box-shadow: @style @c; 
box-shadow: @style @c; 
} 
.box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) { 
.box-shadow(@style, rgba(0, 0, 0, @alpha)); 
} 
.box { 
color: saturate(@base, 5%); 
border-color: lighten(@base, 30%); 
div { .box-shadow(0 0 5px, 30%) } 
} 
.box { 
color: #fe33ac; 
border-color: #fdcdea; 
} 
.box div { 
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); 
} 
• Precompiler for CSS 
• Variables 
• Nesting 
• Macro's
Design of the Solution 
BUNDLE 
RESOURCE 
BOWER 
COMPONENT 
MOCKUP 
COMPONENT 
STANDALONE 
FILES 
DIAZO 
STATIC 
HTML REGISTRY
Bundles 
• Dependency 
• Compilation 
• Enabled 
<records prefix="plone.bundles/plone-legacy" 
interface='Products.CMFPlone.interfaces.IBundleRegistry'> 
<value key="resources" purge="false"> 
<element>plone_javascript_variables</element> 
<element>unlockOnFormUnload</element> 
<element>table_sorter</element> 
<element>inline-validation</element> 
<element>jquery-highlightsearchterms</element> 
<element>cookie_functions</element> 
</value> 
<value key="jscompilation">++plone++static/plone-legacy-compiled.js</value> 
<value key="csscompilation">++plone++static/plone-legacy-compiled.css</value> 
<value key="last_compilation">2014-08-14 00:00:00</value> 
<value key="compile">False</value> 
<value key="enabled">True</value> 
</records> 
<records prefix="plone.bundles/plone" 
interface='Products.CMFPlone.interfaces.IBundleRegistry'> 
<value key="resources"> 
<element>plone</element> 
</value> 
<value key="enabled">True</value> 
<value key="jscompilation">++plone++static/plone-compiled.js</value> 
<value key="csscompilation">++plone++static/plone-compiled.css</value> 
<value key="last_compilation">2014-08-14 00:00:00</value> 
</records>
Resources 
• js 
• export/init 
• css 
• url 
<records prefix="plone.resources/tinymce" 
interface='Products.CMFPlone.interfaces.IResourceRegistry'> 
<value key="js">++plone++static/components/tinymce/tinymce.js</value> 
<value key="export">window.tinyMCE</value> 
<value key="init">function () { this.tinyMCE.DOM.events.domLoaded = true; return this.tinyMCE; }</value> 
<value key="css"> 
<element>++plone++static/components/tinymce/skins/lightgray/skin.min.css</element> 
<element>++plone++static/components/tinymce/skins/lightgray/content.inline.min.css</element> 
</value> 
</records> 
<records prefix="plone.resources/mockup-patterns-select2" 
interface='Products.CMFPlone.interfaces.IResourceRegistry'> 
<value key="js">++resource++mockup/select2/patterns.js</value> 
<value key="css"> 
<element>++resource++mockup/select2/pattern.select2.less</element> 
</value> 
</records> 
<records prefix="plone.resources/mockup-patterns-structure" 
interface='Products.CMFPlone.interfaces.IResourceRegistry'> 
<value key="js">++resource++mockup/structure/pattern.js</value> 
<value key="url">++resource++mockup/structure</value> 
<value key="css"> 
<element>++resource++mockup/structure/less/pattern.structure.less</element> 
</value> 
</records>
LESS Vars 
<!-- Mixins vars for less with the paths --> 
<record name="plone.lessvariables"> 
<field type="plone.registry.field.Dict"> 
<title>Less variables</title> 
<description>Variables that are going to be compiled on less</description> 
<key_type type="plone.registry.field.ASCIILine" /> 
<value_type type="plone.registry.field.TextLine" /> 
</field> 
<value> 
<element key="bowerPath">"{site_url}/++plone++static/components/"</element> 
<element key="mockupPath">"{site_url}/++resource++mockup/"</element> 
<element key="mockuplessPath">"{site_url}/++resource++mockupless/"</element> 
! 
<element key="plone-link-color">rgba(0,123,179,1)</element> 
<element key="plone-gray-lighter">lighten(#000, 80%)</element> 
<element key="plone-gray-light">lighten(#000, 46.5%)</element> 
! 
<element key="plone-toolbar-bg">rgba(0,0,0,.9)</element> 
<element key="plone-toolbar-submenu-bg">rgba(20,20,20,.9)</element> 
<element key="plone-toolbar-font-primary">'Roboto Condensed', sans-serif</element>
Pattern Options 
<record name="plone.patternoptions"> 
<field type="plone.registry.field.Dict"> 
<title>Patterns configuration</title> 
<description>Base pattern configuration options</description> 
<key_type type="plone.registry.field.ASCIILine" /> 
<value_type type="plone.registry.field.Text" /> 
</field> 
<value> 
<element key="pickadate">{"selectYears": 200}</element>
Development & Production 
<record name="plone.resources.development"> 
<field type="plone.registry.field.Bool"> 
<title>Frontend development mode</title> 
</field> 
<value>true</value> 
</record> 
• Compile on browser on each 
reload using RequireJS / LESS 
• Develop static HTML with 
compiled bundles 
• Grunt using browser config.js/ 
mixins.less 
• Get the compiled css/js 
bundles 
• Deployment with compiled 
css/js
Diazo 
[theme] 
title = Barceloneta Theme 
description = Plone 5 theme 
rules = /++theme++barceloneta/rules.xml 
prefix = /++theme++barceloneta 
doctype = <!DOCTYPE html> 
enabled-bundles = barceloneta 
disabled-bundles = 
<!-- CSS --> 
<after theme-children="/html/head" content="/html/head/link" /> 
<!-- Script --> 
<after theme-children="/html/head" content="/html/head/script" />
Views: config.js 
requirejs.config({ 
baseUrl: 'http://localhost:8080/Plone', 
paths: { 
'tinymce-save': ‘++plone++static/components/tinymce/plugins/save/plugin', 
'mockup-patterns-accessibility': ‘++resource++mockup/accessibility/pattern’, 
'mockup-patterns-tinymce-url': '++resource++mockup/tinymce' 
… 
'mockup-patterns-formautofocus': '++resource++mockup/formautofocus/pattern', 
'bootstrap-tooltip': '++plone++static/components/bootstrap/js/tooltip', 
'resource-plone-app-event-portlet_calendar-js': '++resource++plone.app.event.portlet_calendar', 
'dropzone': '++plone++static/components/dropzone/downloads/dropzone-amd-module'}, 
shim: { 
'tinymce-save': {deps: ['tinymce']}, 
'mockup-router': {}, 'tinymce-spellchecker': {deps: ['tinymce']}, 
'jquery.event.drop': {exports: '$.drop', deps: ['jquery']}, 
'tinymce-autosave': {deps: ['tinymce']}, 
… 
'bootstrap-tooltip': {deps: ['jquery']}}, 
optimize: 'uglify', 
wrapShim: true 
});
Views: less-variables.js 
window.less = { 
env: "development", 
logLevel: 2, 
async: false, 
fileAsync: false, 
errorReporting: window.lessErrorReporting || 'console', 
poll: 1000, 
functions: {}, 
relativeUrls: true, 
dumpLineNumbers: "comments", 
globalVars: { 
sitePath: '"http://localhost:8080/Plone"', 
isPlone: 'true', 
isMockup: 'false', 
'plone-toolbar-font-primary': "'Roboto Condensed', sans-serif", 
'plone-gray-lighter': "lighten(#000, 80%)", 
'mockuplessPath': ""http://localhost:8080/Plone/++resource++mockupless/"", 
'bowerPath': ""http://localhost:8080/Plone/++plone++static/components/"", 
'plone-toolbar-internally-published-color': "rgb(136,61,250)", 
'mockupPath': ""http://localhost:8080/Plone/++resource++mockup/"", 
… 
'plone-toolbar-private-color': "rgb(196,24,60)", 
'plone-screen-xs-max': "(@plone-screen-sm-min + 1)", 
'plone-toolbar-bg': "rgba(255,0,0,.9)", 
'plone-gray-light': "lighten(#000, 46.5%)", 
'barceloneta': ‘"http://localhost:8080/Plone/++plone++barceloneta/less/barceloneta.plone.less"', 
… 
'picker_time': '"http://localhost:8080/Plone/++plone++static/components/pickadate/lib/themes/classic.time.css"', 
'picker': '"http://localhost:8080/Plone/++plone++static/components/pickadate/lib/themes/classic.css"', 
'plone-patterns-toolbar': '"http://localhost:8080/Plone/++plone++static/patterns/toolbar/src/css/toolbar.plone.less"', 
'plone': '"http://localhost:8080/Plone/++plone++static/plone.less"', 
…}};
plone.less 
… 
@import url("@{mockup-patterns-upload}"); 
@import url("@{plone-patterns-toolbar}"); 
@import url("@{mockup-patterns-tinymce}"); 
! 
! 
@import "@{bowerPath}bootstrap/less/dropdowns.less"; 
…
plone.js 
require([ 
'jquery', 
'mockup-registry', 
'mockup-patterns-base', 
'mockup-patterns-select2', 
'mockup-patterns-pickadate', 
'mockup-patterns-relateditems', 
'mockup-patterns-querystring', 
'mockup-patterns-tinymce', 
'plone-patterns-toolbar', 
'mockup-patterns-accessibility', 
'mockup-patterns-autotoc', 
'mockup-patterns-formunloadalert', 
'mockup-patterns-preventdoublesubmit', 
'mockup-patterns-formautofocus', 
'mockup-patterns-modal', 
'mockup-patterns-structure', 
'bootstrap-dropdown', 
'bootstrap-collapse', 
‘bootstrap-tooltip' 
…
TTW customization 
• Fully customizable trough the web 
• Controlpanel in Plone
Legacy Plone 
• cssregistry.xml and 
jsregistry.xml still 
work 
• Legacy bundle 
• Not all attributes 
are supported 
<?xml version="1.0"?> 
<object name="portal_javascripts" meta_type="JavaScripts Registry"> 
<javascript compression="safe" 
authenticated="True" 
id="hello-world.js" 
insert-after="*" 
/> 
</object> 
<?xml version="1.0"?> 
<object name="portal_css"> 
<stylesheet title="" 
id="hello-world.css" 
media="screen" 
rel="stylesheet" rendering="link" 
cacheable="True" 
compression="safe" 
cookable="True" 
enabled="1" 
expression="" 
insert-before="print.css" /> 
</object>
Standard resources 
• Mockup 
• Bower components 
accessibility 
autotoc 
backdrop 
eventedit 
filemanager 
formautofocus 
formunloadalert 
modal 
moment 
pickadate 
preventdoublesubmit 
querystring 
relateditems 
resourceregistry 
select2 
sortable 
structure 
tablesorter 
texteditor 
thememapper 
tinymce 
toggle 
tooltip 
tree 
upload
Are you able to do 
"console dev" ? 
• generate_gruntfile.py -> creates Gruntconfig.js
Demo
Migration 
• Resources defined as pattern and less file 
• Always generate production bundle 
• Move jsregistry and cssregistry to registry.xml 
• On/live jquery 1.11 modifications 
• Never loose hope
Questions ? 
• Additional info at: 
• https://www.nathanvangheem.com/news/plone-5- 
resource-registries
SPRINT 
• Static CSS/JS for mockups / CDN 
• Cooking on production 
• Mockup issues 
• Write documentation!! 
• Write tests!!

Más contenido relacionado

La actualidad más candente

Hdv309 - Real World Sandboxed Solutions
Hdv309 - Real World Sandboxed SolutionsHdv309 - Real World Sandboxed Solutions
Hdv309 - Real World Sandboxed Solutions
woutervugt
 
Effective TDD - Less is more
Effective TDD - Less is moreEffective TDD - Less is more
Effective TDD - Less is more
Ben Lau
 

La actualidad más candente (20)

Beyond PrettyFaces - Einführung in Rewrite
Beyond PrettyFaces - Einführung in RewriteBeyond PrettyFaces - Einführung in Rewrite
Beyond PrettyFaces - Einführung in Rewrite
 
Web Components
Web ComponentsWeb Components
Web Components
 
Web Components and Modular CSS
Web Components and Modular CSSWeb Components and Modular CSS
Web Components and Modular CSS
 
Hdv309 - Real World Sandboxed Solutions
Hdv309 - Real World Sandboxed SolutionsHdv309 - Real World Sandboxed Solutions
Hdv309 - Real World Sandboxed Solutions
 
Uniface Lectures Webinar - Building Responsive Applications with Uniface: Dev...
Uniface Lectures Webinar - Building Responsive Applications with Uniface: Dev...Uniface Lectures Webinar - Building Responsive Applications with Uniface: Dev...
Uniface Lectures Webinar - Building Responsive Applications with Uniface: Dev...
 
Preparing your web services for Android and your Android app for web services...
Preparing your web services for Android and your Android app for web services...Preparing your web services for Android and your Android app for web services...
Preparing your web services for Android and your Android app for web services...
 
AJAX - An introduction
AJAX - An introductionAJAX - An introduction
AJAX - An introduction
 
Introduction about-ajax-framework
Introduction about-ajax-frameworkIntroduction about-ajax-framework
Introduction about-ajax-framework
 
Angularjs & REST
Angularjs & RESTAngularjs & REST
Angularjs & REST
 
Zk doc1
Zk doc1Zk doc1
Zk doc1
 
HTML5 - An introduction
HTML5 - An introductionHTML5 - An introduction
HTML5 - An introduction
 
Even faster django
Even faster djangoEven faster django
Even faster django
 
Node.js introduction
Node.js introductionNode.js introduction
Node.js introduction
 
Effective TDD - Less is more
Effective TDD - Less is moreEffective TDD - Less is more
Effective TDD - Less is more
 
WebApp #3 : API
WebApp #3 : APIWebApp #3 : API
WebApp #3 : API
 
WebApp / SPA @ AllFacebook Developer Conference
WebApp / SPA @ AllFacebook Developer ConferenceWebApp / SPA @ AllFacebook Developer Conference
WebApp / SPA @ AllFacebook Developer Conference
 
Go Fullstack: JSF for Public Sites (CONFESS 2012)
Go Fullstack: JSF for Public Sites (CONFESS 2012)Go Fullstack: JSF for Public Sites (CONFESS 2012)
Go Fullstack: JSF for Public Sites (CONFESS 2012)
 
Mule esb
Mule esbMule esb
Mule esb
 
003. ReactJS basic
003. ReactJS basic003. ReactJS basic
003. ReactJS basic
 
AJAX
AJAXAJAX
AJAX
 

Similar a Resource Registries: Plone Conference 2014

Progressive downloads and rendering (Stoyan Stefanov)
Progressive downloads and rendering (Stoyan Stefanov)Progressive downloads and rendering (Stoyan Stefanov)
Progressive downloads and rendering (Stoyan Stefanov)
Ontico
 
Simple blog wall creation on Java
Simple blog wall creation on JavaSimple blog wall creation on Java
Simple blog wall creation on Java
Max Titov
 
E2 appspresso hands on lab
E2 appspresso hands on labE2 appspresso hands on lab
E2 appspresso hands on lab
NAVER D2
 
E3 appspresso hands on lab
E3 appspresso hands on labE3 appspresso hands on lab
E3 appspresso hands on lab
NAVER D2
 

Similar a Resource Registries: Plone Conference 2014 (20)

Resource registries plone conf 2014
Resource registries plone conf 2014Resource registries plone conf 2014
Resource registries plone conf 2014
 
Plone Interactivity
Plone InteractivityPlone Interactivity
Plone Interactivity
 
Building iPhone Web Apps using "classic" Domino
Building iPhone Web Apps using "classic" DominoBuilding iPhone Web Apps using "classic" Domino
Building iPhone Web Apps using "classic" Domino
 
Rich Portlet Development in uPortal
Rich Portlet Development in uPortalRich Portlet Development in uPortal
Rich Portlet Development in uPortal
 
Progressive downloads and rendering (Stoyan Stefanov)
Progressive downloads and rendering (Stoyan Stefanov)Progressive downloads and rendering (Stoyan Stefanov)
Progressive downloads and rendering (Stoyan Stefanov)
 
[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC[Coscup 2012] JavascriptMVC
[Coscup 2012] JavascriptMVC
 
前端概述
前端概述前端概述
前端概述
 
BITM3730Week7.pptx
BITM3730Week7.pptxBITM3730Week7.pptx
BITM3730Week7.pptx
 
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
jQuery Makes Writing JavaScript Fun Again (for HTML5 User Group)
 
JavaScript performance patterns
JavaScript performance patternsJavaScript performance patterns
JavaScript performance patterns
 
Simple blog wall creation on Java
Simple blog wall creation on JavaSimple blog wall creation on Java
Simple blog wall creation on Java
 
Responsive WordPress workflow
Responsive WordPress workflowResponsive WordPress workflow
Responsive WordPress workflow
 
Progressive Downloads and Rendering
Progressive Downloads and RenderingProgressive Downloads and Rendering
Progressive Downloads and Rendering
 
20190118_NetadashiMeetup#8_React2019
20190118_NetadashiMeetup#8_React201920190118_NetadashiMeetup#8_React2019
20190118_NetadashiMeetup#8_React2019
 
Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!Django Rest Framework and React and Redux, Oh My!
Django Rest Framework and React and Redux, Oh My!
 
E2 appspresso hands on lab
E2 appspresso hands on labE2 appspresso hands on lab
E2 appspresso hands on lab
 
E3 appspresso hands on lab
E3 appspresso hands on labE3 appspresso hands on lab
E3 appspresso hands on lab
 
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
Oracle Application Express & jQuery Mobile - OGh Apex Dag 2012
 
The new static resources framework
The new static resources frameworkThe new static resources framework
The new static resources framework
 
HTML 5 - Overview
HTML 5 - OverviewHTML 5 - Overview
HTML 5 - Overview
 

Más de Rob Gietema

Projectgroep Millennium GroenLinks Arnhem
Projectgroep Millennium GroenLinks ArnhemProjectgroep Millennium GroenLinks Arnhem
Projectgroep Millennium GroenLinks Arnhem
Rob Gietema
 

Más de Rob Gietema (20)

Van klimhal naar Big Wall: Bergsportdag 2024
Van klimhal naar Big Wall: Bergsportdag 2024Van klimhal naar Big Wall: Bergsportdag 2024
Van klimhal naar Big Wall: Bergsportdag 2024
 
Alpiene Cursussen van Bergsportreizen: Bergsportdag 2024
Alpiene Cursussen van Bergsportreizen: Bergsportdag 2024Alpiene Cursussen van Bergsportreizen: Bergsportdag 2024
Alpiene Cursussen van Bergsportreizen: Bergsportdag 2024
 
How to Build a Site Using Nick
How to Build a Site Using NickHow to Build a Site Using Nick
How to Build a Site Using Nick
 
Nick: A Nearly Headless CMS
Nick: A Nearly Headless CMSNick: A Nearly Headless CMS
Nick: A Nearly Headless CMS
 
Van Klimhal naar Big Wall
Van Klimhal naar Big WallVan Klimhal naar Big Wall
Van Klimhal naar Big Wall
 
Van 0 naar 6000+
Van 0 naar 6000+Van 0 naar 6000+
Van 0 naar 6000+
 
How to create your own Volto site!
How to create your own Volto site!How to create your own Volto site!
How to create your own Volto site!
 
Volto Extensibility Story: Plone Conference 2018
Volto Extensibility Story: Plone Conference 2018Volto Extensibility Story: Plone Conference 2018
Volto Extensibility Story: Plone Conference 2018
 
Volto: Plone Conference 2018
Volto: Plone Conference 2018Volto: Plone Conference 2018
Volto: Plone Conference 2018
 
React Native: JS MVC Meetup #15
React Native: JS MVC Meetup #15React Native: JS MVC Meetup #15
React Native: JS MVC Meetup #15
 
React Native: React Meetup 3
React Native: React Meetup 3React Native: React Meetup 3
React Native: React Meetup 3
 
React Router: React Meetup XXL
React Router: React Meetup XXLReact Router: React Meetup XXL
React Router: React Meetup XXL
 
Four o Four: World Plone Day 2014
Four o Four: World Plone Day 2014Four o Four: World Plone Day 2014
Four o Four: World Plone Day 2014
 
Hackathon: Silicon Alley Lightning Talks
Hackathon: Silicon Alley Lightning TalksHackathon: Silicon Alley Lightning Talks
Hackathon: Silicon Alley Lightning Talks
 
Arnhem Sprint 2013: Plone Conference 2013
Arnhem Sprint 2013: Plone Conference 2013Arnhem Sprint 2013: Plone Conference 2013
Arnhem Sprint 2013: Plone Conference 2013
 
Plone 5: Nederlandse Plone Gebruikersdag 2014
Plone 5: Nederlandse Plone Gebruikersdag 2014Plone 5: Nederlandse Plone Gebruikersdag 2014
Plone 5: Nederlandse Plone Gebruikersdag 2014
 
Projectgroep Millennium GroenLinks Arnhem
Projectgroep Millennium GroenLinks ArnhemProjectgroep Millennium GroenLinks Arnhem
Projectgroep Millennium GroenLinks Arnhem
 
Deco UI: Plone Conference 2010
Deco UI: Plone Conference 2010Deco UI: Plone Conference 2010
Deco UI: Plone Conference 2010
 
Deco UI: DZUG Tagung 2010
Deco UI: DZUG Tagung 2010Deco UI: DZUG Tagung 2010
Deco UI: DZUG Tagung 2010
 
Deco UI: Nederlandse Plone Gebruikesdag 2010
Deco UI: Nederlandse Plone Gebruikesdag 2010Deco UI: Nederlandse Plone Gebruikesdag 2010
Deco UI: Nederlandse Plone Gebruikesdag 2010
 

Último

Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLLucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
imonikaupta
 
( Pune ) VIP Baner Call Girls 🎗️ 9352988975 Sizzling | Escorts | Girls Are Re...
( Pune ) VIP Baner Call Girls 🎗️ 9352988975 Sizzling | Escorts | Girls Are Re...( Pune ) VIP Baner Call Girls 🎗️ 9352988975 Sizzling | Escorts | Girls Are Re...
( Pune ) VIP Baner Call Girls 🎗️ 9352988975 Sizzling | Escorts | Girls Are Re...
nilamkumrai
 
VIP Call Girls Himatnagar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Himatnagar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Himatnagar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Himatnagar 7001035870 Whatsapp Number, 24/07 Booking
dharasingh5698
 
6.High Profile Call Girls In Punjab +919053900678 Punjab Call GirlHigh Profil...
6.High Profile Call Girls In Punjab +919053900678 Punjab Call GirlHigh Profil...6.High Profile Call Girls In Punjab +919053900678 Punjab Call GirlHigh Profil...
6.High Profile Call Girls In Punjab +919053900678 Punjab Call GirlHigh Profil...
@Chandigarh #call #Girls 9053900678 @Call #Girls in @Punjab 9053900678
 
Low Sexy Call Girls In Mohali 9053900678 🥵Have Save And Good Place 🥵
Low Sexy Call Girls In Mohali 9053900678 🥵Have Save And Good Place 🥵Low Sexy Call Girls In Mohali 9053900678 🥵Have Save And Good Place 🥵
Low Sexy Call Girls In Mohali 9053900678 🥵Have Save And Good Place 🥵
Chandigarh Call girls 9053900678 Call girls in Chandigarh
 

Último (20)

Real Men Wear Diapers T Shirts sweatshirt
Real Men Wear Diapers T Shirts sweatshirtReal Men Wear Diapers T Shirts sweatshirt
Real Men Wear Diapers T Shirts sweatshirt
 
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRLLucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
Lucknow ❤CALL GIRL 88759*99948 ❤CALL GIRLS IN Lucknow ESCORT SERVICE❤CALL GIRL
 
( Pune ) VIP Baner Call Girls 🎗️ 9352988975 Sizzling | Escorts | Girls Are Re...
( Pune ) VIP Baner Call Girls 🎗️ 9352988975 Sizzling | Escorts | Girls Are Re...( Pune ) VIP Baner Call Girls 🎗️ 9352988975 Sizzling | Escorts | Girls Are Re...
( Pune ) VIP Baner Call Girls 🎗️ 9352988975 Sizzling | Escorts | Girls Are Re...
 
VIP Call Girls Himatnagar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Himatnagar 7001035870 Whatsapp Number, 24/07 BookingVIP Call Girls Himatnagar 7001035870 Whatsapp Number, 24/07 Booking
VIP Call Girls Himatnagar 7001035870 Whatsapp Number, 24/07 Booking
 
Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Rani Bagh Escort Service Delhi N.C.R.
 
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providersMoving Beyond Twitter/X and Facebook - Social Media for local news providers
Moving Beyond Twitter/X and Facebook - Social Media for local news providers
 
Russian Call Girls Pune (Adult Only) 8005736733 Escort Service 24x7 Cash Pay...
Russian Call Girls Pune  (Adult Only) 8005736733 Escort Service 24x7 Cash Pay...Russian Call Girls Pune  (Adult Only) 8005736733 Escort Service 24x7 Cash Pay...
Russian Call Girls Pune (Adult Only) 8005736733 Escort Service 24x7 Cash Pay...
 
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
2nd Solid Symposium: Solid Pods vs Personal Knowledge Graphs
 
VVIP Pune Call Girls Mohammadwadi WhatSapp Number 8005736733 With Elite Staff...
VVIP Pune Call Girls Mohammadwadi WhatSapp Number 8005736733 With Elite Staff...VVIP Pune Call Girls Mohammadwadi WhatSapp Number 8005736733 With Elite Staff...
VVIP Pune Call Girls Mohammadwadi WhatSapp Number 8005736733 With Elite Staff...
 
Busty Desi⚡Call Girls in Vasundhara Ghaziabad >༒8448380779 Escort Service
Busty Desi⚡Call Girls in Vasundhara Ghaziabad >༒8448380779 Escort ServiceBusty Desi⚡Call Girls in Vasundhara Ghaziabad >༒8448380779 Escort Service
Busty Desi⚡Call Girls in Vasundhara Ghaziabad >༒8448380779 Escort Service
 
Katraj ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For S...
Katraj ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For S...Katraj ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready For S...
Katraj ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready For S...
 
Wagholi & High Class Call Girls Pune Neha 8005736733 | 100% Gennuine High Cla...
Wagholi & High Class Call Girls Pune Neha 8005736733 | 100% Gennuine High Cla...Wagholi & High Class Call Girls Pune Neha 8005736733 | 100% Gennuine High Cla...
Wagholi & High Class Call Girls Pune Neha 8005736733 | 100% Gennuine High Cla...
 
6.High Profile Call Girls In Punjab +919053900678 Punjab Call GirlHigh Profil...
6.High Profile Call Girls In Punjab +919053900678 Punjab Call GirlHigh Profil...6.High Profile Call Girls In Punjab +919053900678 Punjab Call GirlHigh Profil...
6.High Profile Call Girls In Punjab +919053900678 Punjab Call GirlHigh Profil...
 
Low Sexy Call Girls In Mohali 9053900678 🥵Have Save And Good Place 🥵
Low Sexy Call Girls In Mohali 9053900678 🥵Have Save And Good Place 🥵Low Sexy Call Girls In Mohali 9053900678 🥵Have Save And Good Place 🥵
Low Sexy Call Girls In Mohali 9053900678 🥵Have Save And Good Place 🥵
 
Russian Call Girls in %(+971524965298 )# Call Girls in Dubai
Russian Call Girls in %(+971524965298  )#  Call Girls in DubaiRussian Call Girls in %(+971524965298  )#  Call Girls in Dubai
Russian Call Girls in %(+971524965298 )# Call Girls in Dubai
 
WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)
WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)
WhatsApp 📞 8448380779 ✅Call Girls In Mamura Sector 66 ( Noida)
 
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
Call Now ☎ 8264348440 !! Call Girls in Shahpur Jat Escort Service Delhi N.C.R.
 
Real Escorts in Al Nahda +971524965298 Dubai Escorts Service
Real Escorts in Al Nahda +971524965298 Dubai Escorts ServiceReal Escorts in Al Nahda +971524965298 Dubai Escorts Service
Real Escorts in Al Nahda +971524965298 Dubai Escorts Service
 
Nanded City ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready ...
Nanded City ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready ...Nanded City ( Call Girls ) Pune  6297143586  Hot Model With Sexy Bhabi Ready ...
Nanded City ( Call Girls ) Pune 6297143586 Hot Model With Sexy Bhabi Ready ...
 
Al Barsha Night Partner +0567686026 Call Girls Dubai
Al Barsha Night Partner +0567686026 Call Girls  DubaiAl Barsha Night Partner +0567686026 Call Girls  Dubai
Al Barsha Night Partner +0567686026 Call Girls Dubai
 

Resource Registries: Plone Conference 2014

  • 1. Resource Registries Ramon Navarro Bosch & Rob Gietema
  • 2.
  • 3. Ramon Navarro Bosch • Iskra.CAT • Member Plone Foundation • FWT member
  • 4. Rob Gietema • Four Digits • Plone Foundation Member
  • 5. Current State <?xml version="1.0"?> <object name="portal_javascripts" meta_type="JavaScripts Registry"> <javascript compression="safe" authenticated="True" id="hello-world.js" insert-after="*" /> </object> <?xml version="1.0"?> <object name="portal_css"> <stylesheet title="" id="hello-world.css" media="screen" rel="stylesheet" rendering="link" cacheable="True" compression="safe" cookable="True" enabled="1" expression="" insert-before="print.css" /> </object> • JS Registry • CSS Registry • Tools
  • 6. Limitations • JS & CSS have evolved • Dependency management • Precompiling (LESS / SASS) • Versioning • Mockup
  • 7. RequireJS <!DOCTYPE html> <html> <head> <script data-main="app" src="lib/require.js"></script> </head> <body> <h1>Hello World</h1> </body> • Include require.js </html> // File: app.js // For any third party dependencies, like jQuery, place them in the lib folder. ! // Configure loading modules from the lib directory, // except for 'app' ones, which are in a sibling // directory. requirejs.config({ baseUrl: 'lib', paths: { app: '../app' } }); ! // Start loading the main app file. Put all of // your application logic in there. requirejs(['app/main']); • Add all your dependencies in Javascript • Async loading of files and modules
  • 8. GRUNT module.exports = function(grunt) { ! grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), concat: { options: { separator: ';' }, dist: { src: ['src/**/*.js'], dest: 'dist/<%= pkg.name %>.js' } }, qunit: { files: ['test/**/*.html'] }, watch: { files: ['<%= jshint.files %>'], tasks: ['jshint', 'qunit'] } }); ! grunt.loadNpmTasks('grunt-contrib-qunit'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-concat'); ! grunt.registerTask('test', ['jshint', 'qunit']); ! grunt.registerTask('default', ['qunit', 'concat']); ! }; • Task runner • Run tests, concat, minimize, JSHint etc
  • 9. NPM npm install (with no args in a package dir) npm install <tarball file> npm install <tarball url> npm install <folder> npm install [@<scope>/]<name> [--save|--save-dev|--save-optional] [--save-exact] npm install [@<scope>/]<name>@<tag> npm install [@<scope>/]<name>@<version> npm install [@<scope>/]<name>@<version range> npm i (with any of the previous argument usage) • Node.js package manager • Dependencies • Versioning
  • 10. Bower { "name": "my-project", "version": "1.0.0", "main": "path/to/main.js", "ignore": [ ".jshintrc", "**/*.txt" ], "dependencies": { "<name>": "<version>", "<name>": "<folder>", "<name>": "<package>" }, "devDependencies": { "<test-framework-name>": "<version>" } } • Javascript package manager • Dependencies • Versioning
  • 11. LESS / SASS @base: #f938ab; ! .box-shadow(@style, @c) when (iscolor(@c)) { -webkit-box-shadow: @style @c; box-shadow: @style @c; } .box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) { .box-shadow(@style, rgba(0, 0, 0, @alpha)); } .box { color: saturate(@base, 5%); border-color: lighten(@base, 30%); div { .box-shadow(0 0 5px, 30%) } } .box { color: #fe33ac; border-color: #fdcdea; } .box div { -webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); box-shadow: 0 0 5px rgba(0, 0, 0, 0.3); } • Precompiler for CSS • Variables • Nesting • Macro's
  • 12. Design of the Solution BUNDLE RESOURCE BOWER COMPONENT MOCKUP COMPONENT STANDALONE FILES DIAZO STATIC HTML REGISTRY
  • 13. Bundles • Dependency • Compilation • Enabled <records prefix="plone.bundles/plone-legacy" interface='Products.CMFPlone.interfaces.IBundleRegistry'> <value key="resources" purge="false"> <element>plone_javascript_variables</element> <element>unlockOnFormUnload</element> <element>table_sorter</element> <element>inline-validation</element> <element>jquery-highlightsearchterms</element> <element>cookie_functions</element> </value> <value key="jscompilation">++plone++static/plone-legacy-compiled.js</value> <value key="csscompilation">++plone++static/plone-legacy-compiled.css</value> <value key="last_compilation">2014-08-14 00:00:00</value> <value key="compile">False</value> <value key="enabled">True</value> </records> <records prefix="plone.bundles/plone" interface='Products.CMFPlone.interfaces.IBundleRegistry'> <value key="resources"> <element>plone</element> </value> <value key="enabled">True</value> <value key="jscompilation">++plone++static/plone-compiled.js</value> <value key="csscompilation">++plone++static/plone-compiled.css</value> <value key="last_compilation">2014-08-14 00:00:00</value> </records>
  • 14. Resources • js • export/init • css • url <records prefix="plone.resources/tinymce" interface='Products.CMFPlone.interfaces.IResourceRegistry'> <value key="js">++plone++static/components/tinymce/tinymce.js</value> <value key="export">window.tinyMCE</value> <value key="init">function () { this.tinyMCE.DOM.events.domLoaded = true; return this.tinyMCE; }</value> <value key="css"> <element>++plone++static/components/tinymce/skins/lightgray/skin.min.css</element> <element>++plone++static/components/tinymce/skins/lightgray/content.inline.min.css</element> </value> </records> <records prefix="plone.resources/mockup-patterns-select2" interface='Products.CMFPlone.interfaces.IResourceRegistry'> <value key="js">++resource++mockup/select2/patterns.js</value> <value key="css"> <element>++resource++mockup/select2/pattern.select2.less</element> </value> </records> <records prefix="plone.resources/mockup-patterns-structure" interface='Products.CMFPlone.interfaces.IResourceRegistry'> <value key="js">++resource++mockup/structure/pattern.js</value> <value key="url">++resource++mockup/structure</value> <value key="css"> <element>++resource++mockup/structure/less/pattern.structure.less</element> </value> </records>
  • 15. LESS Vars <!-- Mixins vars for less with the paths --> <record name="plone.lessvariables"> <field type="plone.registry.field.Dict"> <title>Less variables</title> <description>Variables that are going to be compiled on less</description> <key_type type="plone.registry.field.ASCIILine" /> <value_type type="plone.registry.field.TextLine" /> </field> <value> <element key="bowerPath">"{site_url}/++plone++static/components/"</element> <element key="mockupPath">"{site_url}/++resource++mockup/"</element> <element key="mockuplessPath">"{site_url}/++resource++mockupless/"</element> ! <element key="plone-link-color">rgba(0,123,179,1)</element> <element key="plone-gray-lighter">lighten(#000, 80%)</element> <element key="plone-gray-light">lighten(#000, 46.5%)</element> ! <element key="plone-toolbar-bg">rgba(0,0,0,.9)</element> <element key="plone-toolbar-submenu-bg">rgba(20,20,20,.9)</element> <element key="plone-toolbar-font-primary">'Roboto Condensed', sans-serif</element>
  • 16. Pattern Options <record name="plone.patternoptions"> <field type="plone.registry.field.Dict"> <title>Patterns configuration</title> <description>Base pattern configuration options</description> <key_type type="plone.registry.field.ASCIILine" /> <value_type type="plone.registry.field.Text" /> </field> <value> <element key="pickadate">{"selectYears": 200}</element>
  • 17. Development & Production <record name="plone.resources.development"> <field type="plone.registry.field.Bool"> <title>Frontend development mode</title> </field> <value>true</value> </record> • Compile on browser on each reload using RequireJS / LESS • Develop static HTML with compiled bundles • Grunt using browser config.js/ mixins.less • Get the compiled css/js bundles • Deployment with compiled css/js
  • 18. Diazo [theme] title = Barceloneta Theme description = Plone 5 theme rules = /++theme++barceloneta/rules.xml prefix = /++theme++barceloneta doctype = <!DOCTYPE html> enabled-bundles = barceloneta disabled-bundles = <!-- CSS --> <after theme-children="/html/head" content="/html/head/link" /> <!-- Script --> <after theme-children="/html/head" content="/html/head/script" />
  • 19. Views: config.js requirejs.config({ baseUrl: 'http://localhost:8080/Plone', paths: { 'tinymce-save': ‘++plone++static/components/tinymce/plugins/save/plugin', 'mockup-patterns-accessibility': ‘++resource++mockup/accessibility/pattern’, 'mockup-patterns-tinymce-url': '++resource++mockup/tinymce' … 'mockup-patterns-formautofocus': '++resource++mockup/formautofocus/pattern', 'bootstrap-tooltip': '++plone++static/components/bootstrap/js/tooltip', 'resource-plone-app-event-portlet_calendar-js': '++resource++plone.app.event.portlet_calendar', 'dropzone': '++plone++static/components/dropzone/downloads/dropzone-amd-module'}, shim: { 'tinymce-save': {deps: ['tinymce']}, 'mockup-router': {}, 'tinymce-spellchecker': {deps: ['tinymce']}, 'jquery.event.drop': {exports: '$.drop', deps: ['jquery']}, 'tinymce-autosave': {deps: ['tinymce']}, … 'bootstrap-tooltip': {deps: ['jquery']}}, optimize: 'uglify', wrapShim: true });
  • 20. Views: less-variables.js window.less = { env: "development", logLevel: 2, async: false, fileAsync: false, errorReporting: window.lessErrorReporting || 'console', poll: 1000, functions: {}, relativeUrls: true, dumpLineNumbers: "comments", globalVars: { sitePath: '"http://localhost:8080/Plone"', isPlone: 'true', isMockup: 'false', 'plone-toolbar-font-primary': "'Roboto Condensed', sans-serif", 'plone-gray-lighter': "lighten(#000, 80%)", 'mockuplessPath': ""http://localhost:8080/Plone/++resource++mockupless/"", 'bowerPath': ""http://localhost:8080/Plone/++plone++static/components/"", 'plone-toolbar-internally-published-color': "rgb(136,61,250)", 'mockupPath': ""http://localhost:8080/Plone/++resource++mockup/"", … 'plone-toolbar-private-color': "rgb(196,24,60)", 'plone-screen-xs-max': "(@plone-screen-sm-min + 1)", 'plone-toolbar-bg': "rgba(255,0,0,.9)", 'plone-gray-light': "lighten(#000, 46.5%)", 'barceloneta': ‘"http://localhost:8080/Plone/++plone++barceloneta/less/barceloneta.plone.less"', … 'picker_time': '"http://localhost:8080/Plone/++plone++static/components/pickadate/lib/themes/classic.time.css"', 'picker': '"http://localhost:8080/Plone/++plone++static/components/pickadate/lib/themes/classic.css"', 'plone-patterns-toolbar': '"http://localhost:8080/Plone/++plone++static/patterns/toolbar/src/css/toolbar.plone.less"', 'plone': '"http://localhost:8080/Plone/++plone++static/plone.less"', …}};
  • 21. plone.less … @import url("@{mockup-patterns-upload}"); @import url("@{plone-patterns-toolbar}"); @import url("@{mockup-patterns-tinymce}"); ! ! @import "@{bowerPath}bootstrap/less/dropdowns.less"; …
  • 22. plone.js require([ 'jquery', 'mockup-registry', 'mockup-patterns-base', 'mockup-patterns-select2', 'mockup-patterns-pickadate', 'mockup-patterns-relateditems', 'mockup-patterns-querystring', 'mockup-patterns-tinymce', 'plone-patterns-toolbar', 'mockup-patterns-accessibility', 'mockup-patterns-autotoc', 'mockup-patterns-formunloadalert', 'mockup-patterns-preventdoublesubmit', 'mockup-patterns-formautofocus', 'mockup-patterns-modal', 'mockup-patterns-structure', 'bootstrap-dropdown', 'bootstrap-collapse', ‘bootstrap-tooltip' …
  • 23. TTW customization • Fully customizable trough the web • Controlpanel in Plone
  • 24. Legacy Plone • cssregistry.xml and jsregistry.xml still work • Legacy bundle • Not all attributes are supported <?xml version="1.0"?> <object name="portal_javascripts" meta_type="JavaScripts Registry"> <javascript compression="safe" authenticated="True" id="hello-world.js" insert-after="*" /> </object> <?xml version="1.0"?> <object name="portal_css"> <stylesheet title="" id="hello-world.css" media="screen" rel="stylesheet" rendering="link" cacheable="True" compression="safe" cookable="True" enabled="1" expression="" insert-before="print.css" /> </object>
  • 25. Standard resources • Mockup • Bower components accessibility autotoc backdrop eventedit filemanager formautofocus formunloadalert modal moment pickadate preventdoublesubmit querystring relateditems resourceregistry select2 sortable structure tablesorter texteditor thememapper tinymce toggle tooltip tree upload
  • 26. Are you able to do "console dev" ? • generate_gruntfile.py -> creates Gruntconfig.js
  • 27. Demo
  • 28. Migration • Resources defined as pattern and less file • Always generate production bundle • Move jsregistry and cssregistry to registry.xml • On/live jquery 1.11 modifications • Never loose hope
  • 29. Questions ? • Additional info at: • https://www.nathanvangheem.com/news/plone-5- resource-registries
  • 30. SPRINT • Static CSS/JS for mockups / CDN • Cooking on production • Mockup issues • Write documentation!! • Write tests!!