#SummitNow Alfresco 4.2 Share Development Workshop November 6, 2013 Kevin Dorr, Sr. Solutions Engineer, Alfresco US
#SummitNow Overview
#SummitNow Workshop Outline Development Tools Housekeeping Simple Project Definition Simple Page 10 Minutes on Dojo Simple Widget Big Finish
#SummitNow My Perspective
#SummitNow Audience Participation
#SummitNow Getting Started
#SummitNow What You Will Need… Java (JDK 1.7) Maven (3.1) Eclipse (Kepler) m2Eclipse Alfresco Source
#SummitNow Lay of the Land
#SummitNow Change is Good Dave Draper went over why yesterday There are a lot of benefits for both page and widget development It really is a LOT easier!
#SummitNow Where Things Are Source Code: root/projects/slingshot /source/web Widget library is in js/alfresco Also themes, etc. Warning!
#SummitNow Where Things Are Widget Code: templates i18n images other special Widget css js alfresco
#SummitNow Where Things Should Go For Production: Make an AMP File! Alfresco amps Repo amp share_amps Share amp
#SummitNow Where Things Should Go For Development (pages and widgets): tomcat shared lib jar
#SummitNow Where Things Should Go For Development (Pages): tomcat shared Site- webscripts classes alfresco Any Arbitrary Path Individual Code Files Web- extension
#SummitNow Where Things Should Go
#SummitNow Resources You Can Leverage
#SummitNow Resources You Can Leverage
#SummitNow Resources You Can Leverage Debug mode: tomcat/webapps/share/classes/alfresco/share-config.xml Tomcat/shared/classes/alfresco/web-extension/share-config-custom.xml true
#SummitNow “Zero Build” widget resource list widget resource list widget resource list widget resource list JSON Page Definition “Built” Dojo Ipsum loren ipsum Ipsum loren Ipsum loren etc User page rendering CSS Image Dojo CSS Dojo Cached Resources CSS Image Dojo CSS Dojo CSS i18n Dojo CSS Server Page Resources Analyze Resolve and Generate Cache
#SummitNow See How Resources are Managed
#SummitNow Share Surf Servlet URIs Stand Alone Page Webscripts /share/page/dp/ws/{webscript URL} /share/page/site/{site}/dp/ws/{ws URL} Hybrid Pages (Share header and footer) /share/page/hdp/ws/{ws URL} Hybrid Remote Pages (from Repo) /share/page/site/{site}/p/{page name} /share/page/hrp/p/{page name}
#SummitNow A Simple Project
#SummitNow Project Concept Special Purpose UI for a Photo Intake Editor Doesn’t need or want to see the rest of Share Just needs to sort photos into keep, maybe, reject Has several “trays” of photos to sort through Has several projects simultaneously
#SummitNow UI Sketch Company Header “Slide Tray” Selection Area Tray Filters Photo Viewer Area
#SummitNow Page Construction
#SummitNow Share Page Example
#SummitNow Share Page Example Lightbox Widget Here Accordion Widget Here
#SummitNow Share Page Files page-name.get.desc.xml (Webscript Descriptor) page-name.get.js (WebScript Controller) page-name.get.html.ftl (Freemarker Template) page-name.get.properties(Optional Text Strings) Files need to be in the same directory Anywhere under site-webscripts is ok
#SummitNow Share Page Descriptor (desc.xml) Create page via JSON editor A page definition for creating pages using a JSON editor Share /page-editor
#SummitNow Share Page Template (.html.ftl)
#SummitNow Share Page Controller (.js) { "widgets": [ { "id": "SET_PAGE_TITLE", "name": "alfresco/header/SetTitle", "config": { "title": "Alfresco Summit Demo" } }, { "name": "alfresco/layout/AlfSideBarContainer", "config": { "initialSidebarWidth": "300" } ] }
#SummitNow Modifying the JSON { "name": "alfresco/layout/AlfSideBarContainer", "config": { "initialSidebarWidth": "300", "widgets": [{ "name": "alfresco/menus/AlfMenuBar", "align": "sidebar", "config": { "widgets": [ { "name": "alfresco/menus/AlfMenuBarItem", "config": { "label": "Filter" } }, { "name": "alfresco/menus/AlfMenuBarItem", "config": { "label": “Project" } }] } } }
#SummitNow How Really Cool This Is Last year, I built a Share UI: Page definition Template Instance Scripting Freemarker template CSS Javascript
#SummitNow How Really Cool This Is This year, I built this: LightboxAccordion Using this: In 30 Minutes!
#SummitNow How Really Cool This Is
#SummitNow Dojo in 10 Minutes
#SummitNow What is Dojo? It’s a Javascript Library! But seriously, it’s got a lot of really good stuff AMD (asynchronous module definition) Widget Templating Accessibility Constructs Unit Testing
#SummitNow What is Dojo? Base DijitDojoX Util (doh) Alfresco Core
#SummitNow Including Dojo Basic: <script type=“text/javascript” src=“www/js/dojo/dojo.js”>
#SummitNow Including Dojo However, Surf resolves everything for you (share/WEB-INF/surf.xml): /res/js/lib/dojo-1.9.0/dojo/dojo.js alfresco/core/Page /res/
#SummitNow Dojo Modules Dojo has a mechanism to define a module Dojo.provide(“myns.mycode”); Which you then include like this: Dojo.require(“myns.mycode”); However, this is just synchronous loading
#SummitNow Dojo Modules Asynchronous Module Definition (AMD): Uses “path” syntax instead of dots: “myns/mycode” New keyword and pattern: define([ "dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin" ], function( declare, _WidgetBase, _TemplatedMixin ){ return declare([ _WidgetBase, _TemplatedMixin ], {}); });
#SummitNow Dojo Modules New require format: require([ "dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin" ], function(declare, _WidgetBase, _TemplatedMixin){ // callback is optional }); This will be built automatically by Surf Cross domain loading is implicit!
#SummitNow Dojo Mixins Dojo provides a mechanism to “mix” objects together Base object + object to append Always mixin the alfresco/core/Core module Helps to resolve i18n strings correctly Other wrappers and Alfresco utility functions
#SummitNow The Dojo Event Model Pub/Sub Widget publishes events by name Consumers can subscribe to get the events, also by name Bubbling Event “bubbles up” the containing widgets until a handler is found
#SummitNow Dijit Widgets Dijit is a UI Widget Library Infrastructure: dijit._widgetBase dijit._TemplatedMixin Menu, Tree, Misc Widget sets Form Widgets Text, Button, ComboBox, Slider, etc. Layout Widgets Container, Border, Tab, Accordion, etc.
#SummitNow Widget Construction
#SummitNow Where we left off… LightboxAccordion
#SummitNow Share Widget Encapsulation Javascript + HTML + CSS + i18N
#SummitNow An Accordion Widget Base ours on the one in the Dijit library – AccordionContainer Takes ContentPanes as children Mixin the Alfresco Core to get the Alfresco pattern
#SummitNow An Accordion Widget Page JSON AlfAccordionContainer Alfresco Repo AlfContentPanel Instance and Parameters Call WS JSON Result
#SummitNow Widget Implementation Class is named by the filename Define and include mixins: define(["dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin", "alfresco/core/Core", "dojo/text!./templates/AlfAccordionContainer.html", "dijit/layout/AccordionContainer", "dojo/_base/array"], function(declare, _Widget, _Templated, AlfCore, template, Accordion, array) { return declare([_Widget, _Templated, AlfCore], { define(["dojo/_base/declare", "dijit/_WidgetBase", "dijit/_TemplatedMixin", "alfresco/core/Core", "dojo/text!./templates/AlfAccordionContainer.html", "dijit/layout/AccordionContainer", "dijit/layout/ContentPane", "dojo/_base/array"], function(declare, _Widget, _Templated, AlfCore, template, Accordion, ContentPane, array) { return declare([_Widget, _Templated, AlfCore], { // declare callback 1 for 1
#SummitNow Widget Implementation Next, pull in the CSS, i18n, and template: // snip… in the declare callback cssRequirements: [{cssFile:"./css/AlfAccordionContainer.css"}], i18nRequirements: [{i18nFile: "./i18n/AlfAccordionContainer.properties"}], templateString: template, //snip…
#SummitNow Widget Implementation Define a XHR function to make a call to the repo: // snip… in the declare callback: loadContent: function alfresco_accordion_AlfAccordionContainer__loadContent() { if ( this._contentLoaded ) { this.alfLog("log", “Content already loaded"); } else { this.alfLog("log", "Loading accordion content pages"); var url = this._contentUrl; if ( url == null ) { url = Alfresco.constants.URL_SERVICECONTEXT + “slidedecks/select"; if ( this.currentSite ) { url = url + "/site/" + this.currentSite; } this.serviceXhr({url : url, method: "GET", successCallback: this._contentDataLoaded, failureCallback: this._contentDataLoadFailed, callbackScope: this}); } },
#SummitNow Widget Implementation Build the accordion from the data in the postCreate method: //snip… in the declare callback: postCreate: function alfresco_accordion_AlfAccordionContainer__postCreate() { this._accordion = new Accordion( {} ); // add the array of panels built from the Xhr callback array.forEach( _panelList, function(panel, index) { _this._accordion.addChild( panel ); }); this._accordion.placeAt( this.containerNode ); },
#SummitNow Finishing My Page
#SummitNow Modifying the JSON { "name": "alfresco/layout/AlfSideBarContainer", "config": { "initialSidebarWidth": "300", "widgets": [{ "name": "alfresco/menus/AlfMenuBar", "align": "sidebar", // menu config…. }, { "name": "alfresco/accordion/AlfAccordionContainer", "align": "sidebar" } ]} }
#SummitNow The Prototype with the Accordion!
#SummitNow The Big Finish
#SummitNow What have we learned today? New AMD Infrastructure allows for decoupled encapsulated construction, plus rich features Page Construction all of the icky bits are hidden Widget Construction build and contribute whatever you need
#SummitNow Thanks UI Team!
#SummitNow Questions
#SummitNow