Decoupled Drupal Powering an Interactive Touchscreen Kiosk
on decoupling drupal
Rendered Pages
CMS
Custom Front End
CMS
Content Creation Tools
Content Repository
Presentation Logic
(renders raw data into pages)
Content Creation Tools
Content Repository
Raw Data
Traditional
Headless/Decoupled
Rendered Page
CMS
Content Creation Tools
Content Repository
API
Progressively Decoupled
Component
Component
Presentation Logic
Custom Front End
CMS
(renders raw data into pages)
Content Creation Tools
Content Repository
Raw Data
Fully Decoupled
building a kiosk
AngularJS
Drupal 7
Youtube
Google Maps + Calendar
Drupal
Home Screen
Ensembles
Photo Gallery
Video Gallery
Calendar
Map
Ensemble Members
Ensemble Detail
Member Bios
Facebook Graph API
Youtube player API
Google Calendar / .ics
Google Maps
Google Geocoding API
Drupal
Home Screen
Ensembles
Photo Gallery
Video Gallery
Calendar
Map
Ensemble Members
Ensemble Detail
Member Bios
Facebook Graph API
Youtube player API
Google Calendar / .ics
Google Maps
Google Geocoding API
Drupal
Home Screen
Ensembles
Photo Gallery
Video Gallery
Calendar
Map
Ensemble Members
Ensemble Detail
Member Bios
Facebook Graph API
Youtube player API
Google Calendar / .ics
Google Maps
Google Geocoding API
https://drupalize.me/blog/201401/introduction-restful-web-services-drupal-8
Drupal
Home Screen
Ensembles
Photo Gallery
Video Gallery
Calendar
Map
Ensemble Members
Ensemble Detail
Member Bios
Facebook Graph API
Youtube player API
Google Calendar / .ics
Google Maps
Google Geocoding API
angular.module('calendar.services', [])
.provider('CalendarConfiguration', function CalendarConfigurationProvider (){
this.addGoogleCalendar = function(calendarLabel, calendarId, apiKey){
// ...Store config details for a google calendar.
};
this.addIcalCalendar = function(calendarLabel, calendarId, apiKey){
// ...Store config details for an Ical
};
});
Creating an angular service for calendar config
separate methods for google & ical
angular.module( 'kiosk', [
'calendar.services'
])
.config( function kioskConfig( CalendarConfigurationProvider ){
CalendarConfigurationProvider.addIcalCalendar('Sessions', 'http://badcampdemo.local/sessions');
CalendarConfigurationProvider.addGoogleCalendar('Bay Area Events', 'foo@group.calendar.google.com');
})
Allows one-line configuration for each calendar source
note both ical and google calendars used above
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:web test events
X-WR-TIMEZONE:America/New_York
X-WR-CALDESC:A test calendar for importing and exporting events
BEGIN:VEVENT
DTSTART:20161024T223000Z
DTEND:20161025T015500Z
DTSTAMP:20161022T182226Z
UID:AEE7890B-17D0-4598-BDED-9C27A79E1901
URL:message://%3C119004230.1476213003399.JavaMail.dets%40ny-dets-002%3E?c=1
476213006&k=%7CflightF9%5C%7CDEN%5C%7CDCA%5C%7C720%5C%7C
CREATED:20161012T184448Z
DESCRIPTION:Brian Reginald Reese
LAST-MODIFIED:20161012T184448Z
LOCATION:Denver International Airport
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Flight: F9 720 from DEN to DCA
TRANSP:OPAQUE
X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-APPLE-RADIUS=0;X-TITLE=Denver Inter
national Airport:geo:39.861698,-104.672996
X-APPLE-SUGGESTION-INFO-CHANGED-FIELDS:0
X-APPLE-SUGGESTION-INFO-CHANGES-ACKNOWLEDGED:FALSE
X-APPLE-SUGGESTION-INFO-OPAQUE-KEY:|flightF9\\|DEN\\|DCA\\|720\\|
X-APPLE-SUGGESTION-INFO-UNIQUE-KEY:|2|\\|flightF9\\\\\\|DEN\\\\\\|DCA\\\\\\
|720\\\\\\||\\|5\\|\\\\\\|4371109B-D5A3-47B0-953E-41271774D06A\\\\\\|<11900
4230.1476213003399.JavaMail.dets@ny-dets-002>
X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:DISABLED
END:VEVENT
END:VCALENDAR
A google calendar feed
BEGIN:VCALENDAR
VERSION:2.0
METHOD:PUBLISH
X-WR-CALNAME;VALUE=TEXT:
PRODID:-//Drupal iCal API//EN
BEGIN:VEVENT
SUMMARY: Brian demos a kiosk
DTSTART:20161023T143907Z
CREATED:20161021T233907Z
LOCATION: UC Berkeley, Berkeley CA
DESCRIPTION: Lorem ipsum dolor sit amet, consectetur adipiscing elit...
END:VEVENT
END:VCALENDAR
My drupal ical feed
BEGIN:VCALENDAR
PRODID:-//Google Inc//Google Calendar 70.9054//EN
VERSION:2.0
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:web test events
X-WR-TIMEZONE:America/New_York
X-WR-CALDESC:A test calendar for importing and exporting events
BEGIN:VEVENT
DTSTART:20161024T223000Z
DTEND:20161025T015500Z
DTSTAMP:20161022T182226Z
UID:AEE7890B-17D0-4598-BDED-9C27A79E1901
URL:message://%3C119004230.1476213003399.JavaMail.dets%40ny-dets-002%3E?c=1
476213006&k=%7CflightF9%5C%7CDEN%5C%7CDCA%5C%7C720%5C%7C
CREATED:20161012T184448Z
DESCRIPTION:Brian Reginald Reese
LAST-MODIFIED:20161012T184448Z
LOCATION:Denver International Airport
SEQUENCE:0
STATUS:CONFIRMED
SUMMARY:Flight: F9 720 from DEN to DCA
TRANSP:OPAQUE
X-APPLE-STRUCTURED-LOCATION;VALUE=URI;X-APPLE-RADIUS=0;X-TITLE=Denver Inter
national Airport:geo:39.861698,-104.672996
X-APPLE-SUGGESTION-INFO-CHANGED-FIELDS:0
X-APPLE-SUGGESTION-INFO-CHANGES-ACKNOWLEDGED:FALSE
X-APPLE-SUGGESTION-INFO-OPAQUE-KEY:|flightF9\\|DEN\\|DCA\\|720\\|
X-APPLE-SUGGESTION-INFO-UNIQUE-KEY:|2|\\|flightF9\\\\\\|DEN\\\\\\|DCA\\\\\\
|720\\\\\\||\\|5\\|\\\\\\|4371109B-D5A3-47B0-953E-41271774D06A\\\\\\|<11900
4230.1476213003399.JavaMail.dets@ny-dets-002>
X-APPLE-TRAVEL-ADVISORY-BEHAVIOR:DISABLED
END:VEVENT
END:VCALENDAR
A google calendar feed
BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//AFWebCMS//Omnitech Inc.//EN
BEGIN:VEVENT
DTSTART:20160504T120000Z
DEND:20160504T090000Z
SUMMARY:12:10-12:45 p.m.
St. John's Church at Lafayette Square
1525 H St. NW
Washington, DC 20005
Join us for an afternoon of music for string orchestra and soloists. We will be performing J.S. Bach's Brandenburg Concerto No. 5 in D Major, BWV 1050 and Friedrich Robert Volkmann's Serenade No. 2 in F Major, Op. 63. Soloist for the Brandenburg concerto are Chief Master Sergeant Stacy Ascione, flute; Master Sergeant Cleveland Chandler, violin; and Brandon Straub, harpsichord.
END:VEVENT
END:VCALENDAR
calendar from legacy cms
angular.module('calendar.services', [])
.provider('CalendarConfiguration', function CalendarConfigurationProvider (){
// ...
})
.service( 'calendarService', ['$http', '$q', 'CalendarConfiguration'],
function($http, $q, CalendarConfiguration) {
var fetchGcalEvents = function() {
// Fetch calendar data using $http and parse relevant details
// Return a promise.
}
var fetchIcalEvents = function() {
// Fetch calendar data using $http and parse relevant details
// Return a promise.
};
});
In our angular calendar services module, we define methods to fetch each type of feed
// ...
var fetchEvents = function(){
CalendarConfiguration.getGoogleCalendars().forEach(function(){
calendarEvents.push(fetchGcalEvents());
});
CalendarConfiguration.getIcalCalendars().forEach(function(){
calendarEvents.push(fetchIcalEvents());
});
$q.all(calendarEvents).then(function(promiseResolves){
// Combine our resolves.
var data = [];
promiseResolves.forEach(function(promiseResolve){
data.concat(promiseResolve);
});
// resolve the original promise.
promiseObj.resolve(data);
});
};
And then we write a wrapper to resolve all the data at the same time
angular.module( 'kiosk', [
'calendar.services'
])
.config( function kioskConfig( CalendarConfigurationProvider ){
CalendarConfigurationProvider.addIcalCalendar('Sessions', 'http://badcampdemo.local/sessions');
CalendarConfigurationProvider.addIcalCalendar('Bay Area Events', 'foo@group.calendar.google.com');
})
.controller( 'KioskCtrl', function KioskCtrl($scope, calendarService) {
calendarService.fetchEvents().then(function(events){
$scope.events = events;
})
});
Allows us to populate $scope with a an array of all our events