Open-source implementation of the Family Tree UI
Written as a Single-Page Application in Javascript
using the REST API
Install pre-requisites
Get an App Key
Contact FamilySearch developer support if you don't already have one
Ask FamilySearch developer support to add http://localhost:9000/#!/auth as an OAuth redirect URL
Run the code
<head>
</head>
<body>
</body>
angular.module('fsReferenceClient', [ 'fsReferenceClientShared', 'templates-app', 'templates-common', 'ui.bootstrap', 'ui.router.state', 'ui.router'])
.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
};
},
...
});
})
.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;
});
});
angular.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
};
});
});
}]
}
});
})
.controller('PersonController', function ($scope, $state, $rootScope, person, sources, fsApi, fsUtils, fsCurrentUserCache) {
var sections = ['vitalFacts', 'otherInfo', 'familyMembers', 'sources', 'discussions', 'notes' ];
$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 });
$rootScope.$emit('alert', {level: 'success', text: person.$getDisplayName()+' deleted'});
});
});
});
});
angular.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);
}
};
});
{{person.$getDisplayName()}}
{{person.$getDisplayBirthDate()}} -
{{person.$getDisplayDeathDate()}}
{{person.id}}
angular.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;
});
});
}
};
});
Mini Pedigree
<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>
angular.module('dqPersonMini', [])
.directive('dqPersonMini', function () {
return {
templateUrl: 'dqComponents/dqPersonMini.tpl.html',
scope: {
person: '=',
isFocus: '@'
}
};
});
Slides are at https://github.com/DallanQ/fs-reference-client-2014-slides