familysearch reference client

36
THE FAMILYSEARCH REFERENCE CLIENT Open-source implementation of the Family Tree UI Written as a Single-Page Application in Javascript using the REST API DALLAN QUASS LYNN MONSON DOVY PAUKSTYS

Upload: dallan-quass

Post on 14-Jun-2015

153 views

Category:

Technology


1 download

DESCRIPTION

Talk given at the FamilySearch Developers Conference in September 2014

TRANSCRIPT

Page 1: FamilySearch Reference Client

THE FAMILYSEARCHREFERENCE CLIENT

Open-source implementation of the Family Tree UI

Written as a Single-Page Application in Javascript

using the REST API

DALLAN QUASSLYNN MONSON

DOVY PAUKSTYS

Page 2: FamilySearch Reference Client

TOUR

Page 3: FamilySearch Reference Client

SELECT PERSON

Page 4: FamilySearch Reference Client

PERSON

Page 5: FamilySearch Reference Client

PERSON (SCROLL DOWN)

Page 6: FamilySearch Reference Client

EDIT NAME

Page 7: FamilySearch Reference Client

CHINESE

Page 8: FamilySearch Reference Client

ADD EVENT

Page 9: FamilySearch Reference Client

ADD SOURCE

Page 10: FamilySearch Reference Client

SOURCE BOX

Page 11: FamilySearch Reference Client

WHY WAS ITDEVELOPED?

1. Make it easy for partners to allow their customers to accessthe FamilySearch tree using an easily-extensible framework

2. Provide a set of re-usable components for use by partners3. A real-world example of accessing the FamilySearch Tree

using the FamilySearch Javascript SDK

Page 12: FamilySearch Reference Client

DISCLAIMERSNot official - not an official FamilySearch projectNot supported - code is provided as-isNot maintained - everything currently works...

Page 13: FamilySearch Reference Client

WHAT CAN I DO WITH IT?1. Have you ever thought you could improve upon the

FamilySearch UI?Fork this project and extend it

2. Do you want to allow people to edit names and are intimidatedby the complexity?

Use the name edit component from this project3. Would you like to understand better how to use the

FamilySearch REST API?Review the source for this project

Page 14: FamilySearch Reference Client

HOW CAN I GETSTARTED?

Install pre-requisites

Install node.js (nodejs.org)npm install -g bower install bowernpm install -g grunt-cli install gruntInstall PhantomJS (phantomjs.org)

Page 15: FamilySearch Reference Client

HOW CAN I GETSTARTED?

Get an App Key

Contact FamilySearch developer support if you don't alreadyhave one

Ask FamilySearch developer support to add as an OAuth redirect URLhttp://localhost:9000/#!/auth

Page 16: FamilySearch Reference Client

HOW CAN I GETSTARTED?

Run the code

clone github.com/rootsdev/familysearch-reference-clientnpm install install build dependenciesbower install install client dependenciesgrunt watch launch a server and watch for changesVisit Sign in using your sandbox username and password

http://localhost:9000

Page 17: FamilySearch Reference Client

ANGULARJS

Page 18: FamilySearch Reference Client

ANGULARJS FRAMEWORKModelsViewsControllers Directives (components)FiltersServices dependency injectioneasy unit tests

Page 19: FamilySearch Reference Client

index.htmlhead> <!-- include stylesheets, fonts, and javascripts --></head>body> <div class="navbar navbar-default navbar-static-top"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="/">FamilySearch Reference Client</a> <span ng-show="busy" style="float: left; line-height: 50px"><i class="fa fa-spinner fa-spin" </div> <div class="collapse navbar-collapse header-collapse"> </div> </div> </div> <div id="themeContainer" class="familysearch_theme"> <div fs-growl=""></div> <div fs-re-authenticate=""></div> <div class="container" ui-view=""></div> </div></body>

Page 20: FamilySearch Reference Client

app.jsangular.module('fsReferenceClient', [ 'fsReferenceClientShared', 'templates-app', 'templates-common' .config(function($stateProvider, $urlRouterProvider) { $urlRouterProvider.otherwise('/'); }) .config(function(fsApiProvider) { fsApiProvider .setClientId('WCQY-7J1Q-GKVV-7DNM-SQ5M-9Q5H-JX3H-CMJK') .setEnvironmentName('sandbox') .setRedirectUri('http://localhost:9000/#!/auth'); }) .config(function(fsLocationProvider) { var prefix = '/#'; fsLocationProvider.configure({ getPersonLocation: function(personId) { return { prefix: prefix, path: '/person/'+personId }; }, ... }); })

Page 21: FamilySearch Reference Client

app.js (continued).controller('AppController', function ($scope) { $scope.environment = 'Sandbox'; $scope.$on('$stateChangeStart', function(event, toState) { if (toState.resolve) { $scope.busy = true; } }); $scope.$on('$stateChangeSuccess', function() { $scope.busy = false; }); $scope.$on('$stateChangeError', function() { $scope.busy = false; }); });

Page 22: FamilySearch Reference Client

person.jsangular.module('fsReferenceClient') .config(function ($stateProvider) { $stateProvider.state('person', { url: '/person/:personId', controller: 'PersonController', templateUrl: 'person/person.tpl.html', data: { pageTitle: 'Person' }, resolve: { person: ['$stateParams','fsApi',function($stateParams, fsApi) { return fsApi.getPerson($stateParams.personId).then(function (response) { return response.getPerson(); }); }], sources: ['_','$q','$stateParams','fsApi',function(_, $q, $stateParams, fsApi) return fsApi.getPersonSourcesQuery($stateParams.personId).then(function(response) return _.map(response.getSourceRefs(), function(sourceRef) { return { ref: sourceRef, description: response.getSourceDescription(sourceRef.$sourceDescriptionId id: sourceRef.id }; }); }); }] } });

Page 23: FamilySearch Reference Client

person.js (continued).controller('PersonController', function ($scope, $state, $rootScope, person, sources, fsApi, fsUtils, fsCurrentUserCache) var sections = ['vitalFacts', 'otherInfo', 'familyMembers', 'sources', 'discussions' $scope.states = {}; sections.forEach(function(section) { $scope.states[section] = {value: 'open'}; }); $scope.person = person; $scope.sources = sources; sources.forEach(function(source) { fsUtils.mixinStateFunctions($scope, source); });

var unbindRestored = $rootScope.$on('restored', function() { fsApi.getPerson($scope.person.id).then(function (response) { fsUtils.refresh($scope.person, response.getPerson()); }); }); $scope.$on('$destroy', unbindRestored);

$scope.$on('delete', function(event, person, changeMessage) { event.stopPropagation(); person._busy = true; person.$delete(changeMessage).then(function() { person._busy = false; fsCurrentUserCache.getUser().then(function(user) { $state.go('person', { personId: user.personId });

Page 24: FamilySearch Reference Client

person.tpl.htmldiv fs-person-profile="" person="person"></div>div class="mainContent"> <div class="row"> <div class="col-md-9"> <div fs-vital-facts-section="" person="person" sources="sources" state="states <div fs-other-info-section="" person="person" state="states['otherInfo']"></div <div fs-family-members-section="" person="person" state="states['familyMembers <div fs-sources-section="" person="person" sources="sources" state="states['sources <div fs-discussions-section="" person="person" state="states['discussions']"></ <div fs-notes-section="" person="person" state="states['notes']"></div> </div> <div class="col-md-3 sidebar"> <div fs-changes-section="" person="person"></div> <div fs-tools-section="" person="person"></div> </div> </div></div>

Page 25: FamilySearch Reference Client

fsPersonProfile.jsangular.module('fsReferenceClientShared') .directive('fsPersonProfile', function (fsLocation) { return { templateUrl: 'fsReferenceClientShared/fsPersonProfile/fsPersonProfile.tpl.html' scope: { person: '=' }, link: function(scope) { scope.treeHref = fsLocation.getTreeUrl(scope.person.id); } }; });

Page 26: FamilySearch Reference Client

fsPersonProfile.tpl.htmldiv class="profileHeaderContainer"> <div class="tree-family jumbotron"> <div class="personWrapper"> <div class="nameWrapper"> <div class="row"> <div class="col-lg-2 col-md-2"> <i class="icon-rounded hidden-xs" ng-class="{'fs-icon-male': person._isMale(), 'fs-icon-female': !person._isMale()}"> </i> </div> <div class="col-lg-10 col-md-10"> <div class="pull-right"><span ng-show="person._busy"> <i class="fa fa-spinner fa-spin"></i></span></div> <h1>{{person.$getDisplayName()}}</h1> <span class="lifeSpan">{{person.$getDisplayBirthDate()}} - {{person.$getDisplayDeathDate()}}</span> <span class="pid">{{person.id}}</span> <div class="personActions"> <ul class="list-collapsed"> <li class="pull-left"><a ng-href="{{treeHref}}"> <i class="fs-icon-male fs-icon-pedigree"> </i>View Tree</a></li> </ul> </div> </div> </div> </div> </div>

Page 27: FamilySearch Reference Client

EXTENDING

Page 28: FamilySearch Reference Client

RESULT

Page 29: FamilySearch Reference Client

RE-USE COMPONENTS

Page 30: FamilySearch Reference Client

FORKFork

create a directory for your components; e.g.,src/common/dqComponents

https://github.com/rootsdev/familysearch-reference-client

Page 31: FamilySearch Reference Client

dqPedigreeMini.jsangular.module('dqPedigreeMini', ['loDash', 'fsReferenceClientShared', 'dqPersonMini' .directive('dqPedigreeMini', function (_, fsApi) { return { templateUrl: 'dqComponents/dqPedigreeMini.tpl.html', scope: { personId: '@' }, controller: function($scope) { fsApi.getAncestry($scope.personId, {generations: 2}).then(function(response) $scope.persons = _.filter(response.getPersons(), function(person) { return person.$getAscendancyNumber() >= 1 && person.$getAscendancyNumber() <= 7; }); }); } }; });

Page 32: FamilySearch Reference Client

dqPedigreeMini.tpl.html<div class="panel panel-info"> <div class="panel-heading"> <h4 class="panel-title">Mini Pedigree</h4> </div> <div class="panel-body dq-pedigree-mini-outer"> <div ng-repeat="person in persons"> <div dq-person-mini person="person" is-focus="{{person.$getAscendancyNumber() == 1}}" class="dq-pedigree-mini-person" ng-class="'dq-pedigree-mini-pos'+person.$getAscendancyNumber()"> </div> </div> </div></div>

Page 33: FamilySearch Reference Client

dqPersonMini.jsangular.module('dqPersonMini', []) .directive('dqPersonMini', function () { return { templateUrl: 'dqComponents/dqPersonMini.tpl.html', scope: { person: '=', isFocus: '@' } }; });

Page 34: FamilySearch Reference Client

dqPersonMini.tpl.htmldiv class="dq-person-mini"> <a href="" fs-person-popover="" person="person" popover-placement="left"> <span class="dq-person-mini-name" ng-style="{'font-weight': isFocus === 'true' ? 'bold' : 'normal', 'color': isFocus === 'true' ? '#333' : '#0051c4'}"> {{person.$getDisplayName()}} </span> </a></div>

Page 35: FamilySearch Reference Client

INJECT INTO PERSON<div class="col-md-3 sidebar"> <div fs-changes-section="" person="person"></div> <div fs-tools-section="" person="person"></div> <div dq-pedigree-mini="" person-id="{{person.id}}"></div></div>

Page 36: FamilySearch Reference Client

THE ENDSlides are at https://github.com/DallanQ/fs-reference-client-

2014-slides