├── .agignore
├── img
└── scale.png
├── js
├── vendor
│ ├── flat_image_zoom
│ │ ├── .gitignore
│ │ ├── javascripts
│ │ │ ├── images
│ │ │ │ ├── layers.png
│ │ │ │ ├── layers-2x.png
│ │ │ │ ├── marker-icon.png
│ │ │ │ ├── marker-shadow.png
│ │ │ │ └── marker-icon-2x.png
│ │ │ └── jquery.actual.min.js
│ │ ├── README.md
│ │ ├── package.json
│ │ ├── LICENSE.txt
│ │ └── Gruntfile.js
│ ├── angular-segmentio.js
│ ├── Leaflet.fullscreen.min.js
│ ├── angular-route.min.js
│ ├── masonry-horizontal.js
│ ├── imagesloaded.pkgd.min.js
│ ├── angular-touch.min.js.map
│ └── angular-route.min.js.map
├── directives
│ ├── hint.js
│ ├── ngPoster.js
│ ├── recalculateDrawerStates.js
│ ├── videoHandler.js
│ ├── share.js
│ ├── vcenter.js
│ ├── controlPanel.js
│ ├── transparentize.js
│ ├── note.js
│ └── flatmap.js
├── controllers
│ ├── notes.js
│ ├── goldweights.js
│ ├── story.js
│ ├── main.js
│ └── object.js
├── config.js
├── routes.js
├── overscroll.js
├── app.js
├── services
│ └── hintManager.js
├── factories.js
└── adapters.js
├── fonts
└── fontello
│ ├── font
│ ├── griot.eot
│ ├── griot.ttf
│ ├── griot.woff
│ └── griot.svg
│ ├── LICENSE.txt
│ ├── css
│ ├── griot-codes.css
│ ├── animation.css
│ ├── griot-ie7-codes.css
│ ├── griot-ie7.css
│ └── griot.css
│ ├── README.txt
│ ├── config.json
│ └── demo.html
├── humans.txt
├── .gitignore
├── robots.txt
├── sass
├── all.scss
├── drawerify.scss
├── clusters.scss
├── leaflet.scss
├── utils.scss
├── index.scss
├── story.scss
├── object.scss
└── generic.scss
├── _deprecated
├── filters.js
├── onPlay.js
└── scroll.js
├── views
├── annotations.html
├── goldweights.html
├── story.html
├── index.html
└── object.html
├── server
└── email.js
├── README.md
├── package.json
├── LICENSE.md
├── Makefile
├── index.html
├── clusters
├── determine-clusters.js
└── clusters.json
└── css
└── goldweights.css
/.agignore:
--------------------------------------------------------------------------------
1 | **bundle.js
2 | css/bundle.css
3 |
--------------------------------------------------------------------------------
/img/scale.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/artsmia/griot/HEAD/img/scale.png
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/.gitignore:
--------------------------------------------------------------------------------
1 | *~
2 | .sass-cache
3 | build
4 | fonts/*
5 | node_modules
6 |
--------------------------------------------------------------------------------
/fonts/fontello/font/griot.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/artsmia/griot/HEAD/fonts/fontello/font/griot.eot
--------------------------------------------------------------------------------
/fonts/fontello/font/griot.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/artsmia/griot/HEAD/fonts/fontello/font/griot.ttf
--------------------------------------------------------------------------------
/fonts/fontello/font/griot.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/artsmia/griot/HEAD/fonts/fontello/font/griot.woff
--------------------------------------------------------------------------------
/humans.txt:
--------------------------------------------------------------------------------
1 | /* TEAM */
2 |
3 | Name: The Minneapolis Institute of Arts
4 | Site: http://github.com/artsmia
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | fallback/*.json
2 | server/.envrc
3 | node_modules
4 | .DS_Store
5 | .sass-cache
6 | css/style.css.map
7 |
--------------------------------------------------------------------------------
/robots.txt:
--------------------------------------------------------------------------------
1 | # www.robotstxt.org/
2 | # www.google.com/support/webmasters/bin/answer.py?hl=en&answer=156449
3 |
4 | User-agent: *
5 |
--------------------------------------------------------------------------------
/js/directives/hint.js:
--------------------------------------------------------------------------------
1 | app.directive( 'hint', function( $rootScope ) {
2 | return function( scope, elem, attrs ) {
3 | $rootScope.hintSeen = true;
4 | }
5 | });
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/javascripts/images/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/artsmia/griot/HEAD/js/vendor/flat_image_zoom/javascripts/images/layers.png
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/javascripts/images/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/artsmia/griot/HEAD/js/vendor/flat_image_zoom/javascripts/images/layers-2x.png
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/javascripts/images/marker-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/artsmia/griot/HEAD/js/vendor/flat_image_zoom/javascripts/images/marker-icon.png
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/javascripts/images/marker-shadow.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/artsmia/griot/HEAD/js/vendor/flat_image_zoom/javascripts/images/marker-shadow.png
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/javascripts/images/marker-icon-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/artsmia/griot/HEAD/js/vendor/flat_image_zoom/javascripts/images/marker-icon-2x.png
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/README.md:
--------------------------------------------------------------------------------
1 | flat_image_zoom
2 | ================
3 |
4 | Rip the image zooming code from
5 | [walkerart/infolounge_walls](https://github.com/walkerart/infolounge_walls).
6 |
--------------------------------------------------------------------------------
/sass/all.scss:
--------------------------------------------------------------------------------
1 | @import 'utils';
2 | @import 'generic';
3 | @import 'index';
4 | @import 'object';
5 | @import 'story';
6 | @import 'leaflet';
7 | @import 'drawerify';
8 | @import 'clusters';
9 | @import 'loading-animation';
10 |
--------------------------------------------------------------------------------
/_deprecated/filters.js:
--------------------------------------------------------------------------------
1 | app.filter('titleCase', function () {
2 | return function (input) {
3 | var words = input.replace('_', ' ').split(' ');
4 | for (var i = 0; i < words.length; i++) {
5 | words[i] = words[i].charAt(0).toUpperCase() + words[i].slice(1);
6 | }
7 | return words.join(' ');
8 | } // https://gist.github.com/maruf-nc/5625869
9 | });
--------------------------------------------------------------------------------
/js/controllers/notes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Controller for notes template.
3 | */
4 |
5 | app.controller('notesCtrl', ['$scope', '$routeParams', 'notes',
6 | function($scope, $routeParams, wp) {
7 | $scope.id = $routeParams.id
8 | wp().then(function(_wp) {
9 | $scope.notes = _wp.objects[$scope.id].views
10 | $scope.$apply()
11 | })
12 | }
13 | ])
--------------------------------------------------------------------------------
/views/annotations.html:
--------------------------------------------------------------------------------
1 |
'
18 | }, function(err){
19 | if (err) console.error(err);
20 | })
21 |
22 | res.send(req.params)
23 | })
24 |
25 | app.listen(33445)
26 |
--------------------------------------------------------------------------------
/js/directives/videoHandler.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Turn a parent element transparent on touchstart.
3 | */
4 |
5 | app.directive( 'videoHandler', function(){
6 |
7 | return function( scope, elem, attrs ){
8 |
9 | var aspect = $(elem).innerHeight() / $(elem).innerWidth();
10 |
11 | var resize = function(){
12 |
13 | var containerWidth = $(elem).closest('.story-video').innerWidth();
14 |
15 | if( window.outerWidth > 1023 ){
16 | containerWidth -= 140;
17 | }
18 |
19 | $(elem).css({
20 | 'width': containerWidth + 'px',
21 | 'height': Math.round( containerWidth * aspect ) + 'px',
22 | 'max-width': '800px'
23 | });
24 |
25 | }
26 |
27 | resize();
28 |
29 | $(window).on('resize orientationchange', function(){
30 | setTimeout( function(){
31 | resize();
32 | }, 300 );
33 | });
34 |
35 | }
36 |
37 | });
--------------------------------------------------------------------------------
/fonts/fontello/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Font license info
2 |
3 |
4 | ## Typicons
5 |
6 | (c) Stephen Hutchings 2012
7 |
8 | Author: Stephen Hutchings
9 | License: SIL (http://scripts.sil.org/OFL)
10 | Homepage: http://typicons.com/
11 |
12 |
13 | ## MFG Labs
14 |
15 | Copyright (C) 2012 by Daniel Bruce
16 |
17 | Author: MFG Labs
18 | License: SIL (http://scripts.sil.org/OFL)
19 | Homepage: http://www.mfglabs.com/
20 |
21 |
22 | ## Entypo
23 |
24 | Copyright (C) 2012 by Daniel Bruce
25 |
26 | Author: Daniel Bruce
27 | License: SIL (http://scripts.sil.org/OFL)
28 | Homepage: http://www.entypo.com
29 |
30 |
31 | ## Font Awesome
32 |
33 | Copyright (C) 2012 by Dave Gandy
34 |
35 | Author: Dave Gandy
36 | License: SIL ()
37 | Homepage: http://fortawesome.github.com/Font-Awesome/
38 |
39 |
40 |
--------------------------------------------------------------------------------
/js/config.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Configure application.
3 | */
4 |
5 | app.constant('envConfig', {
6 |
7 | // Location of tile server; used in flatmap directive
8 | tilesaw: '//tiles.dx.artsmia.org/',
9 | tileUrlSubdomain: function(tileUrl) {
10 | return tileUrl.replace('http://0.', 'http://{s}.')
11 | },
12 |
13 | // Location of content
14 | crashpad: 'http://new.artsmia.org/crashpad/griot/',
15 |
16 | // CDN for Goldweights audio (specific to MIA implementation)
17 | cdn: 'http://cdn.dx.artsmia.org/',
18 |
19 | miaEmailSharingActive: true,
20 | emailServer: 'http://dx.artsmia.org:33445/',
21 |
22 | // Adapters - set to false to use GriotWP for everything.
23 | miaMediaMetaActive: true,
24 | miaMediaMetaSrc: 'http://cdn.dx.artsmia.org/credits.json',
25 | miaObjectMetaActive: true,
26 | miaObjectMetaSrc: "http://caption-search.dx.artsmia.org/id/",
27 | miaThumbnailActive: true,
28 | miaThumbnailSrc: 'http://cdn.dx.artsmia.org/'
29 |
30 | });
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Griot
2 |
3 | Griot is an open-source iPad application that facilitates engagement with a collection of **objects** (artifacts, artwork, graphs, or anything else that can be represented visually) through **annotations** (points of interest on the object itself) and **stories** (related text-based and multimedia content, presented as a series of pages).
4 |
5 | The Griot framework requires three components:
6 |
7 | 1. The Griot software itself (this);
8 | 2. A server for creating and serving tiled images ([tilesaw][]); and
9 | 3. An interface for loading content and bundling it in JSON format
10 | ([GriotWP][]).
11 |
12 | ## Installation
13 |
14 | 1. Deploy Griot to the directory where you would like it to run.
15 | 2. Edit `js/config.js` to point to your source of image tiles (i.e. your implementation of [tilesaw][]) and application content (i.e. your implementation of [GriotWP][]).
16 |
17 | [tilesaw]: https://github.com/artsmia/tilesaw
18 | [GriotWP]: https://github.com/artsmia/GriotWP
--------------------------------------------------------------------------------
/js/directives/share.js:
--------------------------------------------------------------------------------
1 | app.directive('share', function(email) {
2 | var template = ''
6 |
7 | return {
8 | restrict: 'A',
9 | template: template,
10 | link: function(scope, element, attrs) {
11 | scope.showEmail = false
12 | scope.el = element
13 | var emailI = scope.el.find('input')[0]
14 |
15 | scope.toggleEmail = function(e) {
16 | if((e.toElement || e.target).nodeName == 'A') scope.showEmail = !scope.showEmail
17 | emailI.focus()
18 | }
19 |
20 | scope.sendEmail = function() {
21 | email.share(scope.email, {subject: scope.wp.title, body: window.location.href})
22 | scope.email = ''
23 | scope.showEmail = false
24 | emailI.blur()
25 | }
26 | }
27 | }
28 | })
29 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "griot",
3 | "version": "0.0.0",
4 | "description": "Griot is an open-source iPad application that facilitates engagement with a collection of **objects** (artifacts, artwork, graphs, or anything else that can be represented visually) through **annotations** (points of interest on the object itself) and **stories** (related text-based and multimedia content, presented as a series of pages).",
5 | "main": "js/app.js",
6 | "dependencies": {
7 | "fastclick": "^1.0.6"
8 | },
9 | "devDependencies": {
10 | "onchange": "^0.2.0",
11 | "uglify-js": "^2.4.16",
12 | "browserify": "^8.1.3"
13 | },
14 | "scripts": {
15 | "test": "echo \"Error: no test specified\" && exit 1"
16 | },
17 | "repository": {
18 | "type": "git",
19 | "url": "git://github.com/artsmia/griot.git"
20 | },
21 | "author": "",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/artsmia/griot/issues"
25 | },
26 | "homepage": "https://github.com/artsmia/griot"
27 | }
28 |
--------------------------------------------------------------------------------
/js/directives/vcenter.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Vertically centers an element within a container. Apply 'vcenter' class to
3 | * element to be centered and make sure parent is positioned.
4 | */
5 |
6 | app.directive( 'vcenter', function(){
7 |
8 | return{
9 | restrict: 'C',
10 | transclude: true,
11 | template: "",
12 | link: function( scope, elem, attrs ) {
13 |
14 | scope.container = jQuery( elem );
15 |
16 | if( scope.container.find( 'video' ).length ) {
17 |
18 | var unwatch = scope.$watch(
19 | function(){
20 | return scope.container.height();
21 | },
22 | function(){
23 | setTimeout( function(){
24 | // Use post-transition height (not the one returned by $watch)
25 | var finalHeight = scope.container.height();
26 | scope.container.find( '.vcenter-cell' ).children('video').css( 'max-height', finalHeight );
27 | }, 150 );
28 | }
29 | );
30 |
31 | scope.$on("$destroy", function(){
32 | unwatch();
33 | });
34 |
35 | }
36 | }
37 | }
38 |
39 | });
--------------------------------------------------------------------------------
/sass/leaflet.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Overrides for default Leaflet control-button styles.
3 | */
4 |
5 | .leaflet-top .leaflet-bar{
6 | @include box-shadow(none);
7 | }
8 |
9 | .leaflet-bar a,
10 | .leaflet-bar a:first-child,
11 | .leaflet-bar a:last-child{
12 | @include transition( all 125ms ease );
13 | width:30px;
14 | height:30px;
15 | margin:0;
16 | line-height:26px;
17 | vertical-align:middle;
18 | background-color:rgba(22, 22, 22, .55);
19 | color:#fff;
20 | border:2px solid #fff;
21 | text-indent:-60px;
22 | overflow:hidden;
23 | position:relative;
24 | }
25 | .leaflet-bar a:last-child{
26 | border-width: 0 2px 2px 2px;
27 | }
28 |
29 | .leaflet-bar a.leaflet-control-zoom-in{
30 | @include icon('\e815');
31 | border-top-left-radius:1000px;
32 | border-top-right-radius:1000px;
33 | &:before{
34 | font-size:16px;
35 | margin-top:-8px;
36 | text-indent:0;
37 | }
38 | }
39 |
40 | .leaflet-bar a.leaflet-control-zoom-out{
41 | @include icon('\e816');
42 | border-bottom-left-radius:1000px;
43 | border-bottom-right-radius:1000px;
44 | &:before{
45 | font-size:16px;
46 | margin-top:-8px;
47 | text-indent:0;
48 | }
49 | }
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Walker Art Center
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
21 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 the Minneapolis Institute of Arts
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/javascripts/jquery.actual.min.js:
--------------------------------------------------------------------------------
1 | /*! Copyright 2012, Ben Lin (http://dreamerslab.com/)
2 | * Licensed under the MIT License (LICENSE.txt).
3 | *
4 | * Version: 1.0.14
5 | *
6 | * Requires: jQuery 1.2.3 ~ 1.9.0
7 | */
8 | ;(function(e){e.fn.extend({actual:function(t,n){if(!this[t]){throw'$.actual => The jQuery method "'+t+'" you called does not exist'}var r={absolute:false,clone:false,includeMargin:false};var i=e.extend(r,n);var s=this.eq(0);var o,u;if(i.clone===true){o=function(){var e="position: absolute !important; top: -1000 !important; ";s=s.clone().attr("style",e).appendTo("body")};u=function(){s.remove()}}else{var a=[];var f="";var l;o=function(){if(e.fn.jquery>="1.8.0")l=s.parents().addBack().filter(":hidden");else l=s.parents().andSelf().filter(":hidden");f+="visibility: hidden !important; display: block !important; ";if(i.absolute===true)f+="position: absolute !important; ";l.each(function(){var t=e(this);a.push(t.attr("style"));t.attr("style",f)})};u=function(){l.each(function(t){var n=e(this);var r=a[t];if(r===undefined){n.removeAttr("style")}else{n.attr("style",r)}})}}o();var c=/(outer)/g.test(t)?s[t](i.includeMargin):s[t]();u();return c}})})(jQuery)
--------------------------------------------------------------------------------
/js/directives/controlPanel.js:
--------------------------------------------------------------------------------
1 | app.directive('controlPanel', function() {
2 | return {
3 | restrict: 'E',
4 | replace: true,
5 | controller: function($scope, $element, $attrs) {
6 | console.log('controlPanel', $scope, $element, $attrs)
7 | },
8 | template: ''+
9 | ''+
10 | '
'+
11 | '
Showing objects near Gallery {{gallery}}
'+
12 | '
'+
13 | '
'+
14 | '
'+
15 | '
Showing Museum Highlights
'+
16 | '
'+
17 | '
Explore more ArtStories '+
18 | '
'+
19 | ''+
24 | ' ',
25 | }
26 | })
27 |
28 |
--------------------------------------------------------------------------------
/js/routes.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Application routing
3 | */
4 |
5 | app.config(['$routeProvider', function($routeProvider) {
6 | return $routeProvider.when('/', {
7 | templateUrl: 'views/index.html',
8 | controller: 'mainCtrl',
9 | resolve: { resolvedNotes: function(notes) { return notes() } }
10 | }).when('/clusters/:cluster', { // TODO: can I de-dupe this in angular? `when('/', '/clusters…')`
11 | templateUrl: 'views/index.html',
12 | controller: 'mainCtrl',
13 | resolve: { resolvedNotes: function(notes) { return notes() } }
14 | }).when('/o/:id', {
15 | templateUrl: 'views/object.html',
16 | controller: 'ObjectCtrl',
17 | resolve: {
18 | resolvedNotes: function(notes) { return notes() },
19 | resolvedObjectMeta: function(miaObjectMetaAdapter, $route) {
20 | return miaObjectMetaAdapter.get($route.current.params.id)
21 | }
22 | }
23 | }).when('/a/:id', {
24 | templateUrl: 'views/annotations.html',
25 | controller: 'notesCtrl'
26 | }).when('/stories/:id', {
27 | templateUrl: 'views/story.html',
28 | controller: 'storyCtrl'
29 | }).when('/goldweights', {
30 | templateUrl: 'views/goldweights.html',
31 | controller: 'goldweightsCtrl'
32 | }).otherwise({
33 | redirectTo: '/'
34 | })
35 | }])
36 |
37 |
--------------------------------------------------------------------------------
/_deprecated/scroll.js:
--------------------------------------------------------------------------------
1 | var _requestAF = window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.msRequestAnimationFrame,
2 | _cancelAF = window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.msCancelAnimationFrame
3 |
4 | app.directive("scroll", function ($window) {
5 | return function(scope, element, attrs) {
6 | var e = document.querySelector('#info')
7 | scope._scrollCallback = scope.$eval(attrs['scroll'])
8 | var scrollCallback = function(event) {
9 | if(scope.scrollAnimation) _requestAF(scope.scrollAnimation)
10 | scope.scrollAnimation = _cancelAF(function() {
11 | scope.scrolled = e.scrollTop >= 100
12 | scope.pageXOffset = window.pageXOffset
13 | if(scope._scrollCallback) scope._scrollCallback(element)
14 | scope.$$phase || scope.$apply()
15 | })
16 | },
17 | hooks = 'touchend touchstart touchmove touchleave touchcancel scroll'
18 |
19 | element.bind(hooks, scrollCallback)
20 | if(!scope._scrollCallback) return
21 | // Bug? binding to element doesn't catch horizontal scrolls…
22 | // use window.addEventListener to cover that.
23 | Array.prototype.map.call(hooks.split(' '), function(hook) {
24 | window.addEventListener(hook, scrollCallback)
25 | })
26 | }
27 | })
28 |
29 |
--------------------------------------------------------------------------------
/js/overscroll.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Prevent overscroll on iOS. Adapted from
3 | * http://stackoverflow.com/questions/10238084
4 | */
5 |
6 | var selScrollable = '.scrollable';
7 |
8 | $(document).on('touchmove',function(e){
9 | e.preventDefault();
10 | });
11 |
12 | $('body').on('touchstart', selScrollable, function(e) {
13 |
14 | if (e.currentTarget.scrollTop === 0) {
15 | e.currentTarget.scrollTop = 1;
16 | } else if (e.currentTarget.scrollHeight === e.currentTarget.scrollTop + e.currentTarget.offsetHeight) {
17 | e.currentTarget.scrollTop -= 1;
18 | }
19 |
20 | if( e.currentTarget.scrollLeft === 0) {
21 | e.currentTarget.scrollLeft = 1;
22 | } else if ( e.currentTarget.scrollWidth === e.currentTarget.scrollLeft + e.currentTarget.offsetWidth ) {
23 | e.currentTarget.scrollLeft -= 1;
24 | }
25 | });
26 |
27 | $( 'body' ).on( 'touchmove', selScrollable, function( e ){
28 | // Only block default if internal div contents are large enough to scroll
29 | // Warning: scrollHeight support is not universal. (http://stackoverflow.com/a/15033226/40352)
30 | if( $(this)[0].scrollHeight > $(this).innerHeight() ){
31 | e.stopPropagation();
32 | }
33 |
34 | if( $(this)[0].scrollWidth > $(this).innerWidth() ){
35 | e.stopPropagation();
36 | }
37 | });
38 |
39 | $(window).on('orientationchange', function() {
40 | window.scrollTo(0, 0);
41 | });
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | default: sass browserify
2 |
3 | .PHONY: sass
4 | sass:
5 | onchange css/style.css -- sh -c 'cat fonts/fontello/css/griot-em* css/vendor/leaflet.css css/style.css css/goldweights.css > css/bundle.css' &
6 | sass --watch -t compact sass/all.scss:css/style.css
7 |
8 | browserify:
9 | browserify --full-path=false js/app.js | uglifyjs > js/bundle.js
10 |
11 | build: browserify
12 | ls -S js/vendor/{angular*,isotope*,masonry*}.js | xargs cat | uglifyjs > js/deps.js
13 | cat js/vendor/jquery-2.1.0.min.js js/vendor/flat_image_zoom/javascripts/{leaflet-src.js,flat_image_zoom.js,jquery.actual.min.js} js/overscroll.js | uglifyjs > js/zooming.js
14 | cat fonts/fontello/css/griot-em* css/vendor/leaflet.css css/style.css css/goldweights.css > css/bundle.css
15 |
16 | watchify:
17 | watchify --full-path=false js/app.js -v -o js/bundle.js
18 |
19 | cdnify:
20 | curl -L http://new.artsmia.org/crashpad/json > fallback/crashpad.json
21 | scp fallback/crashpad.json dx:/apps/cdn/crashpad.json
22 | scp fallback/crashpad.json dxt:/apps/cdn/crashpad.json
23 |
24 | images_used: fallback/crashpad.json
25 | cat fallback/crashpad.json | jq '.objects[].views[].image, .stories[].pages[].image, .stories[].pages[].imageB' | uniq | tr -d null | tr -s '\n' | tr -d \"
26 |
27 | all_goldweights_ids: fallback/crashpad.json
28 | cat fallback/crashpad.json | jq '.objects["196"].views[].annotations[].attachments' | json -g | jq '.[]' | sed 's/"//g' | tr -s ' ' | cut -d' ' -f2
29 |
--------------------------------------------------------------------------------
/fonts/fontello/css/griot-codes.css:
--------------------------------------------------------------------------------
1 |
2 | .icon-resize-full:before { content: '\e800'; } /* '' */
3 | .icon-resize-normal:before { content: '\e801'; } /* '' */
4 | .icon-home:before { content: '\e802'; } /* '' */
5 | .icon-menu:before { content: '\e803'; } /* '' */
6 | .icon-left-open:before { content: '\e804'; } /* '' */
7 | .icon-right-open:before { content: '\e805'; } /* '' */
8 | .icon-left:before { content: '\e806'; } /* '' */
9 | .icon-right:before { content: '\e807'; } /* '' */
10 | .icon-left-small:before { content: '\e808'; } /* '' */
11 | .icon-right-small:before { content: '\e809'; } /* '' */
12 | .icon-play:before { content: '\e80a'; } /* '' */
13 | .icon-info-circled:before { content: '\e80b'; } /* '' */
14 | .icon-info-circled-alt:before { content: '\e80c'; } /* '' */
15 | .icon-cancel-circled:before { content: '\e80d'; } /* '' */
16 | .icon-cancel-circled-outline:before { content: '\e80e'; } /* '' */
17 | .icon-cancel:before { content: '\e80f'; } /* '' */
18 | .icon-cancel-outline:before { content: '\e810'; } /* '' */
19 | .icon-pause:before { content: '\e811'; } /* '' */
20 | .icon-back:before { content: '\e812'; } /* '' */
21 | .icon-info:before { content: '\e813'; } /* '' */
22 | .icon-doc-text:before { content: '\e814'; } /* '' */
23 | .icon-plus:before { content: '\e815'; } /* '' */
24 | .icon-minus:before { content: '\e816'; } /* '' */
25 | .icon-resize-vertical:before { content: '\e817'; } /* '' */
26 | .icon-mail:before { content: '\e818'; } /* '' */
--------------------------------------------------------------------------------
/js/directives/transparentize.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Turn a parent element transparent on touchstart.
3 | */
4 |
5 | app.directive( 'transparentize', function($timeout){
6 |
7 | return {
8 | restrict:'A',
9 | require:'^?drawerify',
10 | link: function( scope, elem, attrs, drawerify ) {
11 |
12 | var $target = jQuery( attrs.transparentize );
13 |
14 | elem.on( 'touchstart mousedown', function(){
15 | if( attrs.hasOwnProperty( 'transparentizeAction' ) ){
16 | switch( attrs.transparentizeAction ){
17 |
18 | case 'playVideo':
19 | // Close drawer in case we're not on a device that automatically
20 | // full-screens the video
21 | if( drawerify ){
22 | drawerify.to('closed');
23 | $timeout( function(){
24 | var $video = $('video[src="' + scope.page.video + '"]');
25 | $video[0].play();
26 | }, 150 );
27 | }
28 | else {
29 | var $video = $('video[src="' + scope.page.video + '"]');
30 | $video[0].play();
31 | }
32 | break;
33 |
34 |
35 | default:
36 | $target.addClass('transparentized');
37 | }
38 | }
39 | else {
40 | $target.addClass('transparentized');
41 | }
42 | });
43 |
44 | elem.on( 'touchend mouseup', function(e){
45 | $target.addClass('detransparentized');
46 | $target.removeClass('transparentized');
47 | $timeout(function() {
48 | $target.removeClass('detransparentized');
49 | }, 300)
50 | });
51 |
52 | }
53 | }
54 |
55 | });
56 |
--------------------------------------------------------------------------------
/views/goldweights.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | {{att.meta1}}
27 |
28 |
29 |
30 |
31 |
32 | Goldweights
33 |
34 |
35 |
36 |
37 |
38 |
Tap on a goldweight to learn more.
39 |
Proverbs spoken by Fred Adiyia.
40 |
41 |
42 |
--------------------------------------------------------------------------------
/js/app.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Set up application and load modules.
3 | */
4 | var fastclick = require('fastclick')
5 |
6 | /*jshint asi: true*/
7 | 'use strict';
8 |
9 | window.app = angular.module('griot', ['ngRoute', 'segmentio']);
10 |
11 | app.run(function() { fastclick(document.body) })
12 |
13 | require('./routes')
14 |
15 | require('./services/hintManager')
16 |
17 | require('./config')
18 |
19 | app.config(
20 | ['$httpProvider', function($httpProvider) {
21 | return delete $httpProvider.defaults.headers.common['X-Requested-With'];
22 | }]
23 | )
24 |
25 | app.run(['$rootScope', 'envConfig', 'miaMediaMetaAdapter', 'miaObjectMetaAdapter', 'miaThumbnailAdapter', '$location', 'hintManager', function( root, config, mediaMeta, objectMeta, objectThumb, $location, hintManager ) {
26 | root.cdn = config.cdn;
27 | var query = $location.search();
28 |
29 | // If adapters are enabled, retrieve and prepare alternate data
30 | if( config.miaMediaMetaActive ) {
31 | mediaMeta.build( config.miaMediaMetaSrc );
32 | }
33 | if( config.miaThumbnailActive ) {
34 | objectThumb.init( config.miaThumbnailSrc );
35 | }
36 |
37 | // hintManager.init();
38 | // Temporarily disable 'pinch to zoom' hints.
39 |
40 | }])
41 |
42 | require('./factories')
43 | require('./adapters')
44 |
45 | require('./controllers/object')
46 | require('./controllers/story')
47 | require('./controllers/notes')
48 | require('./controllers/main')
49 | require('./controllers/goldweights')
50 |
51 | require('./directives/flatmap')
52 | require('./directives/note')
53 | require('./directives/vcenter')
54 | require('./directives/ngPoster')
55 | require('./directives/transparentize')
56 | require('./directives/drawerify')
57 | require('./directives/recalculateDrawerStates')
58 | require('./directives/share')
59 | require('./directives/videoHandler')
60 | require('./directives/hint')
61 | require('./directives/controlPanel')
62 |
--------------------------------------------------------------------------------
/js/services/hintManager.js:
--------------------------------------------------------------------------------
1 | app.service( 'hintManager', function( $location, $timeout, $rootScope ) {
2 |
3 | var _this = this;
4 |
5 | // Wait this number of seconds after last touch before displaying hints again
6 | this.delay = 60;
7 |
8 | // Has a hint been seen by the user yet?
9 | $rootScope.hintSeen = false;
10 |
11 | this.init = function(){
12 |
13 | // Start with hints off
14 | $rootScope.showHints = false;
15 |
16 | // Has the user seen a hint yet?
17 | $rootScope.hintSeen = false;
18 |
19 | var query = $location.search();
20 |
21 | // Directs app to refresh hints after a minute of inactivity.
22 | $rootScope.hosted = query.hasOwnProperty( 'hosted' ) && query.hosted === 'true';
23 |
24 | // Forces app to assume browser has touch events enabled.
25 | if( query.hasOwnProperty( 'touch' ) && query.touch === 'true' ){
26 | this.setTouch();
27 | } else {
28 | $rootScope.touch = false;
29 | }
30 |
31 | // If we aren't explicitly told that this screen is touchable, listen for
32 | // a touch event and activate hints if one is heard.
33 | if( ! $rootScope.touch ){
34 | $(window).on( 'touchstart', _this.setTouch );
35 | }
36 | }
37 |
38 | // Sets touch to true, and removes the listener on window if applicable
39 | this.setTouch = function(){
40 | $timeout( function(){
41 | $rootScope.touch = true;
42 | $rootScope.showHints = true;
43 | $(window).off( 'touchstart', _this.setTouch );
44 | if( $rootScope.hosted ){
45 | $(window).on( 'touchend', function(){
46 | _this.resetTimer( _this.delay );
47 | });
48 | }
49 | });
50 | }
51 |
52 | this.resetTimer = function( delay ){
53 |
54 | // Clear timer if it exists
55 | if( _this.hasOwnProperty( 'hintTimer' ) ){
56 | $timeout.cancel( _this.hintTimer );
57 | }
58 | // Set new timer
59 | _this.hintTimer = $timeout( function(){
60 | if( $rootScope.touch ){
61 | $rootScope.showHints = true;
62 | }
63 | }, delay * 1000 );
64 | }
65 |
66 | $rootScope.$on( 'zoom', function(){
67 | if( $rootScope.hintSeen ){
68 | $timeout( function(){
69 | $rootScope.showHints = false;
70 | });
71 | }
72 | });
73 |
74 | });
--------------------------------------------------------------------------------
/fonts/fontello/css/animation.css:
--------------------------------------------------------------------------------
1 | /*
2 | Animation example, for spinners
3 | */
4 | .animate-spin {
5 | -moz-animation: spin 2s infinite linear;
6 | -o-animation: spin 2s infinite linear;
7 | -webkit-animation: spin 2s infinite linear;
8 | animation: spin 2s infinite linear;
9 | display: inline-block;
10 | }
11 | @-moz-keyframes spin {
12 | 0% {
13 | -moz-transform: rotate(0deg);
14 | -o-transform: rotate(0deg);
15 | -webkit-transform: rotate(0deg);
16 | transform: rotate(0deg);
17 | }
18 |
19 | 100% {
20 | -moz-transform: rotate(359deg);
21 | -o-transform: rotate(359deg);
22 | -webkit-transform: rotate(359deg);
23 | transform: rotate(359deg);
24 | }
25 | }
26 | @-webkit-keyframes spin {
27 | 0% {
28 | -moz-transform: rotate(0deg);
29 | -o-transform: rotate(0deg);
30 | -webkit-transform: rotate(0deg);
31 | transform: rotate(0deg);
32 | }
33 |
34 | 100% {
35 | -moz-transform: rotate(359deg);
36 | -o-transform: rotate(359deg);
37 | -webkit-transform: rotate(359deg);
38 | transform: rotate(359deg);
39 | }
40 | }
41 | @-o-keyframes spin {
42 | 0% {
43 | -moz-transform: rotate(0deg);
44 | -o-transform: rotate(0deg);
45 | -webkit-transform: rotate(0deg);
46 | transform: rotate(0deg);
47 | }
48 |
49 | 100% {
50 | -moz-transform: rotate(359deg);
51 | -o-transform: rotate(359deg);
52 | -webkit-transform: rotate(359deg);
53 | transform: rotate(359deg);
54 | }
55 | }
56 | @-ms-keyframes spin {
57 | 0% {
58 | -moz-transform: rotate(0deg);
59 | -o-transform: rotate(0deg);
60 | -webkit-transform: rotate(0deg);
61 | transform: rotate(0deg);
62 | }
63 |
64 | 100% {
65 | -moz-transform: rotate(359deg);
66 | -o-transform: rotate(359deg);
67 | -webkit-transform: rotate(359deg);
68 | transform: rotate(359deg);
69 | }
70 | }
71 | @keyframes spin {
72 | 0% {
73 | -moz-transform: rotate(0deg);
74 | -o-transform: rotate(0deg);
75 | -webkit-transform: rotate(0deg);
76 | transform: rotate(0deg);
77 | }
78 |
79 | 100% {
80 | -moz-transform: rotate(359deg);
81 | -o-transform: rotate(359deg);
82 | -webkit-transform: rotate(359deg);
83 | transform: rotate(359deg);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/js/vendor/flat_image_zoom/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | // Project configuration.
4 | grunt.initConfig({
5 | pkg: grunt.file.readJSON('package.json'),
6 |
7 | concat: {
8 | options: {
9 | // define a string to put between each file in the concatenated output
10 | separator: ';'
11 | },
12 | dist: {
13 | // the files to concatenate
14 | //src: ['javascripts/*.js'],
15 |
16 | src: [
17 | 'javascripts/jquery-2.0.1.min.js',
18 | 'javascripts/underscore-min.js',
19 | 'javascripts/leaflet-src.js',
20 | 'javascripts/zoom_swipe.js',
21 | 'javascripts/jquery.actual.min.js',
22 | 'javascripts/flat_image_zoom.js',
23 | ],
24 | // the location of the resulting JS file
25 | dest: 'build/<%= pkg.name %>.js'
26 | }
27 | },
28 |
29 | jshint: {
30 | options: {
31 | curly: true,
32 | eqeqeq: true,
33 | eqnull: true,
34 | browser: true,
35 | globals: {
36 | jQuery: true
37 | },
38 | },
39 |
40 | files: {
41 | src: [ ]
42 | }
43 | },
44 |
45 | uglify: {
46 | options: {
47 | // the banner is inserted at the top of the output
48 | banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n',
49 | //report : 'gzip',
50 | // to help optimize the varibale names and stuff like that
51 | //compress : true
52 | },
53 | dist: {
54 | files: {
55 | 'build/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
56 | }
57 | }
58 | },
59 |
60 | watch: {
61 | files: ['javascripts/*.js'],
62 | tasks: ['concat', 'uglify'],
63 | }
64 |
65 | });
66 |
67 | grunt.loadNpmTasks('grunt-contrib-uglify');
68 | grunt.loadNpmTasks('grunt-contrib-concat');
69 | grunt.loadNpmTasks('grunt-contrib-jshint');
70 | grunt.loadNpmTasks('grunt-contrib-qunit');
71 | grunt.loadNpmTasks('grunt-contrib-watch');
72 | grunt.loadNpmTasks('grunt-sass');
73 | grunt.loadNpmTasks('grunt-contrib-compass');
74 |
75 | // Default task(s).
76 | grunt.registerTask('default', ['concat', 'uglify']);
77 | };
78 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | MIA ArtStories
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
34 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/sass/utils.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Media queries, vendor prefixes, and base styles for frequently used elements.
3 | */
4 |
5 | $smallPortrait:'screen and (orientation:portrait) and (max-width:640px)';
6 | $small:'screen and (min-width:641px), screen and (orientation:landscape)';
7 | $medium:'screen and (min-width:1024px)';
8 |
9 | @mixin box-sizing( $params ) {
10 | -webkit-box-sizing:$params;
11 | -moz-box-sizing:$params;
12 | box-sizing:$params;
13 | }
14 | @mixin box-shadow( $params... ) {
15 | -webkit-box-shadow:$params;
16 | -moz-box-shadow:$params;
17 | box-shadow:$params;
18 | }
19 | @mixin transition( $params... ) {
20 | -webkit-transition: $params;
21 | -moz-transition: $params;
22 | -o-transition: $params;
23 | }
24 | @mixin transform( $params ) {
25 | -webkit-transform:$params;
26 | -moz-transform:$params;
27 | -o-transform:$params;
28 | -ms-transform:$params;
29 | transform:$params;
30 | }
31 | @mixin transform-origin( $params ) {
32 | -webkit-transform-origin:$params;
33 | -moz-transform-origin:$params;
34 | -o-transform-origin:$params;
35 | -ms-transform-origin:$params;
36 | transform-origin:$params;
37 | }
38 | @mixin no-select {
39 | -webkit-touch-callout: none;
40 | -webkit-user-select: none;
41 | -khtml-user-select: none;
42 | -moz-user-select: none;
43 | -ms-user-select: none;
44 | user-select: none;
45 | }
46 | @mixin label{
47 | color:#222;
48 | font-size:0.8em;
49 | font-family:'MiaGrotesk-Light', sans-serif;
50 | text-align:center;
51 | text-transform:uppercase;
52 | }
53 | @mixin meta{
54 | color:#888;
55 | font-size:0.9em;
56 | font-family:'MiaGrotesk-Light', sans-serif;
57 | font-style:italic;
58 | }
59 | @mixin icon( $content ){
60 | font-style:normal;
61 | cursor:pointer;
62 | -webkit-tap-highlight-color: transparent;
63 |
64 | &:before{
65 | position:absolute;
66 | display:block;
67 | top:50%;
68 | width:100%;
69 | text-align:center;
70 | line-height:100%;
71 | font-family:'griot';
72 | content: $content;
73 |
74 | // -- rev -- //
75 | //font-size:24px;
76 | //margin-top:-12px;
77 | left:0;
78 | }
79 | }
80 | @mixin truncate {
81 | width: 100%;
82 | white-space: nowrap;
83 | overflow: hidden;
84 | text-overflow: ellipsis;
85 | }
86 | .transparentized{
87 | @include transition( opacity 300ms ease-out );
88 | opacity: 0 !important;
89 | }
90 | .detransparentized {
91 | @include transition( opacity 150ms ease-in );
92 | }
93 |
--------------------------------------------------------------------------------
/js/vendor/angular-segmentio.js:
--------------------------------------------------------------------------------
1 | angular.module('segmentio', ['ng'])
2 | .factory('segmentio', ['$rootScope', '$window', '$location', '$log', function ($rootScope, $window, $location, $log) {
3 | var service = {};
4 |
5 | $window.analytics = $window.analytics || [];
6 |
7 | // Define a factory that generates wrapper methods to push arrays of
8 | // arguments onto our `analytics` queue, where the first element of the arrays
9 | // is always the name of the analytics.js method itself (eg. `track`).
10 | var methodFactory = function (type) {
11 | return function () {
12 | var args = Array.prototype.slice.call(arguments, 0);
13 | if(analytics.initialized) {
14 | $window.analytics[type].apply($window.analytics, args);
15 | }
16 | else {
17 | $window.analytics.push([type].concat(args));
18 | }
19 | };
20 | };
21 |
22 | // Loop through analytics.js' methods and generate a wrapper method for each.
23 | var methods = ['identify', 'track', 'trackLink', 'trackForm', 'trackClick',
24 | 'trackSubmit', 'pageview', 'ab', 'alias', 'ready', 'group'];
25 | for (var i = 0; i < methods.length; i++) {
26 | service[methods[i]] = methodFactory(methods[i]);
27 | }
28 |
29 | // Listening to $viewContentLoaded event to track pageview
30 | $rootScope.$on('$viewContentLoaded', function () {
31 | service.pageview($location.path());
32 | });
33 |
34 | /**
35 | * @description
36 | * Load Segment.io analytics script
37 | * @param apiKey The key API to use
38 | */
39 | service.load = function(apiKey) {
40 | // Create an async script element for analytics.js.
41 | var script = document.createElement('script');
42 | script.type = 'text/javascript';
43 | script.async = true;
44 | script.src = ('https:' === document.location.protocol ? 'https://' : 'http://') +
45 | 'd2dq2ahtl5zl1z.cloudfront.net/analytics.js/v1/' + apiKey + '/analytics.js';
46 |
47 | // Find the first script element on the page and insert our script next to it.
48 | var firstScript = document.getElementsByTagName('script')[0];
49 | firstScript.parentNode.insertBefore(script, firstScript);
50 | };
51 |
52 | return service;
53 | }]);
--------------------------------------------------------------------------------
/clusters/determine-clusters.js:
--------------------------------------------------------------------------------
1 | // http://caption-search.dx.artsmia.org/ids/45269,4866,1312,108767,113136,111099,97,111879,1854,12111,1937,3778,115514,115320,1358,111088,114833,111893,12092,376,105014,117153,3520,91467,7505,5788,4324,114429,118304,116725,108860,60728,4379,1380,4829,22412,107241,116294,113926,1704,1721,2210,2606,537,1218,1978,4418,10436,529,109122,278,1270,1348,1727,1355,115836,1411,1244,1748,8023,1226,119599,115352,113568,1637,1629,116116,98653,114514,109112,43877
2 | var objects = require("./objects.json")
3 | var locations = "G200 G219 G223 G230 G258 G260 G261 G321 G340 G350 G363 G374 G375 G379 G236 G250 G254".split(' ')
4 |
5 | objectLocations = objects.map(function(o) { return o.room })
6 |
7 | // console.log('cube locations', locations)
8 | // console.log('object locations', objectLocations)
9 |
10 | var groups = {}
11 | var id = function(o) { return o.id }
12 |
13 | // How to group the artstories??
14 | // Location-wise I want to do it by the gallery number.
15 | // So first, 'Not on View'
16 |
17 | groups.offView = objects.filter(function(o) { return o.room == 'Not on View' }).map(id)
18 |
19 | // The simplest possible grouping now is by floor…
20 |
21 | groups.floor1 = objects.filter(function(o) { return o.room.match(/^G1/) }).map(id)
22 | groups.floor2 = objects.filter(function(o) { return o.room.match(/^G2/) }).map(id)
23 | groups.floor3 = objects.filter(function(o) { return o.room.match(/^G3/) }).map(id)
24 |
25 | // I want to group them according to the closest gallery-located iPads
26 | // `locations`
27 |
28 | function galleryDistance(a, b) {
29 | if(a == 'Not on View' || b == 'Not on View') return 1000
30 | a = parseInt(a.replace('G', ''))
31 | b = parseInt(b.replace('G', ''))
32 | return Math.abs(a-b);
33 | }
34 |
35 | function findClusters(object, threshold) {
36 | var objectLocation = object.room
37 | // How far is it to the existing clusters?
38 | var clusterDistances = locations.map(function(clusterLocation) {
39 | return galleryDistance(objectLocation, clusterLocation)
40 | })
41 | return clusterDistances.map(function(d, i) {
42 | if(d <= threshold) return locations[i]
43 | }).filter(function(cluster) { return cluster })
44 | }
45 |
46 | var clusters = locations.reduce(function(clusters, location) {
47 | clusters[location] = []
48 | return clusters
49 | }, {})
50 |
51 | // find the 'nearest' clusters for each object
52 | objects.map(function(o) {
53 | findClusters(o, 25).map(function(cluster) {
54 | clusters[cluster].push(o.id)
55 | })
56 | })
57 |
58 | // TODO: sort objects in clusters by lowest distance
59 |
60 | clusters.offView = groups.offView
61 |
62 | console.log(JSON.stringify(clusters))
63 |
--------------------------------------------------------------------------------
/fonts/fontello/css/griot-ie7-codes.css:
--------------------------------------------------------------------------------
1 |
2 | .icon-resize-full { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
3 | .icon-resize-normal { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
4 | .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
5 | .icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
6 | .icon-left-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
7 | .icon-right-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
8 | .icon-left { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
9 | .icon-right { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
10 | .icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
11 | .icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
12 | .icon-play { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
13 | .icon-info-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
14 | .icon-info-circled-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
15 | .icon-cancel-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
16 | .icon-cancel-circled-outline { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
17 | .icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
18 | .icon-cancel-outline { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
19 | .icon-pause { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
20 | .icon-back { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
21 | .icon-info { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
22 | .icon-doc-text { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
23 | .icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
24 | .icon-minus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
25 | .icon-resize-vertical { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
26 | .icon-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
--------------------------------------------------------------------------------
/js/vendor/Leaflet.fullscreen.min.js:
--------------------------------------------------------------------------------
1 | L.Control.Fullscreen=L.Control.extend({options:{position:"topleft",title:{"false":"View Fullscreen","true":"Exit Fullscreen"}},onAdd:function(map){var container=L.DomUtil.create("div","leaflet-control-fullscreen leaflet-bar leaflet-control");this.link=L.DomUtil.create("a","leaflet-control-fullscreen-button leaflet-bar-part",container);this.link.href="#";this._map=map;this._map.on("fullscreenchange",this._toggleTitle,this);this._toggleTitle();L.DomEvent.on(this.link,"click",this._click,this);return container},_click:function(e){L.DomEvent.stopPropagation(e);L.DomEvent.preventDefault(e);this._map.toggleFullscreen()},_toggleTitle:function(){this.link.title=this.options.title[this._map.isFullscreen()]}});L.Map.include({isFullscreen:function(){return this._isFullscreen||false},toggleFullscreen:function(){var container=this.getContainer();if(this.isFullscreen()){if(document.exitFullscreen){document.exitFullscreen()}else if(document.mozCancelFullScreen){document.mozCancelFullScreen()}else if(document.webkitCancelFullScreen){document.webkitCancelFullScreen()}else{L.DomUtil.removeClass(container,"leaflet-pseudo-fullscreen");this._toggleFullscreenClass();this.invalidateSize();this._isFullscreen=false;this.fire("fullscreenchange")}}else{if(container.requestFullscreen){container.requestFullscreen()}else if(container.mozRequestFullScreen){container.mozRequestFullScreen()}else if(container.webkitRequestFullscreen){container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}else{L.DomUtil.addClass(container,"leaflet-pseudo-fullscreen");this._toggleFullscreenClass();this.invalidateSize();this._isFullscreen=true;this.fire("fullscreenchange")}}},_toggleFullscreenClass:function(){var container=this.getContainer();if(this.isFullscreen()){L.DomUtil.removeClass(container,"leaflet-fullscreen-on")}else{L.DomUtil.addClass(container,"leaflet-fullscreen-on")}},_onFullscreenChange:function(){var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement;this._toggleFullscreenClass();if(fullscreenElement===this.getContainer()){this._isFullscreen=true;this.fire("fullscreenchange")}else if(this._isFullscreen){this._isFullscreen=false;this.fire("fullscreenchange")}}});L.Map.mergeOptions({fullscreenControl:false});L.Map.addInitHook(function(){if(this.options.fullscreenControl){this.fullscreenControl=new L.Control.Fullscreen;this.addControl(this.fullscreenControl)}var fullscreenchange;if("onfullscreenchange"in document){fullscreenchange="fullscreenchange"}else if("onmozfullscreenchange"in document){fullscreenchange="mozfullscreenchange"}else if("onwebkitfullscreenchange"in document){fullscreenchange="webkitfullscreenchange"}if(fullscreenchange){this.whenReady(function(){L.DomEvent.on(document,fullscreenchange,this._onFullscreenChange,this)});this.on("unload",function(){L.DomEvent.off(document,fullscreenchange,this._onFullscreenChange)})}});L.control.fullscreen=function(options){return new L.Control.Fullscreen(options)};
--------------------------------------------------------------------------------
/js/controllers/goldweights.js:
--------------------------------------------------------------------------------
1 | app.controller('goldweightsCtrl', ['$scope', '$sce', 'segmentio', 'notes', 'miaObjectMetaAdapter', 'miaThumbnailAdapter', function($scope, $sce, segmentio, wp, objectMeta, objectThumb ) {
2 | wp().then(function(wordpress) {
3 | window.$scope = $scope
4 | Zoomer.windowResized()
5 | $scope.goldweights = wordpress.objects['196']
6 | $scope.goldweights.trustedDescription = $sce.trustAsHtml( $scope.goldweights.description );
7 | $scope.showDescription = true
8 |
9 | var loadNotes = function() {
10 | $scope.notes = $scope.goldweights.views
11 | angular.forEach($scope.notes, function(view) {
12 | angular.forEach(view.annotations, function(ann) {
13 | var proverbLinkPattern = /\n?\[(PR\d+)\]<\/p>/, match = ann.description.match(proverbLinkPattern), proverbId = match && match[1]
14 | ann.proverb = proverbId
15 | ann.trustedAudio = $sce.trustAsResourceUrl($scope.cdn+'goldweights/'+proverbId+'.mp3')
16 | ann.trustedDescription = $sce.trustAsHtml(ann.description.replace(proverbLinkPattern, ''))
17 | angular.forEach(ann.attachments, function(att) {
18 | var mash = att.image_id.split(' ');
19 | att.image_id = mash[0];
20 | att.object_id = mash[1];
21 | att.meta1 = att.metaG = '';
22 | if( objectMeta.isActive ) { // Let's hope it is, because this data does not exist elsewhere
23 | att.title = objectMeta.get( att.object_id, 'gw_title' );
24 | att.meta1 = objectMeta.get( att.object_id, 'meta1' );
25 | att.meta2 = objectMeta.get( att.object_id, 'gw_meta2' );
26 | }
27 | if( objectThumb.isActive ) {
28 | att.thumb = objectThumb.get( att.image_id );
29 | }
30 | })
31 | })
32 | })
33 | $scope.$$phase || $scope.$apply()
34 | }
35 | $scope.$on('viewChanged', loadNotes)
36 | if($scope.mapLoaded) loadNotes()
37 | })
38 |
39 | $scope.play = function(scope, $event) {
40 | $('audio').each(function() { this.pause() })
41 | var audio = $event.target.querySelector('audio')
42 | audio.paused ? audio.play() : audio.pause()
43 | scope.playing = !audio.paused
44 | audio.addEventListener('ended', function() {
45 | scope.playing = false
46 | scope.$apply()
47 | })
48 | }
49 |
50 | $scope.toggle = function(scope) {
51 | $scope.popupWeight = ($scope.popupWeight == scope ? undefined : scope)
52 | }
53 |
54 | $scope.toggleInfo = function(scope) {
55 | $scope.showInfo = !$scope.showInfo
56 | }
57 |
58 | if(window.location.href.match(/west/)) {
59 | $('body').addClass('west')
60 | setTimeout(function() {
61 | window.scrollTo(0, document.body.scrollHeight)
62 | }, 1000)
63 | }
64 |
65 | $scope.home = function() {
66 | angular.forEach($scope.notes[0].annotations, function(note) { note.active = false })
67 | $scope.$$phase || $scope.$apply()
68 | }
69 |
70 | }])
--------------------------------------------------------------------------------
/fonts/fontello/css/griot-ie7.css:
--------------------------------------------------------------------------------
1 | [class^="icon-"], [class*=" icon-"] {
2 | font-family: 'griot';
3 | font-style: normal;
4 | font-weight: normal;
5 |
6 | /* fix buttons height */
7 | line-height: 1em;
8 |
9 | /* you can be more comfortable with increased icons size */
10 | /* font-size: 120%; */
11 | }
12 |
13 | .icon-resize-full { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
14 | .icon-resize-normal { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
15 | .icon-home { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
16 | .icon-menu { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
17 | .icon-left-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
18 | .icon-right-open { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
19 | .icon-left { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
20 | .icon-right { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
21 | .icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
22 | .icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
23 | .icon-play { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
24 | .icon-info-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
25 | .icon-info-circled-alt { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
26 | .icon-cancel-circled { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
27 | .icon-cancel-circled-outline { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
28 | .icon-cancel { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
29 | .icon-cancel-outline { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
30 | .icon-pause { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
31 | .icon-back { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
32 | .icon-info { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
33 | .icon-doc-text { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
34 | .icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
35 | .icon-minus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
36 | .icon-resize-vertical { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
37 | .icon-mail { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
--------------------------------------------------------------------------------
/fonts/fontello/README.txt:
--------------------------------------------------------------------------------
1 | This webfont is generated by http://fontello.com open source project.
2 |
3 |
4 | ================================================================================
5 | Please, note, that you should obey original font licences, used to make this
6 | webfont pack. Details available in LICENSE.txt file.
7 |
8 | - Usually, it's enough to publish content of LICENSE.txt file somewhere on your
9 | site in "About" section.
10 |
11 | - If your project is open-source, usually, it will be ok to make LICENSE.txt
12 | file publically available in your repository.
13 |
14 | - Fonts, used in Fontello, don't require to make clickable links on your site.
15 | But any kind of additional authors crediting is welcome.
16 | ================================================================================
17 |
18 |
19 | Comments on archive content
20 | ---------------------------
21 |
22 | - /font/* - fonts in different formats
23 |
24 | - /css/* - different kinds of css, for all situations. Should be ok with
25 | twitter bootstrap. Also, you can skip style and assign icon classes
26 | directly to text elements, if you don't mind about IE7.
27 |
28 | - demo.html - demo file, to show your webfont content
29 |
30 | - LICENSE.txt - license info about source fonts, used to build your one.
31 |
32 | - config.json - keeps your settings. You can import it back to fontello anytime,
33 | to continue your work
34 |
35 |
36 | Why so many CSS files ?
37 | -----------------------
38 |
39 | Because we like to fit all your needs :)
40 |
41 | - basic file, .css - is usually enougth, in contains @font-face
42 | and character codes definition
43 |
44 | - *-ie7.css - if you need IE7 support, but still don't wish to put char codes
45 | directly into html
46 |
47 | - *-codes.css and *-ie7-codes.css - if you like to use your own @font-face
48 | rules, but still wish to benefit of css generation. That can be very
49 | convenient for automated assets build systems. When you need to update font -
50 | no needs to manually edit files, just override old version with archive
51 | content. See fontello source codes for example.
52 |
53 | - *-embedded.css - basic css file, but with embedded WOFF font, to avoid
54 | CORS issues in Firefox and IE9+, when fonts are hosted on the separate domain.
55 | We strongly recommend to resolve this issue by `Access-Control-Allow-Origin`
56 | server headers. But if you ok with dirty hack - this file is for you. Note,
57 | that data url moved to separate @font-face to avoid problems with
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
37 |
38 |
39 |
{{page.glanceText}}
40 |
41 |
42 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/views/index.html:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 | ArtStories: Spotlight on the Collection
43 | Slide to browse, tap to view
44 |
45 |
46 |
53 |
--------------------------------------------------------------------------------
/js/vendor/angular-route.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | AngularJS v1.2.15
3 | (c) 2010-2014 Google, Inc. http://angularjs.org
4 | License: MIT
5 | */
6 | (function(n,e,A){'use strict';function x(s,g,k){return{restrict:"ECA",terminal:!0,priority:400,transclude:"element",link:function(a,c,b,f,w){function y(){p&&(p.remove(),p=null);h&&(h.$destroy(),h=null);l&&(k.leave(l,function(){p=null}),p=l,l=null)}function v(){var b=s.current&&s.current.locals;if(e.isDefined(b&&b.$template)){var b=a.$new(),d=s.current;l=w(b,function(d){k.enter(d,null,l||c,function(){!e.isDefined(t)||t&&!a.$eval(t)||g()});y()});h=d.scope=b;h.$emit("$viewContentLoaded");h.$eval(u)}else y()}
7 | var h,l,p,t=b.autoscroll,u=b.onload||"";a.$on("$routeChangeSuccess",v);v()}}}function z(e,g,k){return{restrict:"ECA",priority:-400,link:function(a,c){var b=k.current,f=b.locals;c.html(f.$template);var w=e(c.contents());b.controller&&(f.$scope=a,f=g(b.controller,f),b.controllerAs&&(a[b.controllerAs]=f),c.data("$ngControllerController",f),c.children().data("$ngControllerController",f));w(a)}}}n=e.module("ngRoute",["ng"]).provider("$route",function(){function s(a,c){return e.extend(new (e.extend(function(){},
8 | {prototype:a})),c)}function g(a,e){var b=e.caseInsensitiveMatch,f={originalPath:a,regexp:a},k=f.keys=[];a=a.replace(/([().])/g,"\\$1").replace(/(\/)?:(\w+)([\?\*])?/g,function(a,e,b,c){a="?"===c?c:null;c="*"===c?c:null;k.push({name:b,optional:!!a});e=e||"";return""+(a?"":e)+"(?:"+(a?e:"")+(c&&"(.+?)"||"([^/]+)")+(a||"")+")"+(a||"")}).replace(/([\/$\*])/g,"\\$1");f.regexp=RegExp("^"+a+"$",b?"i":"");return f}var k={};this.when=function(a,c){k[a]=e.extend({reloadOnSearch:!0},c,a&&g(a,c));if(a){var b=
9 | "/"==a[a.length-1]?a.substr(0,a.length-1):a+"/";k[b]=e.extend({redirectTo:a},g(b,c))}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce",function(a,c,b,f,g,n,v,h){function l(){var d=p(),m=r.current;if(d&&m&&d.$$route===m.$$route&&e.equals(d.pathParams,m.pathParams)&&!d.reloadOnSearch&&!u)m.params=d.params,e.copy(m.params,b),a.$broadcast("$routeUpdate",m);else if(d||m)u=!1,a.$broadcast("$routeChangeStart",
10 | d,m),(r.current=d)&&d.redirectTo&&(e.isString(d.redirectTo)?c.path(t(d.redirectTo,d.params)).search(d.params).replace():c.url(d.redirectTo(d.pathParams,c.path(),c.search())).replace()),f.when(d).then(function(){if(d){var a=e.extend({},d.resolve),c,b;e.forEach(a,function(d,c){a[c]=e.isString(d)?g.get(d):g.invoke(d)});e.isDefined(c=d.template)?e.isFunction(c)&&(c=c(d.params)):e.isDefined(b=d.templateUrl)&&(e.isFunction(b)&&(b=b(d.params)),b=h.getTrustedResourceUrl(b),e.isDefined(b)&&(d.loadedTemplateUrl=
11 | b,c=n.get(b,{cache:v}).then(function(a){return a.data})));e.isDefined(c)&&(a.$template=c);return f.all(a)}}).then(function(c){d==r.current&&(d&&(d.locals=c,e.copy(d.params,b)),a.$broadcast("$routeChangeSuccess",d,m))},function(c){d==r.current&&a.$broadcast("$routeChangeError",d,m,c)})}function p(){var a,b;e.forEach(k,function(f,k){var q;if(q=!b){var g=c.path();q=f.keys;var l={};if(f.regexp)if(g=f.regexp.exec(g)){for(var h=1,p=g.length;h\[(http:\/\/.*)\]<\/p>/,
24 | match = page.text.match(iframe_pattern)
25 | if(match && match[1]) {
26 | page.iframe = $sce.trustAsResourceUrl(match[1])
27 | page.text = page.text.replace(/
\[(http:\/\/.*)\]<\/p>/, '').trim()
28 | }
29 | page.trustedText = $sce.trustAsHtml(page.text.replace(/
( )?<\/p>/,''))
30 | }
31 | page.trustedVideo = $sce.trustAsResourceUrl(page.video)
32 | page.poster = $sce.trustAsResourceUrl(page.video + '.jpg')
33 | page.contentMinimized = false;
34 | page.toggleMinimizeContent = function(){
35 | this.contentMinimized = !this.contentMinimized;
36 | setTimeout(Zoomer.windowResized, 100)
37 | }
38 | page.meta = $sce.trustAsHtml( page.meta );
39 | page.metaB = $sce.trustAsHtml( page.metaB );
40 |
41 | if( mediaMeta.isActive ) {
42 | // Identify the key - media URL for videos, media ID for zoomers.
43 | var key = null, keyB = null;
44 | switch( page.type ) {
45 | case 'text':
46 | break;
47 | case 'video':
48 | key = page.video;
49 | break;
50 | case 'image':
51 | key = page.image;
52 | break;
53 | case 'comparison':
54 | key = page.image;
55 | keyB = page.imageB;
56 | break;
57 | }
58 | // Look up in mediaMeta hash or fall back to GriotWP value.
59 | if( key ) {
60 | page.meta = mediaMeta.get( key ) || page.meta;
61 | }
62 | if( keyB ) {
63 | page.metaB = mediaMeta.get( keyB ) || page.metaB;
64 | }
65 | }
66 |
67 | // Glance Text
68 | switch( page.type ){
69 | case 'video':
70 | page.glanceText = 'Tap to play video';
71 | break;
72 | case 'image':
73 | page.glanceText = 'Press to view image';
74 | break;
75 | case 'comparison':
76 | page.glanceText = 'Press to view images';
77 | break;
78 | default:
79 | page.glanceText = 'Press to view';
80 | }
81 |
82 | });
83 |
84 | segmentio.track('Opened a Story', {id: $scope.id, name: $scope.story.title})
85 | })
86 |
87 | setTimeout(Zoomer.windowResized, 100)
88 | $scope.storyMenuOpen = false
89 | $scope.toggleStoryMenu = function(){
90 | $scope.storyMenuOpen = !$scope.storyMenuOpen
91 | }
92 |
93 | $scope.activePage = 0
94 | $scope.updateActivePage = function(newPage){
95 | if((newPage > -1) && (newPage < $scope.story.pages.length)){
96 | $scope.activePage = newPage
97 | segmentio.track('Paged a Story', {id: $scope.id, name: $scope.story.title, page: newPage})
98 | }
99 | setTimeout(Zoomer.windowResized, 200)
100 | }
101 | $scope.backToObject=function(){
102 | $rootScope.nextView = 'more'
103 | if(history.length > 1) {
104 | history.back();
105 | } else {
106 | window.location = window.location.origin + window.location.pathname
107 | }
108 | }
109 | }
110 | ])
--------------------------------------------------------------------------------
/css/goldweights.css:
--------------------------------------------------------------------------------
1 | /* Goldweights
2 | */
3 | #goldweights .flatmap .hint {
4 | display: none;
5 | z-index: -1;
6 | }
7 |
8 | #goldweights #zoomer {
9 | height: 551px;
10 | min-height: 551px;
11 | }
12 |
13 | #goldweights ol {
14 | list-style: none;
15 | padding: 0;
16 | margin: 0;
17 | }
18 |
19 | #goldweights ol > li {
20 | display: none;
21 | }
22 | #goldweights ol > li.active {
23 | display: block;
24 | margin: 0 1em 0 5em;
25 | }
26 | #goldweights li.active ~ li.active {
27 | display: none;
28 | }
29 |
30 | #goldweights h3 {
31 | position: absolute;
32 | top:-60px;
33 | left:55px;
34 | }
35 |
36 | #goldweights .play {
37 | /*width: 2.35em;
38 | height: 2.35em;*/
39 | width:44px;
40 | height:44px;
41 | padding: 1px 0 0 3px;
42 | border: 3px solid #000;
43 | border-radius: 50%;
44 | font-size:1.45em;
45 | background-color:#ededed;
46 | text-align:center;
47 | position: absolute;
48 | top:-55px;
49 | left:2px;
50 | }
51 | #goldweights .play.icon-pause {
52 | padding: 1px 0 0 0px;
53 | }
54 |
55 | #goldweights figure.popup {
56 | position: fixed;
57 | width: 100%;
58 | height: 100vh;
59 | top: 0;
60 | left: 0;
61 | margin: 0;
62 | z-index: 1000;
63 | }
64 | @media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : landscape) {
65 | #goldweights figure.popup { height: 748px; }
66 | }
67 | @media only screen and (min-device-width : 768px) and (max-device-width : 1024px) and (orientation : portrait) {
68 | #goldweights figure.popup { height: 1004px; }
69 | }
70 |
71 | #goldweights figure.popup .flatmap {
72 | width: 100%;
73 | height: 100%;
74 | z-index: 10000;
75 | }
76 | #goldweights .popup a.icon, .popup aside {
77 | position: absolute;
78 | bottom: 0;
79 | z-index: 10000000;
80 | padding: 10px;
81 | color: black;
82 | background-color: rgba(250,250,250,0.9);
83 | opacity: 1;
84 | max-height: 748px;
85 | overflow-y: scroll;
86 | }
87 | #goldweights .popup a.back {
88 | left: 0;
89 | }
90 | .popup figcaption > a {
91 | font-size: 1em;
92 | font-weight: bold;
93 | text-transform: uppercase;
94 | white-space: nowrap;
95 | }
96 | .popup figcaption > a:before {
97 | font-size: 1.4em;
98 | }
99 | .popup figcaption a.back {
100 | left: 0;
101 | }
102 | .popup figcaption a.credits {
103 | right: 0;
104 | }
105 | #goldweights figcaption aside {
106 | right: 0;
107 | max-width: 45em;
108 | background-color: rgba(250, 250, 250, 0.9);
109 | text-align: right;
110 | }
111 | #goldweights aside > * {
112 | font-weight: 200;
113 | font-size: 0.8rem;
114 | }
115 |
116 | #goldweights aside {
117 | position: relative;
118 | top: 0;
119 | opacity: 1 !important;
120 | }
121 |
122 | #goldweights div.description p:first-child{
123 | margin-top:65px;
124 | }
125 |
126 | #goldweights div.description {
127 | margin-left:55px;
128 | max-width: 33em;
129 | }
130 |
131 | #goldweights li {
132 | position:relative;
133 | margin-left:55px;
134 | }
135 |
136 | #goldweights li ul{
137 | list-style-type: none;
138 | margin-left: 55px;
139 | }
140 |
141 | #goldweights li ul li{
142 | width:25%;
143 | float:left;
144 | margin: 10px 0 !important;
145 | }
146 | #goldweights li ul li.tombstoned {
147 | width: 50%;
148 | position: relative;
149 | }
150 | #goldweights li.tombstoned img {
151 | width: 50%;
152 | }
153 | #goldweights li.tombstoned aside {
154 | position: absolute;
155 | top: 0;
156 | left: 55%;
157 | }
158 |
159 |
160 | body.west {
161 | transition: -webkit-transform 300ms linear;
162 | -webkit-transform-origin: center bottom;
163 | -webkit-transform: rotate(180deg);
164 | margin-bottom: 200px;
165 | max-height: 700px;
166 | }
167 | .west #goldweights #zoomer {
168 | -webkit-transform: rotate(180deg);
169 | }
170 | .west #goldweights #zoomer .noteMarker span {
171 | -webkit-transform: rotate(180deg);
172 | }
173 | #goldweights hr {
174 | clear: both;
175 | display: none;
176 | }
177 |
178 | #goldweights #home {
179 | position: absolute;
180 | top: 567px;
181 | right: 2em;
182 | text-align: right;
183 | }
184 | #goldweights .icon-home {
185 | color: #222;
186 | }
187 | #goldweights #home p {
188 | margin: 0;
189 | }
190 |
--------------------------------------------------------------------------------
/fonts/fontello/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "griot",
3 | "css_prefix_text": "icon-",
4 | "css_use_suffix": false,
5 | "hinting": true,
6 | "units_per_em": 1000,
7 | "ascent": 850,
8 | "glyphs": [
9 | {
10 | "uid": "d3b3f17bc3eb7cd809a07bbd4d178bee",
11 | "css": "resize-vertical",
12 | "code": 59415,
13 | "src": "fontawesome"
14 | },
15 | {
16 | "uid": "e335adbc2d898c7d85d40c507796e7b4",
17 | "css": "mail",
18 | "code": 59416,
19 | "src": "entypo"
20 | },
21 | {
22 | "uid": "3ba4275937db277075fc47d6b5a69a2e",
23 | "css": "back",
24 | "code": 59410,
25 | "src": "entypo"
26 | },
27 | {
28 | "uid": "24aba8757d4a7b49568c98a577a85df3",
29 | "css": "cancel-outline",
30 | "code": 59408,
31 | "src": "typicons"
32 | },
33 | {
34 | "uid": "1dq4tek4k8ea7zlj4kc3w83itnutaxg5",
35 | "css": "cancel",
36 | "code": 59407,
37 | "src": "typicons"
38 | },
39 | {
40 | "uid": "517522647a556192fbc78aa391b7b0c2",
41 | "css": "cancel-circled-outline",
42 | "code": 59406,
43 | "src": "typicons"
44 | },
45 | {
46 | "uid": "3327862df439988139b61814143b7a42",
47 | "css": "cancel-circled",
48 | "code": 59405,
49 | "src": "typicons"
50 | },
51 | {
52 | "uid": "1gf923f9wvaezxmfon515dglxa3drf0e",
53 | "css": "plus",
54 | "code": 59413,
55 | "src": "typicons"
56 | },
57 | {
58 | "uid": "qab5uvjyoc3uu4d2pvt8soshtgkuvpak",
59 | "css": "minus",
60 | "code": 59414,
61 | "src": "typicons"
62 | },
63 | {
64 | "uid": "85fda3129wk4amvn25wrq843sbj3yzl0",
65 | "css": "info",
66 | "code": 59411,
67 | "src": "typicons"
68 | },
69 | {
70 | "uid": "w3nzesrlbezu6f30q7ytyq919p6gdlb6",
71 | "css": "home",
72 | "code": 59394,
73 | "src": "typicons"
74 | },
75 | {
76 | "uid": "6a06892e76b81e023da6ddfb38a26b37",
77 | "css": "doc-text",
78 | "code": 59412,
79 | "src": "typicons"
80 | },
81 | {
82 | "uid": "jh3jpcb1t1bcm80gidkadilh080aq79h",
83 | "css": "menu",
84 | "code": 59395,
85 | "src": "typicons"
86 | },
87 | {
88 | "uid": "cdfalpadi7huwv9ah4fef2gpfpb4c6qm",
89 | "css": "resize-full",
90 | "code": 59392,
91 | "src": "typicons"
92 | },
93 | {
94 | "uid": "8d2bc2d959a55e76466bbef6e84c8373",
95 | "css": "resize-normal",
96 | "code": 59393,
97 | "src": "typicons"
98 | },
99 | {
100 | "uid": "wlri7uftq4zbi82q2xuf08ayd8kpijlk",
101 | "css": "left-open",
102 | "code": 59396,
103 | "src": "typicons"
104 | },
105 | {
106 | "uid": "6zhrgcf3co77hnljttd3b2mrc8z5fiq5",
107 | "css": "right-open",
108 | "code": 59397,
109 | "src": "typicons"
110 | },
111 | {
112 | "uid": "qqsxko9kqxh5g53lz33yonkpc2rpkvkn",
113 | "css": "left",
114 | "code": 59398,
115 | "src": "typicons"
116 | },
117 | {
118 | "uid": "4oaz56fmzfvx7vry2o540n9l4z79fz8t",
119 | "css": "right",
120 | "code": 59399,
121 | "src": "typicons"
122 | },
123 | {
124 | "uid": "58b78b6ca784d5c3db5beefcd9e18061",
125 | "css": "left-small",
126 | "code": 59400,
127 | "src": "typicons"
128 | },
129 | {
130 | "uid": "877a233d7fdca8a1d82615b96ed0d7a2",
131 | "css": "right-small",
132 | "code": 59401,
133 | "src": "typicons"
134 | },
135 | {
136 | "uid": "3e290a111c0f3ee3acbf7b5f17ccc04a",
137 | "css": "play",
138 | "code": 59402,
139 | "src": "typicons"
140 | },
141 | {
142 | "uid": "e44ef09cb81413287d702eefa65dd790",
143 | "css": "pause",
144 | "code": 59409,
145 | "src": "typicons"
146 | },
147 | {
148 | "uid": "8f25d96c5665c84e4403538eef14ec2c",
149 | "css": "info-circled",
150 | "code": 59403,
151 | "src": "mfglabs"
152 | },
153 | {
154 | "uid": "15ba51cbb4d05e6fb88f03a31a7c711c",
155 | "css": "info-circled-alt",
156 | "code": 59404,
157 | "src": "mfglabs"
158 | }
159 | ]
160 | }
--------------------------------------------------------------------------------
/js/factories.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Retrieve external data.
3 | */
4 |
5 | // Tile data
6 | app.factory('tilesaw', ['$http', 'envConfig', function($http, config) {
7 | return { get: function(image) {
8 | return $http.get(config.tilesaw + image + '.tif', {cache: true}).then(function(result) { return result.data; })
9 | }}
10 | }])
11 |
12 | // Application content
13 | app.factory('notes', ['$http', 'envConfig', 'miaThumbnailAdapter', '$sce', '$q', function($http, config, thumbs, $sce, $q) {
14 | window.miaThumbnailAdapter = thumbs // TODO: why isn't this injected below? I can't access inside either of the next functions on L15 and 16
15 | window.$q = $q // again, why!?
16 | return function() {
17 | var d = $q.defer()
18 |
19 | $http.get(config.crashpad, {cache: true}).then(function(result) {
20 | result.data.clusters = require('../clusters/clusters.json') // TODO: PS these shouldn't be hardcoded
21 |
22 | angular.forEach(result.data.objects, function(o) {
23 | o.thumbnail = miaThumbnailAdapter.get(o.views[0].image)
24 | o.title = o.title.replace('&', '&')
25 | })
26 | angular.forEach(result.data.panels, function(panel) {
27 | panel.trustedContent = $sce.trustAsHtml(panel.content)
28 | })
29 |
30 | return result.data;
31 | }).then(function(data) {
32 | // (artstories-image-dimensions.json is 72kb of JSON generated by a makefile task completely dependent on me)
33 | // TODO: compute this hash of image dimensions automatically, codify it into the image server.
34 | // then maybe serve up only the needed images?
35 | var url = "http://cdn.dx.artsmia.org/thumbs/artstories-image-dimensions.json"
36 | return $http.get(url, {cache: true}).then(function(result) {
37 | var allImageDimensions = result.data
38 | data.objects = angular.forEach(data.objects, function(o, id) {
39 | var dimensions = allImageDimensions[o.views[0].image]
40 | if(!dimensions) return console.info('missing dimensions for', id, o.views[0].image)
41 | o.imageWidth = dimensions[0]
42 | o.imageHeight = dimensions[1]
43 | })
44 |
45 | d.resolve(data)
46 | })
47 | })
48 |
49 | return d.promise
50 | }
51 | }])
52 |
53 | app.factory('email', ['$http', 'envConfig', function($http, config) {
54 | return {
55 | share: function(email, params) {
56 | return $http.post(config.emailServer + email, params).success(function(response) {
57 | return response
58 | })
59 | }
60 | }
61 | }])
62 |
63 | app.factory('initIsotope', ['$rootScope', function($rootScope) {
64 | return function() {
65 | if( window.innerWidth < 768 ) {
66 | $rootScope.loaded = true;
67 | return;
68 | }
69 |
70 | var cover = document.querySelector('#cover');
71 |
72 | this.iso = new Isotope( cover, {
73 | itemSelector:'.isotope-item',
74 | layoutMode:'masonryHorizontal',
75 | masonryHorizontal: {
76 | rowHeight: 300,
77 | gutter: 2 // this is only for the vertical space between rows, space each element out with margin-right
78 | },
79 | containerStyle: null,
80 | isInitLayout: false
81 | });
82 |
83 | var centerCover = function(){
84 | // Get height of container
85 | var availableHeight = $('.cover-wrapper').height();
86 |
87 | // Get number of rows - 300px plus 10px gutter.
88 | var rowCount = Math.floor( availableHeight / 302 ) || 1;
89 |
90 | // Get height that will wrap snugly around rows
91 | var newHeight = ( rowCount * 302 ) + 1;
92 |
93 | // Get new top for #cover
94 | var newTop = ( availableHeight - newHeight) / 2;
95 |
96 | // Update cover height and top margin
97 | $('#cover').css({
98 | 'height': newHeight + 'px',
99 | 'top': newTop + 'px'
100 | });
101 |
102 | }
103 |
104 | this.iso.on( 'layoutComplete', function(){
105 |
106 | centerCover();
107 |
108 | $('.cover-item').css({
109 | 'opacity':1
110 | });
111 |
112 | $rootScope.loaded = true;
113 | });
114 |
115 | $(window).on( 'resize', function(){
116 | centerCover();
117 | });
118 |
119 | this.iso.layout();
120 |
121 | };
122 | }])
123 |
--------------------------------------------------------------------------------
/js/directives/note.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Creates and controls annotation markers on a zoomable image (flatmap).
3 | */
4 |
5 | app.directive('note', function(segmentio, $sce) {
6 | var divIcon = L.divIcon({className: 'noteMarker'})
7 | return {
8 | restrict: 'E',
9 | // scope: {note: '=', view: '='},
10 | controller: function($scope) {},
11 | require: '^flatmap',
12 | link: function(scope, element, attrs, flatmapCtrl) {
13 | var jsonToLayer = function(note) {
14 | var geometry, json;
15 | if(note.type == 'FeatureCollection') {
16 | json = {type: 'MultiPolygon', coordinates: [].map.call(note.features, function (f) { return [f.geometry.coordinates[0]] })}
17 | } else {
18 | json = note.geometry
19 | }
20 |
21 | return L.GeoJSON.geometryToLayer(json)
22 | }
23 |
24 | var eachMarker = function(callback) {
25 | angular.forEach(scope.markers, callback)
26 | },
27 | eachLayer = function(layer, callback) {
28 | layer.eachLayer ? layer.eachLayer(callback) : callback(layer)
29 | }
30 |
31 | scope.flatmapCtrl = flatmapCtrl
32 | scope.map = scope.flatmapCtrl.scope.zoom.map
33 | scope.jsonLayer = jsonToLayer(scope.note.geoJSON)
34 | scope.note.index = scope.$parent.$parent.noteCount = (scope.$parent.$parent.noteCount || 0) + 1
35 | divIcon.options.html = "" + scope.note.index + " "
36 | scope.markers = []
37 |
38 | eachLayer(scope.jsonLayer, function(layer) {
39 | scope.markers.push(L.marker(layer.getBounds().getCenter(), {icon: divIcon}))
40 | })
41 |
42 | scope.note.active = false
43 |
44 | var zoomNote = function() {
45 | flatmapCtrl.scope.$broadcast('changeView', scope.view)
46 | flatmapCtrl.scope.$broadcast('changeGeometry', scope.jsonLayer)
47 | scope.note.active = true
48 | scope.$$phase || scope.$apply()
49 | scrollNoteTextIntoView()
50 | }
51 | var scrollNoteTextIntoView = function() { // this is hacky
52 | var noteEl = $('#annotations li.note:nth-child(' + (scope.$index+1) + ')')[0]
53 | if(noteEl) noteEl.scrollIntoViewIfNeeded && noteEl.scrollIntoViewIfNeeded() || noteEl.scrollIntoView()
54 | }
55 | var toggleNoteZoom = function() {
56 | scope.$apply(function() { scope.note.active = !scope.note.active })
57 | }
58 |
59 | scope.$watch('note.active', function(newVal, oldVal) {
60 | var openedOrClosed = undefined
61 | if(!newVal && oldVal && scope.note == flatmapCtrl.scope.lastActiveNote) {
62 | flatmapCtrl.removeJsonLayer()
63 | scope.map.zoomOut(100)
64 | flatmapCtrl.scope.lastActiveNote = null
65 | openedOrClosed = 'Closed'
66 | } else if(newVal && !oldVal) {
67 | var lastNote = flatmapCtrl.scope.lastActiveNote, note = scope.note
68 | if(lastNote) lastNote.active = false
69 | zoomNote()
70 | flatmapCtrl.scope.lastActiveNote = scope.note
71 | openedOrClosed = 'Opened'
72 | scope.$parent.$parent.$parent.glanceText = $sce.trustAsHtml( "Press to view detail " + scope.note.index + " " );
73 | scope.$$phase || scope.$apply()
74 | }
75 | if(openedOrClosed) segmentio.track(openedOrClosed + ' a Detail', {title: scope.note.title, index: scope.note.index, id: flatmapCtrl.scope.$parent.id})
76 |
77 | // The active marker goes to the SW (lower-left) corner of bounds
78 | // inactive markers, center of bounds
79 | var layer = scope.jsonLayer, index = 0
80 | eachLayer(layer, function(_layer) {
81 | scope.markers[index].setLatLng(newVal ? _layer._latlngs[0] : _layer.getBounds().getCenter())
82 | index++
83 | })
84 | })
85 |
86 | flatmapCtrl.scope.$watch('image', function(newVal, oldVal) {
87 | eachMarker(function(marker) {
88 | if(newVal == scope.$parent.view.image) {
89 | marker.setOpacity(1)
90 | marker.on('click', toggleNoteZoom)
91 | } else {
92 | marker.setOpacity(0)
93 | marker.off('click', toggleNoteZoom)
94 | }
95 | })
96 | })
97 |
98 | eachMarker(function(marker) { marker.addTo(scope.map) })
99 | }
100 | }
101 | })
102 |
103 |
--------------------------------------------------------------------------------
/sass/index.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Styles for the cover page.
3 | */
4 |
5 | .cover-wrapper {
6 | position:absolute;
7 | top:0;
8 | right:0;
9 | bottom:3em;
10 | left:0;
11 | list-style:none;
12 | padding:0;
13 | overflow:auto;
14 | -webkit-overflow-scrolling:touch;
15 | }
16 |
17 | #cover {
18 | position:absolute;
19 | top:0;
20 | right:0;
21 | bottom:0;
22 | left:0;
23 | display:block;
24 | padding: 0 10px;
25 | margin:0;
26 | overflow:auto;
27 | -webkit-overflow-scrolling:touch;
28 |
29 | @media #{$medium}{
30 | padding:0 0 0 10px;
31 | }
32 | }
33 |
34 | .cover-item {
35 | @include transition( opacity 300ms ease );
36 | display:block;
37 | vertical-align:top;
38 | margin-right: 2px;
39 | height:auto;
40 | max-height:300px;
41 | max-width:100%;
42 |
43 | @media #{$medium}{
44 | opacity:0;
45 | }
46 |
47 | &.story {
48 | max-width:100%;
49 | width:300px;
50 | height:300px;
51 | padding:15px;
52 | background-color:#fff;
53 | border:1px solid #999;
54 | }
55 |
56 | &.panel{
57 | padding:15px;
58 | background-color:#fff;
59 | border:1px solid #999;
60 | max-width:100%;
61 | max-height:100%;
62 | }
63 |
64 | &.panel-big{
65 | width:610px;
66 | height:610px;
67 | }
68 |
69 | &.panel-portrait{
70 | width:300px;
71 | height:610px;
72 | }
73 |
74 | &.panel-landscape{
75 | width:610px;
76 | height:300px;
77 | }
78 |
79 | &.panel-small{
80 | width:300px;
81 | height:300px;
82 | }
83 |
84 | a {
85 | text-decoration:none;
86 | }
87 |
88 | @media #{$medium} {
89 | height:300px;
90 | margin:0 2px 0 0;
91 | }
92 | }
93 |
94 | .cover-item-image {
95 | display:block;
96 | max-height:100%;
97 | margin:0 auto;
98 | border:1px solid #999;
99 | }
100 |
101 | .cover-item-title {
102 | font-size:1.1em;
103 | color:#222;
104 | text-align:center;
105 | line-height:1.1;
106 | padding:0;
107 | margin:0;
108 |
109 | .object & {
110 | display:none;
111 | }
112 | }
113 |
114 | .cover-item-poster{
115 | width:100%;
116 | height:200px;
117 | background-size:cover;
118 | background-position:50% 50%;
119 | border:1px solid #999;
120 | }
121 |
122 | .cover-item-caption {
123 | position:relative;
124 | height:85px;
125 | margin:0;
126 | padding:10px;
127 | }
128 |
129 | .cover-panel-wrap{
130 | height:100%;
131 | }
132 |
133 | .cover-instructions {
134 | @include box-shadow(0 -3px 5px rgba(0,0,0,0.23));
135 | position:absolute;
136 | display:block;
137 | bottom:0;
138 | font-size:1em;
139 | font-style:italic;
140 | text-align:center;
141 | width:100%;
142 | height:50px;
143 | line-height:50px;
144 | vertical-align:middle;
145 | background-color:#ddd;
146 | }
147 |
148 | .cover-instructions * {
149 | display: inline;
150 | font-size: 100%;
151 | }
152 |
153 | .cover-instructions p {
154 | display: none;
155 | }
156 |
157 | .clusters img {
158 | max-width: 30%;
159 | }
160 |
161 | .clusters li {
162 | display: inline;
163 | list-style: none;
164 | -webkit-columns: 3;
165 | }
166 |
167 | aside.splash.show {
168 | z-index: 10;
169 | opacity: 1;
170 | }
171 |
172 | aside.splash {
173 | z-index: -1;
174 | opacity: 0;
175 | display: block;
176 | -webkit-transition: all 0.5s;
177 | text-align: center;
178 | font-family: MiaGrotesk-Light;
179 | font-size: 234%;
180 | height: 100%;
181 | position: relative;
182 | }
183 |
184 | aside.splash h1 {
185 | text-transform: lowercase;
186 | font-family: MiaGrotesk-Bold, sans-serif;
187 | font-size: 3em;
188 | margin: 0 0 -.25em 0;
189 | color: #333;
190 | }
191 |
192 | aside.splash #placard {
193 | background-color: rgba(255, 255, 255, 0.7);
194 | vertical-align: middle;
195 | padding: 1em;
196 | position: relative;
197 | top: 50%;
198 | transform: translateY(-50%);
199 | -webkit-transform: translateY(-50%);
200 | max-width: 100%;
201 | }
202 | @media #{$medium}{
203 | aside.splash h1 {
204 | font-size: 4em;
205 | }
206 | aside.splash #placard > p {
207 | padding: 0 2em;
208 | }
209 | }
210 |
211 | #ethnio-screener-48826 {
212 | top: auto !important;
213 | bottom: 0;
214 | }
215 | #ethnio-screener-48826 > div:first-child {
216 | padding: 0 !important;
217 | margin: 9px 0;
218 | }
219 | #ethnio-screener-id-48826 {
220 | top: auto !important;
221 | bottom: 0px;
222 | }
223 |
--------------------------------------------------------------------------------
/js/adapters.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Adapters (MIA-specific)
3 | *
4 | * These adapters are specific to the MIA's implementation of Griot. You should
5 | * overwrite them if you'd like to use your own service to pull data. If you'd
6 | * rather pull all data from GriotWP or another service, set
7 | * config.miaMediaMetaActive, config.miaObjectMetaActive, and
8 | * config.miaThumbnailAdapterActive to false in config.js.
9 | */
10 |
11 | /**
12 | * miaMediaMetaAdapter
13 | *
14 | * Grabs media metadata from an external source and provides a method for
15 | * retrieving that metadata by ID.
16 | */
17 | app.service( 'miaMediaMetaAdapter', function( $http, $sce, envConfig ) {
18 |
19 | var _this = this;
20 |
21 | this.isActive = false;
22 |
23 | this.metaHash = {};
24 |
25 | this.get = function( id ) {
26 | return _this.metaHash[ id ] || false;
27 | }
28 |
29 | this.build = function( src ){
30 |
31 | $http.get( src, { cache: true } ).success( function( result ) {
32 |
33 | _this.isActive = true;
34 |
35 | for( var id in result ) {
36 | var description = result[ id ].description ? result[id].description + " " : '';
37 | var credit = result[ id ].credit || '';
38 | _this.metaHash[ id ] = $sce.trustAsHtml((description + credit).replace(/\n/g, ' \n'));
39 | }
40 |
41 | });
42 |
43 | }
44 |
45 | });
46 |
47 | /**
48 | * miaObjectMetaAdapter
49 | *
50 | * Grabs object metadata from an external source and provides a method for
51 | * retrieving metadata reformatted into a particular grouping, i.e. to match
52 | * the groups in GriotWP.
53 | */
54 | app.service( 'miaObjectMetaAdapter', function( $http, $sce, envConfig ) {
55 | var _this = this;
56 |
57 | this.isActive = envConfig.miaObjectMetaActive;
58 |
59 | this.metaHash = {};
60 |
61 | this.get = function( id, grouping ) {
62 | try{
63 | if (_this.metaHash[id] !== undefined) {
64 | var hash = _this.metaHash[id] || _this.metaHash[parseInt(id)]
65 | return grouping ? hash[grouping] : hash
66 | } else {
67 | return this.getFromAPI(id, grouping)
68 | }
69 | } catch(e) {
70 | console.log('error in objectMeta.get', e)
71 | return null;
72 | }
73 | }
74 |
75 | this.getFromAPI = function(id, grouping) {
76 | var apiURL = envConfig.miaObjectMetaSrc+id
77 | return $http.get(apiURL, {cache: true}).then(function(result) {
78 | var data = result.data
79 | if(id.match('/')) id = data.id.split('/').reverse()[0]
80 | _this.addObjectToMetaHash(id, data)
81 | return _this.get(id, grouping)
82 | })
83 | }
84 |
85 | this.addObjectToMetaHash = function(id, json) {
86 | var groupings = {},
87 | artist,
88 | culture,
89 | country,
90 | dated,
91 | medium,
92 | dimension,
93 | creditline,
94 | accession_number,
95 | trustedDescription;
96 |
97 | artist = json.artist || 'Artist unknown';
98 | culture = json.culture || '';
99 | country = json.country || '';
100 | dated = json.dated || '';
101 | medium = json.medium || '';
102 | dimension = json.dimension || '';
103 | creditline = json.creditline || '';
104 | accession_number = json.accession_number || '';
105 | trustedDescription = $sce.trustAsHtml( json.description );
106 |
107 | groupings.meta1 = artist + ', ' + ( culture && culture + ', ' ) + country;
108 | groupings.meta2 = dated;
109 | groupings.meta3 = $sce.trustAsHtml( ( medium && medium + " " ) + ( dimension && dimension + " " ) + ( creditline && creditline + " " ) + accession_number );
110 |
111 | // Special editions for goldweights
112 | groupings.gw_title = $sce.trustAsHtml( json.title );
113 | groupings.gw_meta2 = $sce.trustAsHtml( ( creditline && creditline + " " ) + accession_number );
114 | groupings.location = json.room.replace('G', '')
115 |
116 | this.metaHash[id] = groupings;
117 | return groupings
118 | }
119 |
120 | });
121 |
122 | /**
123 | * miaThumbnailAdapter
124 | *
125 | * Provides a method for retrieving an image thumbnail from an external source,
126 | * given an image ID.
127 | */
128 | app.service( 'miaThumbnailAdapter', function() {
129 |
130 | var _this = this;
131 |
132 | this.isActive = false;
133 |
134 | this.cdn = '';
135 |
136 | this.init = function( cdn ) {
137 | _this.isActive = true;
138 | _this.cdn = cdn;
139 | }
140 |
141 | this.get = function( id ) {
142 | if(id === undefined) return
143 | var trimmed_id = id.replace( '.tif', '' );
144 | return _this.cdn + 'thumbs/tn_' + trimmed_id + '.jpg';
145 | }
146 |
147 | });
148 |
--------------------------------------------------------------------------------
/js/vendor/masonry-horizontal.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * masonryHorizontal layout mode for Isotope
3 | * http://isotope.metafizzy.co
4 | */
5 |
6 | /*jshint browser: true, strict: true, undef: true, unused: true */
7 |
8 | ( function( window ) {
9 |
10 | 'use strict';
11 |
12 | // -------------------------- helpers -------------------------- //
13 |
14 | var indexOf = Array.prototype.indexOf ?
15 | function( items, value ) {
16 | return items.indexOf( value );
17 | } :
18 | function ( items, value ) {
19 | for ( var i=0, len = items.length; i < len; i++ ) {
20 | var item = items[i];
21 | if ( item === value ) {
22 | return i;
23 | }
24 | }
25 | return -1;
26 | };
27 |
28 | // -------------------------- definition -------------------------- //
29 |
30 | function masonryHorizontalDefinition( getSize, LayoutMode ) {
31 | // create an Outlayer layout class
32 | var MasonryHorizontal = LayoutMode.create('masonryHorizontal');
33 |
34 | MasonryHorizontal.prototype._resetLayout = function() {
35 | this.getRowHeight();
36 | this._getMeasurement( 'gutter', 'outerHeight' );
37 |
38 | this.rowHeight += this.gutter;
39 | // measure rows
40 | this.rows = Math.floor( ( this.isotope.size.innerHeight + this.gutter ) / this.rowHeight );
41 | this.rows = Math.max( this.rows, 1 );
42 |
43 | // reset row Xs
44 | var i = this.rows;
45 | this.rowXs = [];
46 | while (i--) {
47 | this.rowXs.push( 0 );
48 | }
49 |
50 | this.maxX = 0;
51 | };
52 |
53 | MasonryHorizontal.prototype._getItemLayoutPosition = function( item ) {
54 | item.getSize();
55 | // how many rows does this brick span
56 | var rowSpan = Math.ceil( item.size.outerHeight / this.rowHeight );
57 | rowSpan = Math.min( rowSpan, this.rows );
58 |
59 | var rowGroup = this._getRowGroup( rowSpan );
60 | // get the minimum X value from the rows
61 | var minimumX = Math.min.apply( Math, rowGroup );
62 | var shortRowIndex = indexOf( rowGroup, minimumX );
63 |
64 | // position the brick
65 | var position = {
66 | x: minimumX,
67 | y: this.rowHeight * shortRowIndex
68 | };
69 |
70 | // apply setHeight to necessary rows
71 | var setWidth = minimumX + item.size.outerWidth;
72 | var setSpan = this.rows + 1 - rowGroup.length;
73 | for ( var i = 0; i < setSpan; i++ ) {
74 | this.rowXs[ shortRowIndex + i ] = setWidth;
75 | }
76 |
77 | return position;
78 | };
79 |
80 | /**
81 | * @param {Number} rowSpan - number of rows the element spans
82 | * @returns {Array} rowGroup
83 | */
84 | MasonryHorizontal.prototype._getRowGroup = function( rowSpan ) {
85 | if ( rowSpan < 2 ) {
86 | // if brick spans only one row, use all the row Xs
87 | return this.rowXs;
88 | }
89 |
90 | var rowGroup = [];
91 | // how many different places could this brick fit horizontally
92 | var groupCount = this.rows + 1 - rowSpan;
93 | // for each group potential horizontal position
94 | for ( var i = 0; i < groupCount; i++ ) {
95 | // make an array of rowX values for that one group
96 | var groupRowXs = this.rowXs.slice( i, i + rowSpan );
97 | // and get the max value of the array
98 | rowGroup[i] = Math.max.apply( Math, groupRowXs );
99 | }
100 | return rowGroup;
101 | };
102 |
103 | MasonryHorizontal.prototype._manageStamp = function( stamp ) {
104 | var stampSize = getSize( stamp );
105 | var offset = this.isotope._getElementOffset( stamp );
106 | // get the rows that this stamp affects
107 | var firstY = this.isotope.options.isOriginTop ? offset.top : offset.bottom;
108 | var lastY = firstY + stampSize.outerHeight;
109 | var firstRow = Math.floor( firstY / this.rowHeight );
110 | firstRow = Math.max( 0, firstRow );
111 | var lastRow = Math.floor( lastY / this.rowHeight );
112 | lastRow = Math.min( this.rows - 1, lastRow );
113 | // set rowXs to outside edge of the stamp
114 | var stampMaxX = ( this.isotope.options.isOriginLeft ? offset.left : offset.right ) +
115 | stampSize.outerWidth;
116 | for ( var i = firstRow; i <= lastRow; i++ ) {
117 | this.rowXs[i] = Math.max( stampMaxX, this.rowXs[i] );
118 | }
119 | };
120 |
121 | MasonryHorizontal.prototype._getContainerSize = function() {
122 | this.maxX = Math.max.apply( Math, this.rowXs );
123 |
124 | return {
125 | width: this.maxX
126 | };
127 | };
128 |
129 | MasonryHorizontal.prototype.needsResizeLayout = function() {
130 | return this.needsVerticalResizeLayout();
131 | };
132 |
133 | return MasonryHorizontal;
134 |
135 | }
136 |
137 | if ( typeof define === 'function' && define.amd ) {
138 | // AMD
139 | define( [
140 | 'get-size/get-size',
141 | 'isotope/js/layout-mode'
142 | ],
143 | masonryHorizontalDefinition );
144 | } else {
145 | // browser global
146 | masonryHorizontalDefinition(
147 | window.getSize,
148 | window.Isotope.LayoutMode
149 | );
150 | }
151 |
152 | })( window );
153 |
--------------------------------------------------------------------------------
/js/directives/flatmap.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Creates a zoomable image element.
3 | */
4 |
5 | app.directive('flatmap', function(tilesaw, envConfig, $rootScope ) {
6 | return {
7 | restrict: 'E',
8 | scope: {
9 | json: '@',
10 | image: '@'
11 | },
12 | replace: true,
13 | transclude: true,
14 | template: '
',
15 | controller: function($scope, $element, $attrs ) {
16 | var scope = $scope
17 | scope.$parent.flatmapScope = scope
18 | scope.zoomed = $rootScope.zoomed
19 |
20 | var removeJsonLayer = function() {
21 | if(scope.jsonLayer) scope.zoom.map.removeLayer(scope.jsonLayer)
22 | if(scope.inverseLayer) scope.zoom.map.removeLayer(scope.inverseLayer)
23 | }
24 |
25 | var showJsonLayer = function(fadeAfter, inverse) {
26 | if(!scope.jsonLayer) return
27 | var layerStyle = {stroke: true, fill: false, weight: 2, color: '#eee', opacity: '0.5'},
28 | addLayer = null
29 |
30 | if(inverse) {
31 | var holes = []
32 | scope.jsonLayer._latlngs ? holes.push(scope.jsonLayer._latlngs)
33 | : scope.jsonLayer.eachLayer(function(l) { holes.push(l._latlngs) })
34 | scope.inverseLayer = L.polygon([scope.zoom.imageBounds.toPolygon()._latlngs].concat(holes))
35 | scope.inverseLayer.setStyle({fill: true, fillColor: '#000', fillOpacity: '0.5', stroke: false})
36 | addLayer = scope.inverseLayer
37 | } else {
38 | scope.jsonLayer.setStyle(layerStyle)
39 | addLayer = scope.jsonLayer
40 | }
41 | scope.zoom.map.addLayer(addLayer)
42 | // if(fadeAfter) setTimeout(removeJsonLayer, fadeAfter)
43 | }
44 |
45 | var loadImage = function(image) {
46 | if(image === 'undefined' || image === '') return
47 | scope.viewChanging = true
48 | scope.image = image
49 | removeJsonLayer(); scope.jsonLayer = null
50 | tilesaw.get(image).then(function(tileJson) {
51 | $('#'+scope.container).find('.leaflet-tile-pane').css('visibility', 'visible') // why is this necessary? when I re-init a zoomer it's visibility is hidden.
52 | var tileUrl = envConfig.tileUrlSubdomain(tileJson.tiles[0])
53 | scope.$parent.$parent.tileJson = tileJson
54 | scope.$parent.$parent.imageAspectRatio = tileJson.width / tileJson.height
55 | scope.zoom = Zoomer.zoom_image({container: scope.container, tileURL: tileUrl, imageWidth: tileJson.width, imageHeight: tileJson.height})
56 | scope.$emit('viewChanged')
57 | scope.$parent.mapLoaded = true
58 | var watchForZoom = scope.zoom.map.on('zoomstart', function() {
59 | scope.$emit('zoom');
60 | (scope.$$phase || $rootScope.$$phase) || scope.$apply(function() { $rootScope.zoomed = scope.zoomed = true })
61 | scope.zoom.map.off(watchForZoom)
62 | })
63 | })
64 | }
65 | loadImage(scope.image)
66 |
67 | var annotateAndZoom = function(geometry) {
68 | removeJsonLayer()
69 | if(geometry) {
70 | if(geometry._initHooksCalled) { // it's a leaflet object, probably layer
71 | scope.jsonLayer = geometry
72 | } else {
73 | scope.jsonLayer = L.GeoJSON.geometryToLayer(geometry)
74 | }
75 | }
76 | if(scope.viewChanging) return // hold off until the view changes, resulting in `viewChanged` triggering this again
77 | if(scope.jsonLayer) {
78 | scope.$parent.$broadcast('showAnnotationsPanel', 'annotations')
79 | var map = scope.zoom.map,
80 | mapBounds = map.getBounds(),
81 | jsonLayerBounds = scope.jsonLayer.getBounds(),
82 | delay = 0
83 | if(mapBounds.intersects(jsonLayerBounds) || mapBounds.contains(jsonLayerBounds)) {
84 | } else {
85 | // Zoomer is misbehaving when zooming outside the current bounds, plus the zoom all the way out and back in thing is cool
86 | setTimeout(function() { map.zoomOut(100) }, 300)
87 | delay = 1000
88 | }
89 | setTimeout(function() { showJsonLayer(3000, true) }, delay)
90 | setTimeout(function() { map.fitBounds(scope.jsonLayer.getBounds()) }, delay+250)
91 | }
92 | }
93 |
94 | scope.$on('changeGeometry', function(event, geometry) { annotateAndZoom(geometry) }, true)
95 | scope.$on('viewChanged', function(event, message) { scope.viewChanging = false; annotateAndZoom() }, true)
96 | scope.$on('changeView', function(event, message) {
97 | if(message.image != scope.image) loadImage(message.image)
98 | })
99 |
100 | // TODO: get this working better
101 | scope.$on('viewChanged', function() {
102 | scope.zoom.map.on('zoomedBeyondMin', function(e) {
103 | if(scope.$parent && scope.$parent.notes && scope.$parent.notes.length > 1 && scope.$parent.changeZoomerForViews)
104 | scope.$parent.changeZoomerForViews(this, scope)
105 | })
106 | })
107 |
108 | return {
109 | loadImage: loadImage,
110 | annotateAndZoom: annotateAndZoom,
111 | removeJsonLayer: removeJsonLayer,
112 | showJsonLayer: showJsonLayer,
113 | scope: scope
114 | }
115 | },
116 | link: function(scope, element, attrs) {
117 | scope.container = 'zoom-' + scope.image.replace('+', '-') + '-' + new Date().getUTCMilliseconds()
118 | element.attr('id', scope.container)
119 | }
120 | }
121 | })
122 |
123 |
--------------------------------------------------------------------------------
/js/controllers/main.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Controller for cover page (index template).
3 | */
4 |
5 | app.controller('mainCtrl', ['$scope', '$routeParams', 'segmentio', '$rootScope', '$timeout', 'orderByFilter', 'miaThumbnailAdapter', '$sce', 'resolvedNotes', 'initIsotope', '$location',
6 | function($scope, $routeParams, segmentio, $rootScope, $timeout, orderByFilter, thumbnailAdapter, $sce, notes, initIsotope, $location) {
7 | var dc = $rootScope.defaultCluster
8 | if(dc && dc !== 'highlights') $location.path('/clusters/'+$rootScope.defaultCluster)
9 |
10 | var data = $scope.data = notes
11 | $rootScope.loaded = false
12 |
13 | var cluster = $rootScope.defaultCluster || $routeParams.cluster || 'highlights'
14 | var clusterObjectIds = data.clusters[cluster.replace(/^(g)?(\d+)/i, '$1$2')]
15 | if(clusterObjectIds) {
16 | $scope.cluster = $rootScope.defaultCluster = cluster
17 | $scope.isGallery = cluster.match(/^G\d/i)
18 | $scope.gallery = $scope.cluster.replace('G', '')
19 | $rootScope.showingCluster = $scope.showingCluster =
20 | (typeof $rootScope.showingCluster === 'undefined') ? true : $rootScope.showingCluster
21 | if(!$rootScope.clusterObjects) {
22 | $scope.clusterObjects = clusterObjectIds.map(function(objectId) {
23 | var isStory = objectId.match && objectId.match(/stories\/(\d+)/)
24 | if(isStory) return data.stories[isStory[1]]
25 | return data.objects[objectId]
26 | }).filter(function(o) { return o })
27 | var startPanels = addPanelsToClusterObjects()
28 | $rootScope.clusterObjects = $scope.clusterObjects = orderByFilter($scope.clusterObjects, random)
29 | startPanels.map(function(p) { $scope.clusterObjects.unshift(p) })
30 |
31 | $rootScope.otherObjects = $scope.otherObjects = $rootScope.otherObjects = loadAllObjects()
32 | } else {
33 | $scope.clusterObjects = $rootScope.clusterObjects
34 | $scope.otherObjects = $rootScope.otherObjects
35 | }
36 | } else { // not a valid cluster
37 | $location.path('/')
38 | }
39 |
40 | $scope.toggleSeeAll = function() {
41 | var container = $('.cover-wrapper')[0]
42 | if($scope.showingCluster) $timeout(function() { container.scrollLeft = container.scrollWidth-window.innerWidth }, 0)
43 | $scope.loading = true
44 | $rootScope.showingCluster = $scope.showingCluster = !$scope.showingCluster
45 |
46 | $timeout(function() {
47 | $timeout(initIsotope, 0)
48 | $scope.loading = false
49 | }, 0)
50 | }
51 |
52 | // Maintain the random order of the cluster objects, and add all the others
53 | // in random order. Then any 'end' panels.
54 | function loadAllObjects() {
55 | var c = $scope.clusterObjects
56 | var others = []
57 |
58 | angular.forEach(data.objects, function(o) {
59 | (c.indexOf(o) > -1) || others.push(o)
60 | })
61 | others = orderByFilter(others, random)
62 |
63 | angular.forEach(data.panels, function(p) {
64 | if(c.indexOf(p) == -1 && p.position == 'end') others.push(p)
65 | })
66 |
67 | return others
68 | return angular.copy(c).map(function(o) {
69 | // angular.copy and $sce.trust don't work together. this prevents an sce.unsafe
70 | if(o.recordType == 'panel') o.trustedContent = $sce.trustAsHtml(o.content)
71 | return o
72 | }).concat(others)
73 | }
74 |
75 | // Add the panels that should be randomized to `clusterObjects` and
76 | // return the panels that need to be at the beginning so they can be
77 | // `unshifted` after randomization happens
78 | // TODO: should panels go into the cluster objects or the other objects?
79 | function addPanelsToClusterObjects() {
80 | var panels = []
81 | angular.forEach(data.panels, function(p) { panels.push(p) })
82 | panels.filter(function(p) { return p.position == 'random' })
83 | .map(function(p) { $scope.clusterObjects.push(p) })
84 | return panels.filter(function(p) { return p.position == 'start' })
85 | }
86 |
87 | $rootScope.nextView = undefined
88 |
89 | $timeout(initIsotope, 0)
90 |
91 | function random() { return 0.5 - Math.random() }
92 |
93 | if(!$rootScope.identifier) {
94 | var adjs = ["autumn", "hidden", "bitter", "misty", "silent", "empty", "dry",
95 | "dark", "summer", "icy", "delicate", "quiet", "white", "cool", "spring",
96 | "patient", "twilight", "dawn", "crimson", "wispy", "weathered", "blue"]
97 | , nouns = ["waterfall", "river", "breeze", "moon", "rain", "wind", "sea",
98 | "morning", "snow", "lake", "sunset", "pine", "shadow", "leaf", "dawn",
99 | "glitter", "forest", "hill", "cloud", "meadow", "sun", "glade", "bird",
100 | "brook", "butterfly", "bush", "dew", "dust", "field", "fire", "flower"]
101 | , number = Math.floor(Math.random()*100)
102 | , name = adjs[Math.floor(Math.random()*(adjs.length-1))]+"-"+nouns[Math.floor(Math.random()*(nouns.length-1))]+"-"+number
103 | $rootScope.identifier = name
104 | segmentio.identify(name)
105 | }
106 |
107 | segmentio.track('Landed on the homepage')
108 |
109 | // When returning to the home page from an object page, scroll to
110 | // that object.
111 | $rootScope.$watch('loaded', function(val) {
112 | if(val && $rootScope.lastObjectId) {
113 | var lastObjContainer = $('a[href*='+$rootScope.lastObjectId+']').parent()
114 | lastObjContainer && lastObjContainer[0].scrollIntoView()
115 | }
116 | })
117 |
118 | if(typeof $rootScope.showSplash == 'undefined') $rootScope.showSplash = true
119 | $scope.closeSplashScreen = function() {
120 | $rootScope.showSplash = false
121 | }
122 | }
123 | ])
124 |
--------------------------------------------------------------------------------
/views/object.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
19 |
20 |
23 |
24 |
25 |
26 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
{{wp.location == 'Not on View' ? 'Not on View' : "Gallery "+wp.location}}
39 |
40 |
41 |
42 | About
43 | Details
44 | More
45 |
46 |
47 |
48 |
49 |
50 |
57 |
58 |
59 |
60 |
61 | {{note.index}} {{note.title || 'Annotation'}}
62 |
63 |
64 |
65 |
66 |
Tap to expand
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
Interactive Features
75 |
76 |
77 |
78 |
79 |
80 |
81 |
More Views
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/sass/story.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Story template styles.
3 | */
4 |
5 | /**
6 | * Header
7 | */
8 | .story-title{
9 | @include truncate;
10 | @include box-shadow( 0 5px 5px rgba(0,0,0,0.13) );
11 | position:absolute;
12 | display:block;
13 | top:0;
14 | left:0;
15 | height:40px;
16 | width:100%;
17 | margin:0;
18 | background-color:#222;
19 | text-align:center;
20 | font-size:1.1em;
21 | color:#fff;
22 | font-weight:600;
23 | line-height:40px;
24 | padding:0 45px;
25 | overflow:hidden;
26 | z-index:2;
27 |
28 | @media #{$medium}{
29 | font-size:1.3em;
30 | }
31 | }
32 |
33 | /**
34 | * Slider structure
35 | */
36 | #story {
37 | position:absolute;
38 | top:0;
39 | right:0;
40 | bottom:0;
41 | left:0;
42 | padding:40px 0;
43 | overflow:hidden;
44 | background: #ffffff;
45 | background: -moz-radial-gradient(center, ellipse cover, #ffffff 0%, #e5e5e5 100%);
46 | background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%,#ffffff), color-stop(100%,#e5e5e5));
47 | background: -webkit-radial-gradient(center, ellipse cover, #ffffff 0%,#e5e5e5 100%);
48 | background: -o-radial-gradient(center, ellipse cover, #ffffff 0%,#e5e5e5 100%);
49 | background: -ms-radial-gradient(center, ellipse cover, #ffffff 0%,#e5e5e5 100%);
50 | background: radial-gradient(ellipse at center, #ffffff 0%,#e5e5e5 100%);
51 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#e5e5e5',GradientType=1 );
52 | }
53 | .pages-wrap{
54 | @include transition( all 500ms cubic-bezier(0.81, 0.11, 0.11, 0.91) );
55 | position:relative;
56 | top:0;
57 | left:0;
58 | width:100%;
59 | height:100%;
60 | white-space:nowrap;
61 | }
62 | .page{
63 | position:relative;
64 | display:inline-block;
65 | width:100%;
66 | height:100%;
67 | vertical-align:top;
68 | white-space:normal;
69 | overflow:hidden;
70 | background-color:#ededed;
71 | }
72 |
73 |
74 | /**
75 | * Illustration
76 | */
77 | .story-illustration {
78 | @include transition( right 100ms ease, bottom 100ms ease );
79 | @include box-shadow( 0px 3px 5px rgba(0,0,0,0.23) );
80 | position:absolute;
81 | top:0;
82 | right:0;
83 | bottom:0;
84 | left:0;
85 | z-index:1;
86 | background-color:#ddd;
87 |
88 | .contentMinimized & {
89 | bottom:45px;
90 | }
91 |
92 | @media #{$medium} {
93 | top:0;
94 | right:33%;
95 | bottom:0;
96 | left:0;
97 |
98 | .contentMinimized & {
99 | right:60px;
100 | bottom:0;
101 | }
102 |
103 | }
104 | }
105 | .story-video,
106 | .story-image,
107 | .story-comparison,
108 | .story-iframe{
109 | position:relative;
110 | width:100%;
111 | height:100%;
112 | }
113 | .story-video video{
114 | @include transition( top 100ms linear, max-height 100ms ease );
115 | display:block;
116 | margin:0px auto;
117 | }
118 | .story-image .flatmap{
119 | position:absolute;
120 | top:0;
121 | right:0;
122 | bottom:0;
123 | left:0;
124 | }
125 | .story-comparison .flatmap-a{
126 | position:absolute;
127 | top:0;
128 | right:50%;
129 | bottom:0;
130 | left:0;
131 | }
132 | .story-comparison .flatmap-b{
133 | position:absolute;
134 | top:0;
135 | right:0;
136 | bottom:0;
137 | left:50%;
138 | border-left:1px solid #ccc;
139 | }
140 |
141 |
142 | /**
143 | * Content
144 | */
145 | .story-content-container{
146 | position:absolute;
147 | top:0;
148 | right:0;
149 | width:33%;
150 | height:100%;
151 | padding:25px;
152 | background-color:#ededed;
153 | }
154 | .story-content{
155 | position:absolute;
156 | top:0;
157 | right:0;
158 | bottom:0;
159 | left:0;
160 | overflow-x:visible;
161 | overflow-y:auto;
162 | }
163 | .story-home-link {
164 | @extend .home-icon;
165 | position:relative;
166 | display:block;
167 | margin:15px 25px 15px;
168 | }
169 | .story-content .caption {
170 | margin:0 25px 15px;
171 | }
172 |
173 | .story-content .caption p{
174 | margin:0 0 1em 0;
175 |
176 | @media #{$medium} {
177 | margin:0 60px 1em 0;
178 | &:last-child{
179 | margin-bottom:0;
180 | }
181 | }
182 | }
183 |
184 | .story-content aside {
185 | @include meta;
186 | margin:0 25px 25px;
187 |
188 | @media #{$medium} {
189 | margin:0 60px 25px 25px;
190 | }
191 | }
192 |
193 |
194 | /**
195 | * Action menu
196 | */
197 | .story-menu {
198 | @include box-shadow( 0px -3px 5px rgba(0,0,0,0.23) );
199 | position:absolute;
200 | right:0;
201 | bottom:0;
202 | left:0;
203 | height:45px;
204 | margin:0;
205 | padding:0;
206 | text-align:center;
207 | background-color:#ddd;
208 | z-index:2;
209 |
210 | @media #{$medium} {
211 | @include box-shadow(none);
212 | position:absolute;
213 | top:0;
214 | right:0;
215 | bottom:auto;
216 | left:auto;
217 | width:35px;
218 | height:35px;
219 | padding:0;
220 | background-color:transparent;
221 | }
222 | }
223 |
224 | .story-menu .toggle-content {
225 | @extend .minimize-icon;
226 | @include box-shadow( none );
227 | position:relative;
228 | display:inline-block;
229 | margin:0;
230 | border:1px solid #ccc;
231 | z-index:1;
232 |
233 | @media #{$medium} {
234 | position:absolute;
235 | display:block;
236 | top:10px;
237 | right:8px;
238 | }
239 |
240 | }
241 |
242 | .story-nav {
243 | @include box-shadow( 0 -5px 5px rgba(0,0,0,0.13) );
244 | position:fixed;
245 | left:0;
246 | bottom:0;
247 | width:100%;
248 | height:40px;
249 | z-index:3;
250 | background-color:#222;
251 | }
252 | .story-nav-pager{
253 | text-align:center;
254 | font-size:0.8em;
255 | text-transform:uppercase;
256 | color:#fff;
257 | line-height:40px;
258 | vertical-align:middle;
259 | margin:0;
260 | }
261 |
262 | .story-return{
263 | @extend .nav-button;
264 | @extend .return-icon;
265 | }
266 | .story-prev-page{
267 | @extend .nav-button;
268 | @extend .nav-button-left;
269 | @extend .prev-icon;
270 | }
271 | .story-next-page{
272 | @extend .nav-button;
273 | @extend .nav-button-right;
274 | @extend .next-icon;
275 | }
--------------------------------------------------------------------------------
/clusters/clusters.json:
--------------------------------------------------------------------------------
1 | {
2 | "highlights": [
3 | 278,
4 | 529,
5 | 1218,
6 | 1226,
7 | 1244,
8 | 1348,
9 | 1355,
10 | 1380,
11 | 4866,
12 | 8023,
13 | 1629,
14 | 1721,
15 | 3183,
16 | 3520,
17 | 60728,
18 | 113926,
19 | 114602,
20 | 108860,
21 | 109118,
22 | 115836,
23 | 116725,
24 | 1270,
25 | 90742,
26 | 1411,
27 | 1748,
28 | 4324,
29 | 5788
30 | ],
31 | "G200": [
32 | 5788,
33 | 116725,
34 | 108860,
35 | 60728,
36 | 4324,
37 | 1380,
38 | 4379,
39 | 117153,
40 | 118304,
41 | 7505,
42 | 22412,
43 | 114429,
44 | 376,
45 | 4829
46 | ],
47 | "G230": [
48 | 3520,
49 | 3183,
50 | 12111,
51 | 3778,
52 | 4866,
53 | 1312,
54 | 111893,
55 | 111879,
56 | 97,
57 | 111088,
58 | 115514,
59 | 1358,
60 | 1854,
61 | 60728,
62 | 4324,
63 | 1380,
64 | 4379,
65 | 117153,
66 | 118304,
67 | 7505,
68 | 22412,
69 | 114429,
70 | 376,
71 | 4829
72 | ],
73 | "G258": [
74 | 3520,
75 | 3183,
76 | 12111,
77 | 3778,
78 | 4866,
79 | 1312,
80 | 111893,
81 | 111879,
82 | 97,
83 | 111088,
84 | 115514,
85 | 1358,
86 | 1854,
87 | 114833,
88 | 115320,
89 | 1937,
90 | 111099,
91 | 108767,
92 | 45269,
93 | 114602,
94 | 678,
95 | 112568
96 | ],
97 | "G260": [
98 | 3183,
99 | 12111,
100 | 3778,
101 | 4866,
102 | 1312,
103 | 111893,
104 | 111879,
105 | 97,
106 | 111088,
107 | 115514,
108 | 1358,
109 | 1854,
110 | 114833,
111 | 115320,
112 | 1937,
113 | 111099,
114 | 108767,
115 | 45269,
116 | 114602,
117 | 678,
118 | 112568
119 | ],
120 | "G310": [
121 | 1978,
122 | 1629,
123 | 8023,
124 | 1727,
125 | 91467,
126 | 31247,
127 | 113926,
128 | 566,
129 | 1748,
130 | 4418,
131 | 537,
132 | 529,
133 | 1348,
134 | 12092,
135 | 1218,
136 | 10436,
137 | 109118,
138 | 278,
139 | 1226
140 | ],
141 | "G321": [
142 | 1978,
143 | 1629,
144 | 8023,
145 | 1727,
146 | 91467,
147 | 31247,
148 | 113926,
149 | 566,
150 | 1748,
151 | 4418,
152 | 537,
153 | 529,
154 | 1348,
155 | 1704,
156 | 1226
157 | ],
158 | "G350": [
159 | 12092,
160 | 1218,
161 | 10436,
162 | 109118,
163 | 278,
164 | 1226,
165 | 566,
166 | 1748,
167 | 4418,
168 | 537,
169 | 529,
170 | 1348,
171 | 115352,
172 | 114514,
173 | 116116,
174 | 109112,
175 | 105014
176 | ],
177 | "G363": [
178 | 12092,
179 | 1218,
180 | 10436,
181 | 109118,
182 | 278,
183 | 115352,
184 | 114514,
185 | 116116,
186 | 109112,
187 | 105014,
188 | 2606,
189 | 1721,
190 | 115836,
191 | 107241,
192 | 109328,
193 | 1355,
194 | 1244,
195 | 1270,
196 | 90742,
197 | 1411,
198 | 108443,
199 | 2210,
200 | 109122
201 | ],
202 | "G375": [
203 | 95937,
204 | 116294,
205 | 98653,
206 | 116191,
207 | 115352,
208 | 114514,
209 | 116116,
210 | 109112,
211 | 105014,
212 | 2606,
213 | 1721,
214 | 115836,
215 | 107241,
216 | 109328,
217 | 1355,
218 | 1244,
219 | 1270,
220 | 90742,
221 | 1411,
222 | 108443,
223 | 2210,
224 | 109122
225 | ],
226 | "G379": [
227 | 95937,
228 | 116294,
229 | 98653,
230 | 116191,
231 | 115352,
232 | 114514,
233 | 116116,
234 | 109112,
235 | 105014,
236 | 12092,
237 | 1218,
238 | 10436,
239 | 1270,
240 | 90742,
241 | 1411,
242 | 1637,
243 | 113568,
244 | 43877,
245 | 108443,
246 | 2210,
247 | 109122
248 | ],
249 | "G236": [
250 | "45269",
251 | "4866",
252 | "1312",
253 | "108767",
254 | "111099",
255 | "97",
256 | "111879",
257 | "1854",
258 | "12111",
259 | "1937",
260 | "3778",
261 | "115514",
262 | "115320",
263 | "1358",
264 | "111088",
265 | "114833",
266 | "111893",
267 | "stories/377",
268 | "stories/256",
269 | "stories/352",
270 | "stories/369",
271 | "stories/371",
272 | "stories/246",
273 | "stories/249",
274 | "stories/373"
275 | ],
276 | "G250": [
277 | "45269",
278 | "4866",
279 | "1312",
280 | "108767",
281 | "111099",
282 | "97",
283 | "111879",
284 | "1854",
285 | "12111",
286 | "1937",
287 | "3778",
288 | "115514",
289 | "115320",
290 | "1358",
291 | "111088",
292 | "114833",
293 | "111893",
294 | "stories/377",
295 | "stories/256",
296 | "stories/352",
297 | "stories/369",
298 | "stories/371",
299 | "stories/246",
300 | "stories/249",
301 | "stories/373"
302 | ],
303 | "G254": [
304 | "45269",
305 | "4866",
306 | "1312",
307 | "108767",
308 | "111099",
309 | "97",
310 | "111879",
311 | "1854",
312 | "12111",
313 | "1937",
314 | "3778",
315 | "115514",
316 | "115320",
317 | "1358",
318 | "111088",
319 | "114833",
320 | "111893",
321 | "stories/377",
322 | "stories/256",
323 | "stories/352",
324 | "stories/369",
325 | "stories/371",
326 | "stories/246",
327 | "stories/249",
328 | "stories/373"
329 | ],
330 | "G220": [
331 | 122167,
332 | 122102,
333 | 122502,
334 | 122505,
335 | 3369,
336 | 122189,
337 | 122166,
338 | 122492,
339 | 122113,
340 | 122115,
341 | 6612
342 | ],
343 | "G223": [
344 | 5788,
345 | 116725,
346 | 108860,
347 | 60728,
348 | 4324,
349 | 1380,
350 | 4379,
351 | 117153,
352 | 118304,
353 | 7505,
354 | 22412,
355 | 114429,
356 | 376,
357 | 4829
358 | ],
359 | "G225": [
360 | 122167,
361 | 122102,
362 | 122502,
363 | 122505,
364 | 3369,
365 | 122189,
366 | 122166,
367 | 122492,
368 | 122113,
369 | 122115,
370 | 6612
371 | ],
372 | "G237": [
373 | 122167,
374 | 122102,
375 | 122502,
376 | 122505,
377 | 3369,
378 | 122189,
379 | 122166,
380 | 122492,
381 | 122113,
382 | 122115,
383 | 6612
384 | ],
385 | }
386 |
--------------------------------------------------------------------------------
/js/vendor/imagesloaded.pkgd.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * imagesLoaded PACKAGED v3.1.7
3 | * JavaScript is all like "You images are done yet or what?"
4 | * MIT License
5 | */
6 |
7 | (function(){function e(){}function t(e,t){for(var n=e.length;n--;)if(e[n].listener===t)return n;return-1}function n(e){return function(){return this[e].apply(this,arguments)}}var i=e.prototype,r=this,o=r.EventEmitter;i.getListeners=function(e){var t,n,i=this._getEvents();if("object"==typeof e){t={};for(n in i)i.hasOwnProperty(n)&&e.test(n)&&(t[n]=i[n])}else t=i[e]||(i[e]=[]);return t},i.flattenListeners=function(e){var t,n=[];for(t=0;e.length>t;t+=1)n.push(e[t].listener);return n},i.getListenersAsObject=function(e){var t,n=this.getListeners(e);return n instanceof Array&&(t={},t[e]=n),t||n},i.addListener=function(e,n){var i,r=this.getListenersAsObject(e),o="object"==typeof n;for(i in r)r.hasOwnProperty(i)&&-1===t(r[i],n)&&r[i].push(o?n:{listener:n,once:!1});return this},i.on=n("addListener"),i.addOnceListener=function(e,t){return this.addListener(e,{listener:t,once:!0})},i.once=n("addOnceListener"),i.defineEvent=function(e){return this.getListeners(e),this},i.defineEvents=function(e){for(var t=0;e.length>t;t+=1)this.defineEvent(e[t]);return this},i.removeListener=function(e,n){var i,r,o=this.getListenersAsObject(e);for(r in o)o.hasOwnProperty(r)&&(i=t(o[r],n),-1!==i&&o[r].splice(i,1));return this},i.off=n("removeListener"),i.addListeners=function(e,t){return this.manipulateListeners(!1,e,t)},i.removeListeners=function(e,t){return this.manipulateListeners(!0,e,t)},i.manipulateListeners=function(e,t,n){var i,r,o=e?this.removeListener:this.addListener,s=e?this.removeListeners:this.addListeners;if("object"!=typeof t||t instanceof RegExp)for(i=n.length;i--;)o.call(this,t,n[i]);else for(i in t)t.hasOwnProperty(i)&&(r=t[i])&&("function"==typeof r?o.call(this,i,r):s.call(this,i,r));return this},i.removeEvent=function(e){var t,n=typeof e,i=this._getEvents();if("string"===n)delete i[e];else if("object"===n)for(t in i)i.hasOwnProperty(t)&&e.test(t)&&delete i[t];else delete this._events;return this},i.removeAllListeners=n("removeEvent"),i.emitEvent=function(e,t){var n,i,r,o,s=this.getListenersAsObject(e);for(r in s)if(s.hasOwnProperty(r))for(i=s[r].length;i--;)n=s[r][i],n.once===!0&&this.removeListener(e,n.listener),o=n.listener.apply(this,t||[]),o===this._getOnceReturnValue()&&this.removeListener(e,n.listener);return this},i.trigger=n("emitEvent"),i.emit=function(e){var t=Array.prototype.slice.call(arguments,1);return this.emitEvent(e,t)},i.setOnceReturnValue=function(e){return this._onceReturnValue=e,this},i._getOnceReturnValue=function(){return this.hasOwnProperty("_onceReturnValue")?this._onceReturnValue:!0},i._getEvents=function(){return this._events||(this._events={})},e.noConflict=function(){return r.EventEmitter=o,e},"function"==typeof define&&define.amd?define("eventEmitter/EventEmitter",[],function(){return e}):"object"==typeof module&&module.exports?module.exports=e:this.EventEmitter=e}).call(this),function(e){function t(t){var n=e.event;return n.target=n.target||n.srcElement||t,n}var n=document.documentElement,i=function(){};n.addEventListener?i=function(e,t,n){e.addEventListener(t,n,!1)}:n.attachEvent&&(i=function(e,n,i){e[n+i]=i.handleEvent?function(){var n=t(e);i.handleEvent.call(i,n)}:function(){var n=t(e);i.call(e,n)},e.attachEvent("on"+n,e[n+i])});var r=function(){};n.removeEventListener?r=function(e,t,n){e.removeEventListener(t,n,!1)}:n.detachEvent&&(r=function(e,t,n){e.detachEvent("on"+t,e[t+n]);try{delete e[t+n]}catch(i){e[t+n]=void 0}});var o={bind:i,unbind:r};"function"==typeof define&&define.amd?define("eventie/eventie",o):e.eventie=o}(this),function(e,t){"function"==typeof define&&define.amd?define(["eventEmitter/EventEmitter","eventie/eventie"],function(n,i){return t(e,n,i)}):"object"==typeof exports?module.exports=t(e,require("eventEmitter"),require("eventie")):e.imagesLoaded=t(e,e.EventEmitter,e.eventie)}(window,function(e,t,n){function i(e,t){for(var n in t)e[n]=t[n];return e}function r(e){return"[object Array]"===d.call(e)}function o(e){var t=[];if(r(e))t=e;else if("number"==typeof e.length)for(var n=0,i=e.length;i>n;n++)t.push(e[n]);else t.push(e);return t}function s(e,t,n){if(!(this instanceof s))return new s(e,t);"string"==typeof e&&(e=document.querySelectorAll(e)),this.elements=o(e),this.options=i({},this.options),"function"==typeof t?n=t:i(this.options,t),n&&this.on("always",n),this.getImages(),a&&(this.jqDeferred=new a.Deferred);var r=this;setTimeout(function(){r.check()})}function c(e){this.img=e}function f(e){this.src=e,v[e]=this}var a=e.jQuery,u=e.console,h=u!==void 0,d=Object.prototype.toString;s.prototype=new t,s.prototype.options={},s.prototype.getImages=function(){this.images=[];for(var e=0,t=this.elements.length;t>e;e++){var n=this.elements[e];"IMG"===n.nodeName&&this.addImage(n);var i=n.nodeType;if(i&&(1===i||9===i||11===i))for(var r=n.querySelectorAll("img"),o=0,s=r.length;s>o;o++){var c=r[o];this.addImage(c)}}},s.prototype.addImage=function(e){var t=new c(e);this.images.push(t)},s.prototype.check=function(){function e(e,r){return t.options.debug&&h&&u.log("confirm",e,r),t.progress(e),n++,n===i&&t.complete(),!0}var t=this,n=0,i=this.images.length;if(this.hasAnyBroken=!1,!i)return this.complete(),void 0;for(var r=0;i>r;r++){var o=this.images[r];o.on("confirm",e),o.check()}},s.prototype.progress=function(e){this.hasAnyBroken=this.hasAnyBroken||!e.isLoaded;var t=this;setTimeout(function(){t.emit("progress",t,e),t.jqDeferred&&t.jqDeferred.notify&&t.jqDeferred.notify(t,e)})},s.prototype.complete=function(){var e=this.hasAnyBroken?"fail":"done";this.isComplete=!0;var t=this;setTimeout(function(){if(t.emit(e,t),t.emit("always",t),t.jqDeferred){var n=t.hasAnyBroken?"reject":"resolve";t.jqDeferred[n](t)}})},a&&(a.fn.imagesLoaded=function(e,t){var n=new s(this,e,t);return n.jqDeferred.promise(a(this))}),c.prototype=new t,c.prototype.check=function(){var e=v[this.img.src]||new f(this.img.src);if(e.isConfirmed)return this.confirm(e.isLoaded,"cached was confirmed"),void 0;if(this.img.complete&&void 0!==this.img.naturalWidth)return this.confirm(0!==this.img.naturalWidth,"naturalWidth"),void 0;var t=this;e.on("confirm",function(e,n){return t.confirm(e.isLoaded,n),!0}),e.check()},c.prototype.confirm=function(e,t){this.isLoaded=e,this.emit("confirm",this,t)};var v={};return f.prototype=new t,f.prototype.check=function(){if(!this.isChecked){var e=new Image;n.bind(e,"load",this),n.bind(e,"error",this),e.src=this.src,this.isChecked=!0}},f.prototype.handleEvent=function(e){var t="on"+e.type;this[t]&&this[t](e)},f.prototype.onload=function(e){this.confirm(!0,"onload"),this.unbindProxyEvents(e)},f.prototype.onerror=function(e){this.confirm(!1,"onerror"),this.unbindProxyEvents(e)},f.prototype.confirm=function(e,t){this.isConfirmed=!0,this.isLoaded=e,this.emit("confirm",this,t)},f.prototype.unbindProxyEvents=function(e){n.unbind(e.target,"load",this),n.unbind(e.target,"error",this)},s});
--------------------------------------------------------------------------------
/fonts/fontello/font/griot.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Copyright (C) 2014 by original authors @ fontello.com
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/js/vendor/angular-touch.min.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version":3,
3 | "file":"angular-touch.min.js",
4 | "lineCount":12,
5 | "mappings":"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",
6 | "sources":["angular-touch.js"],
7 | "names":["window","angular","undefined","makeSwipeDirective","directiveName","direction","eventName","ngTouch","directive","$parse","$swipe","MAX_VERTICAL_DISTANCE","MAX_VERTICAL_RATIO","MIN_HORIZONTAL_DISTANCE","scope","element","attr","validSwipe","coords","startCoords","deltaY","Math","abs","y","deltaX","x","valid","swipeHandler","bind","start","event","cancel","end","$apply","triggerHandler","module","factory","getCoordinates","touches","length","e","changedTouches","originalEvent","clientX","clientY","eventHandlers","totalX","totalY","lastPos","active","on","MOVE_BUFFER_RADIUS","preventDefault","config","$provide","decorator","$delegate","shift","$timeout","$rootElement","checkAllowableRegions","touchCoordinates","i","x1","CLICKBUSTER_THRESHOLD","y1","splice","onClick","Date","now","lastPreventedTime","PREVENT_DURATION","lastLabelClickCoordinates","target","tagName","toLowerCase","stopPropagation","blur","onTouchStart","push","ACTIVE_CLASS_NAME","resetState","tapping","removeClass","clickHandler","ngClick","tapElement","startTime","touchStartX","touchStartY","srcElement","nodeType","parentNode","addClass","diff","dist","sqrt","pow","TAP_DURATION","MOVE_TOLERANCE","addEventListener","isDefined","disabled","onclick","element.onclick","touchend"]
8 | }
9 |
--------------------------------------------------------------------------------
/js/controllers/object.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Controller for object template.
3 | */
4 |
5 | app.controller('ObjectCtrl', ['$scope', '$routeParams', '$location', '$sce', 'resolvedNotes', 'segmentio', '$rootScope', 'miaMediaMetaAdapter', 'miaObjectMetaAdapter', 'miaThumbnailAdapter', 'email', 'envConfig', '$timeout', 'resolvedObjectMeta',
6 | function($scope, $routeParams, $location, $sce, notes, segmentio, $rootScope, mediaMeta, objectMetaAdapter, miaThumbs, email, config, $timeout, objectMeta) {
7 | // Defaults
8 | $scope.movedZoomer = false;
9 | $scope.currentAttachment = null;
10 | $scope.contentMinimized = window.outerWidth < 1024;
11 | $scope.enableSharing = config.miaEmailSharingActive
12 | $scope.translucent = false;
13 |
14 | $scope.id = $routeParams.id
15 | $rootScope.lastObjectId = $scope.id = $routeParams.id
16 |
17 | _wp = notes
18 | $scope.wp = _wp.objects[$scope.id]
19 | segmentio.track('Browsed an Object', {id: $scope.id, name: $scope.wp.title})
20 |
21 | $scope.wp.meta3 = $sce.trustAsHtml( $scope.wp.meta3 );
22 |
23 | // Replace object metadata if using adapter
24 | if( objectMetaAdapter.isActive ) {
25 | $scope.wp.meta1 = $scope.wp.meta1 || objectMeta.meta1;
26 | $scope.wp.meta2 = $scope.wp.meta2 || objectMeta.meta2;
27 | $scope.wp.meta3 = $scope.wp.meta3 || objectMeta.meta3;
28 | $scope.wp.location = objectMeta.location;
29 | }
30 |
31 | $scope.relatedStories = []
32 | angular.forEach($scope.wp.relatedStories, function(story_id){
33 | if( _wp.stories[story_id] ) {
34 | $scope.relatedStories.push({
35 | 'id':story_id,
36 | 'title':_wp.stories[story_id].title
37 | })
38 | }
39 | })
40 | if($scope.wp) {
41 | $scope.mainImage = $scope.wp.views[0].image
42 | $scope.wp.trustedDescription = $sce.trustAsHtml($scope.wp.description)
43 | $scope.$on('viewChanged', loadDetails)
44 | $scope.$watch('mapLoaded', function(v) { v && loadDetails() }) // TODO: once details load, cancel this watch
45 |
46 | // Open the More tab when returning from a story via the 'Back' button
47 | if($rootScope.nextView) {
48 | $scope.activeSection = $rootScope.nextView
49 | $rootScope.nextView = undefined
50 | // make sure the drawer is open, if we have one
51 | var drawer = angular.element($('.object-content-container')).scope().drawerify
52 | if(drawer) drawer.to('open', 0)
53 | }
54 | $scope.$$phase || $scope.$apply()
55 |
56 | }
57 |
58 | var loadDetails = function() {
59 | $scope.notes = $scope.wp.views;
60 | $scope.allNotes = [];
61 | $scope.allAttachments = [];
62 | angular.forEach($scope.notes, function(view) {
63 | angular.forEach(view.annotations, function(ann) {
64 | ann.trustedDescription = $sce.trustAsHtml(ann.description)
65 | ann.view = view;
66 | $scope.allNotes.push( ann );
67 |
68 | // Replace attachment metadata if using adapter
69 | angular.forEach( ann.attachments, function(att) {
70 | att.thumbnail = miaThumbs.get(att.image_id)
71 | if( mediaMeta.isActive ) {
72 | // Hacky! We need to only trustAsHtml(att.meta) once. Or find a better way generally.
73 | att.meta = mediaMeta.get( att.image_id ) || ( typeof att.meta === 'object' ? att.meta : $sce.trustAsHtml(att.meta) );
74 | }
75 | att.trustedDescription = $sce.trustAsHtml(att.description);
76 | $scope.allAttachments.push( att );
77 | })
78 |
79 | })
80 | })
81 | $scope.$$phase || $scope.$apply()
82 | }
83 |
84 | $scope.next = function(direction) {
85 | var next = $scope.objects.ids[$scope.objects.ids.indexOf(parseInt($scope.id))+1]
86 | if(next) $location.url('/o/'+next)
87 | }
88 | $scope.prev = function(direction) {
89 | var prev = $scope.objects.ids[$scope.objects.ids.indexOf(parseInt($scope.id))-1]
90 | if(prev) $location.url('/o/'+prev)
91 | }
92 |
93 | $scope.viewEnabled = function(nextView, debug) {
94 | return (nextView == 'more' && $scope.relatedStories && $scope.relatedStories.length > 0 ||
95 | nextView == 'annotations' && getFirstDetail() ||
96 | nextView == 'about')
97 | }
98 |
99 | // return the first annotation, falsey if there aren't any
100 | function getFirstDetail() {
101 | var i = 0, view = $scope.notes && $scope.notes[i], firstDetail
102 | while(view && view.annotations.length == 0) {
103 | view = $scope.notes && $scope.notes[i]
104 | i++
105 | }
106 | firstDetail = view && view.annotations && view.annotations[0]
107 | return firstDetail
108 | }
109 |
110 | $scope.toggleView = function(nextView, dontTrack) {
111 | if(!dontTrack) segmentio.track('Changed Sections within an Object', {view: nextView})
112 | nextView = nextView || 'about'
113 | if(!$scope.viewEnabled(nextView)) return
114 | if(nextView == 'annotations') {
115 | if(!$scope.notes) $scope.notes = $scope.wp.views
116 | var firstDetail = getFirstDetail()
117 |
118 | if(firstDetail && !$scope.flatmapScope.lastActiveNote) {
119 | $scope.activateNote(firstDetail, $scope.notes[0])
120 | } else if($scope.flatmapScope.lastActiveNote) {
121 | // If there's an active annotation, center the map over it.
122 | $scope.glanceText = $sce.trustAsHtml( "Press to view detail " + $scope.flatmapScope.lastActiveNote.index + " " );
123 | if(!$scope.flatmapScope.zoom.map.getBounds().contains($scope.flatmapScope.jsonLayer.getBounds())) {
124 | $scope.$broadcast('changeGeometry', $scope.flatmapScope.lastActiveNote.geoJSON.geometry)
125 | }
126 | }
127 | } else {
128 | $scope.glanceText = $sce.trustAsHtml( "Press to view object" );
129 | }
130 | // Reset image to the primary when changing back to about
131 | if(nextView == 'about' && $scope.flatmapScope && $scope.notes[0].image != $scope.flatmapScope.image) {
132 | $scope.activateView($scope.notes[0])
133 | }
134 | $scope.activeSection = nextView
135 | }
136 |
137 | $scope.toggleAttachment = function(attachment, closeAttachmentIfOpen, $event){
138 | if($scope.currentAttachment==attachment){
139 | if(!closeAttachmentIfOpen) return;
140 | $scope.currentAttachment = $scope.showAttachmentCredits = null;
141 | } else {
142 | $scope.currentAttachment = attachment;
143 | $scope.showAttachmentCredits = false
144 | setTimeout(Zoomer.windowResized, 0);
145 | }
146 | if($event) $event.stopPropagation();
147 | }
148 | $scope.toggleAttachmentCredits = function(attachment) {
149 | $scope.showAttachmentCredits = !$scope.showAttachmentCredits
150 | setTimeout(Zoomer.windowResized, 125)
151 | }
152 |
153 | $scope.toggleView($scope.activeSection, true)
154 | $scope.$on('showAnnotationsPanel', function(view) {
155 | $scope.activeSection = 'annotations'
156 | })
157 |
158 | $scope.changeZoomerForViews = function(map, flatmapScope) {
159 | $scope.$apply(function() { $scope.showViews = true })
160 | }
161 |
162 | $scope.activateNote = function(note, view) {
163 | /*
164 | $scope.translucent = true;
165 | */
166 | $scope.showViews = false
167 | $scope.activeView = view
168 | note.active = !note.active
169 | $scope.glanceText = $sce.trustAsHtml( "Press to view detail " + note.index + " " );
170 | /*
171 | $timeout( function(){
172 | $scope.translucent = false;
173 | }, 1000 );
174 | */
175 | }
176 |
177 | $scope.deactivateAllNotes = function() {
178 | angular.forEach($scope.notes, function(view) {
179 | angular.forEach(view.annotations, function(ann) { ann.active = false; })
180 | })
181 | $scope.$$phase || $scope.$apply()
182 | }
183 |
184 | $scope.activateView = function(view) {
185 | // TODO: encapsulate active view the same way I do notes, with view.active?
186 | $scope.showViews = false
187 | $scope.activeView = view
188 | $scope.deactivateAllNotes()
189 |
190 | $scope.flatmapScope.$broadcast('changeView', view)
191 | }
192 | $scope.activateViewAndShowFirstAnnotation = function(view) {
193 | $scope.activateView(view)
194 | var note = view.annotations[0]
195 | if(note) activateNote(note)
196 | }
197 |
198 | $scope.toggleSixbar = function(element) {
199 | $scope.sixBarClosed = !$scope.sixBarClosed
200 | setTimeout(Zoomer.windowResized, 0)
201 | }
202 |
203 | $scope.toggleExtendedTombstone = function(event) {
204 | $scope.showExtendedTombstone = !$scope.showExtendedTombstone
205 | $scope.$broadcast( 'recalculateCustomDrawerStates' );
206 | if(event) event.stopPropagation()
207 | }
208 |
209 | $scope.toggleMinimizeContent = function() {
210 | $scope.contentMinimized = !$scope.contentMinimized;
211 | //setTimeout( Zoomer.windowResized, 125); // Zoomer now stays put behind content
212 | }
213 |
214 | $scope.glanceText = $sce.trustAsHtml( "Press to view object" );
215 | }
216 | ])
217 |
218 |
--------------------------------------------------------------------------------
/js/vendor/angular-route.min.js.map:
--------------------------------------------------------------------------------
1 | {
2 | "version":3,
3 | "file":"angular-route.min.js",
4 | "lineCount":13,
5 | "mappings":"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",
6 | "sources":["angular-route.js"],
7 | "names":["window","angular","undefined","ngViewFactory","$route","$anchorScroll","$animate","link","scope","$element","attr","ctrl","$transclude","cleanupLastView","previousElement","remove","currentScope","$destroy","currentElement","leave","update","locals","current","isDefined","$template","newScope","$new","clone","enter","onNgViewEnter","autoScrollExp","$eval","$emit","onloadExp","autoscroll","onload","$on","ngViewFillContentFactory","$compile","$controller","html","contents","controller","$scope","controllerAs","data","children","ngRouteModule","module","provider","$RouteProvider","inherit","parent","extra","extend","pathRegExp","path","opts","insensitive","caseInsensitiveMatch","ret","keys","replace","_","slash","key","option","optional","star","push","regexp","RegExp","routes","when","this.when","route","redirectPath","length","substr","otherwise","this.otherwise","params","$get","$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache","$sce","updateRoute","next","parseRoute","last","$$route","equals","pathParams","reloadOnSearch","forceReload","copy","$broadcast","redirectTo","isString","interpolate","search","url","then","resolve","template","templateUrl","forEach","value","get","invoke","isFunction","getTrustedResourceUrl","loadedTemplateUrl","response","all","error","match","m","exec","on","i","len","val","decodeURIComponent","name","string","result","split","segment","segmentMatch","join","reload","$evalAsync","$RouteParamsProvider","this.$get","directive","$inject"]
8 | }
9 |
--------------------------------------------------------------------------------
/fonts/fontello/demo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
231 |
232 |
233 |
245 |
246 |
247 |
256 |
257 |
258 |
icon-resize-full 0xe800
259 |
icon-resize-normal 0xe801
260 |
icon-home 0xe802
261 |
icon-menu 0xe803
262 |
263 |
264 |
icon-left-open 0xe804
265 |
icon-right-open 0xe805
266 |
icon-left 0xe806
267 |
icon-right 0xe807
268 |
269 |
270 |
icon-left-small 0xe808
271 |
icon-right-small 0xe809
272 |
icon-play 0xe80a
273 |
icon-info-circled 0xe80b
274 |
275 |
276 |
icon-info-circled-alt 0xe80c
277 |
icon-cancel-circled 0xe80d
278 |
icon-cancel-circled-outline 0xe80e
279 |
icon-cancel 0xe80f
280 |
281 |
282 |
icon-cancel-outline 0xe810
283 |
icon-pause 0xe811
284 |
icon-back 0xe812
285 |
icon-info 0xe813
286 |
287 |
288 |
icon-doc-text 0xe814
289 |
icon-plus 0xe815
290 |
icon-minus 0xe816
291 |
icon-resize-vertical 0xe817
292 |
293 |
294 |
icon-mail 0xe818
295 |
296 |
297 |
298 |
299 |
--------------------------------------------------------------------------------
/sass/object.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Object template styles.
3 | */
4 |
5 | $sidebarWidth: 23rem;
6 |
7 | /**
8 | * Content - "Above the Fold" (Controls and Meta)
9 | */
10 | .object-content-container{
11 | position:absolute;
12 | top:0;
13 | left:0;
14 | width: $sidebarWidth;
15 | height:100%;
16 | }
17 | .object-content{
18 | @include transition( opacity 500ms ease );
19 | position:absolute;
20 | top:0;
21 | right:0;
22 | bottom:0;
23 | left:0;
24 | margin:0 auto;
25 | background-color:#ededed;
26 | padding:15px;
27 | overflow-x:hidden;
28 | overflow-y:auto;
29 |
30 | &.translucent{
31 | opacity:0;
32 | }
33 |
34 | }
35 |
36 | .object-menu {
37 | display:block;
38 | height:40px;
39 | margin:0;
40 | padding:0;
41 | }
42 | .object-menu > a {
43 | position:relative;
44 | display:block;
45 | float:left;
46 | margin:0 5px 0 0;
47 | }
48 | .object-home-link {
49 | @extend .home-icon;
50 | }
51 | .contentMinimized .object-maximize-content {
52 | background-color: rgba(22, 22, 22, .55);
53 | }
54 |
55 | .object-menu .toggle-meta {
56 | @extend .meta-icon;
57 | }
58 | .object-menu .email {
59 | @extend .meta-icon;
60 | @include icon( '\e818' );
61 | font-size: 21px;
62 | }
63 |
64 | .object-title{
65 | margin:5px 0 0;
66 | }
67 | .meta1{
68 | max-height:0;
69 | margin:0;
70 | overflow:hidden;
71 |
72 | .extended & {
73 | max-height:200px;
74 | }
75 |
76 | @media #{$medium} {
77 | @include transition( max-height 125ms ease );
78 | max-height:none;
79 | }
80 | }
81 | .meta2,
82 | .meta3{
83 | margin:0;
84 | font-size:0.9em;
85 | font-weight:normal;
86 | max-height:0;
87 | overflow:hidden;
88 |
89 | .extended & {
90 | max-height:225px;
91 | }
92 |
93 | @media #{$medium} {
94 | @include transition( max-height 125ms ease );
95 | }
96 | }
97 |
98 |
99 | /**
100 | * Navbar
101 | */
102 | .object-nav {
103 | margin:15px 0 0;
104 | }
105 | .object-nav a {
106 | display:block;
107 | width:33.3%;
108 | float:left;
109 | padding:0.5em 0;
110 | border:1px solid #222;
111 | border-right:none;
112 | color:#222;
113 | text-transform: uppercase;
114 | font-size:0.85em;
115 | font-weight:700;
116 | text-align:center;
117 | background-color: #ededed;
118 | cursor:pointer;
119 |
120 | &.disabled,
121 | &.disabled:hover {
122 | color:#bbb;
123 | background-color:#ededed;
124 | cursor:default;
125 | }
126 |
127 | &:last-child{
128 | border-right:1px solid #222;
129 | }
130 |
131 | &.selected {
132 | color:#ededed;
133 | background-color: #222;
134 | }
135 |
136 | @media #{$medium} {
137 | &:active{
138 | color:#ededed;
139 | background-color: #222;
140 | }
141 | }
142 | }
143 |
144 |
145 | /**
146 | * Content - Container
147 | */
148 | .object-stories{
149 | margin:0;
150 | padding:0;
151 | }
152 |
153 |
154 | /**
155 | * Content - Details/Annotations
156 | */
157 | .object-details{
158 | list-style:none;
159 | padding:0;
160 | }
161 | .annotation{
162 | padding:0 0 15px 0;
163 | position:relative;
164 | }
165 | .annotation-title{
166 | margin:0 0 0 40px;
167 | cursor:pointer;
168 | }
169 | .annotation-title:active {
170 | text-decoration: underline;
171 | }
172 | .annotation-index{
173 | position:absolute;
174 | display:block;
175 | top:0;
176 | left:0;
177 | width:30px;
178 | height:30px;
179 | margin-right:10px;
180 | color:#fff;
181 | background-color:#222;
182 | border-radius:1000px;
183 | border:2px solid #fff;
184 | text-align:center;
185 | line-height:26px;
186 | font-size:1.125rem;
187 |
188 | .glance &{
189 | position:relative;
190 | display:inline-block;
191 | margin:0;
192 | }
193 | }
194 | .annotation-content{
195 | @include transition( max-height 125ms ease );
196 | max-height:0;
197 | overflow:hidden;
198 |
199 | .annotation.active &{
200 | max-height:500px;
201 | }
202 | }
203 | .annotation-content p{
204 | margin:10px 0 0 0;
205 | }
206 |
207 | .annotation-content ul {
208 | margin-top: 10px;
209 | }
210 | .annotation-content ul li {
211 | list-style-type: disc;
212 | margin-left: -1.25em;
213 | }
214 |
215 | /**
216 | * Content - Details/Annotations - Attachments
217 | */
218 | .annotation-attachments{
219 | @include transition( max-height 125ms ease );
220 | max-height:0;
221 | overflow:hidden;
222 | padding:0;
223 | margin:0;
224 |
225 | .annotation.active &{
226 | max-height:500px;
227 | }
228 | }
229 | .annotation-attachments p{
230 | font-size:0.75em;
231 | margin:15px 0 10px;
232 | text-transform:uppercase;
233 | color:#999;
234 | font-weight:bold;
235 | border-top:1px solid #ccc;
236 | }
237 | .attachment-thumb{
238 | display:inline-block;
239 | width:75px;
240 | height:75px;
241 | position:relative;
242 | margin:0 5px 5px 0;
243 | cursor:pointer;
244 | background-size:cover;
245 | }
246 | .attachment-big{
247 | @include transition( left 375ms ease );
248 | display:block;
249 | position:absolute;
250 | width:100%;
251 | height:100%;
252 | left:-300%;
253 | top:0;
254 | background-color:#ddd;
255 | z-index:1000000001;
256 | text-align:center;
257 |
258 | &.active {
259 | left:0;
260 | }
261 | }
262 | .attachment-zoomer{
263 | @include transition( height 125ms ease );
264 | height:100%;
265 |
266 | .showAttachmentMeta & {
267 | height:67%;
268 | }
269 | }
270 | .attachment-big .return-link{
271 | @extend .nav-button;
272 | @extend .nav-button-left;
273 | @extend .return-icon;
274 | position:absolute;
275 | border-top:1px solid #222;
276 | border-right:1px solid #222;
277 | }
278 | .attachment-toggle-meta{
279 | @extend .meta-icon;
280 | position:absolute;
281 | display:block;
282 | right:12px;
283 | bottom:8px;
284 | margin:0;
285 | z-index:4;
286 | }
287 | .attachment-tombstone{
288 | @include transition( bottom 125ms ease );
289 | @include box-shadow( inset 0 5px 5px rgba(0,0,0,0.23));
290 | position:absolute;
291 | right:0;
292 | bottom:-33%;
293 | left:0;
294 | height:33%;
295 | padding:15px 60px;
296 | overflow-y:scroll;
297 | overflow-x:hidden;
298 | font-size:0.9em;
299 | text-align:left;
300 | background-color:#ededed;
301 | color:#444;
302 |
303 | .showAttachmentMeta & {
304 | bottom:0;
305 | }
306 | }
307 | .attachment-content{
308 |
309 | }
310 |
311 |
312 | /**
313 | * Content - Stories/"More"
314 | */
315 | .more-title {
316 | margin:15px 0 0;
317 | text-transform:uppercase;
318 | }
319 |
320 | .object-related{
321 | list-style:none;
322 | padding:0;
323 | }
324 | .object-related a{
325 | color:#222;
326 | width:100%;
327 | border:1px solid #222;
328 | padding:10px 15px;
329 | display:block;
330 | margin:5px 0px;
331 | text-align:left;
332 | font-size:1em;
333 | transition:all 250ms linear;
334 | text-decoration: none;
335 |
336 | @media screen and (min-width:1025px) {
337 | &:hover {
338 | color:#ededed;
339 | background-color:#222;
340 | }
341 | }
342 | &:active {
343 | color:#ededed;
344 | background-color:#222;
345 | }
346 | }
347 |
348 |
349 | /**
350 | * Zoomer
351 | */
352 | .object-zoomer {
353 | @include box-shadow( 0px 3px 5px rgba(0,0,0,0.23) );
354 | @include transition( opacity 125ms ease );
355 | position:absolute;
356 | top:0;
357 | right:0;
358 | bottom:0;
359 | left:0;
360 | background-color:#ccc;
361 | text-align:center;
362 |
363 | @media #{$medium} {
364 | left: $sidebarWidth;
365 | }
366 | }
367 |
368 |
369 | /*
370 | * Zoomer - Markers
371 | */
372 | .leaflet-overlay-pane,
373 | .leaflet-marker-pane{
374 | display:none;
375 |
376 | .object-zoomer.annotations & {
377 | display:block;
378 | }
379 | }
380 | .noteMarker {
381 | @include transition( all 125ms ease );
382 | padding: 3em;
383 | margin: -3em !important;
384 | text-align: center;
385 | font-family: 'MiaGrotesk-Light', sans-serif;
386 | font-weight: bold;
387 | font-size: 1em ;
388 | color: #fff;
389 | z-index:1000000 !important;
390 | }
391 | .noteMarker span {
392 | @include transition( all 125ms ease );
393 | display: block;
394 | height: 30px;
395 | width: 30px;
396 | margin: -15px 0 0 -15px;
397 | padding: 0;
398 | border-radius: 1000px;
399 | border: 2px solid #fff;
400 | font-weight: bold;
401 | text-align: center;
402 | font-size: 1.125rem;
403 | background-color: rgba(22, 22, 22, .55);
404 | line-height:26px;
405 | vertical-align:middle;
406 | }
407 | .noteMarker:hover span, .noteMarker:active span {
408 | width:36px;
409 | height:36px;
410 | margin: -18px 0 0 -18px;
411 | line-height:34px;
412 | }
413 |
414 | // Toggle 'show all views' control
415 | .object-zoomer .flatmap > div:first-child {
416 | z-index: 100;
417 | width: 100%;
418 | margin: 0;
419 | padding: 0;
420 | }
421 | .object-zoomer .flatmap .view {
422 | margin-left: -100em;
423 | @include transition(margin 125ms ease-out);
424 | }
425 | .showAllViews .object-zoomer .flatmap .view {
426 | display: inline;
427 | min-height: 3em;
428 | margin-left: 0;
429 | @include transition(margin 125ms ease);
430 | }
431 | .object-zoomer aside {
432 | display: none;
433 | font-size: 1.25em;
434 | font-weight: bold;
435 | }
436 | .showAllViews aside {
437 | display: block !important;
438 | }
439 |
440 | // Transition the leaflet pane away
441 | .object-zoomer .flatmap .leaflet-map-pane {
442 | @include transition(-webkit-transform 125ms ease-out);
443 | }
444 | .showAllViews .object-zoomer .flatmap .leaflet-map-pane {
445 | -webkit-transform: scale(0.25) translateX(-1234px) !important;
446 | }
447 |
448 | .more-views a, a.view {
449 | height: 8em;
450 | width: 32.8%;
451 | margin: 0.5% 0.5% 0 0;
452 | background-size: cover;
453 | background-position: 50% 15%;
454 | display: block;
455 | float: left;
456 | // margin-bottom: 1px;
457 |
458 | &.open, &:hover {
459 | border: 5px solid rgba(255, 255, 255, 0.6);
460 | }
461 | }
462 | .object-zoomer .flatmap a.view {
463 | height: 17em;
464 | }
465 | .leaflet-control-container *{
466 | @include transition(opacity 125ms ease-out);
467 | }
468 | .showAllViews .object-zoomer .leaflet-control-container .leaflet-right {
469 | opacity: 0;
470 | }
471 |
472 | // Email share form
473 | #share.email form {
474 | margin-top: -0.5em;
475 | max-width: 0;
476 | opacity: 0;
477 | margin-left: 2.5em;
478 | -webkit-transition: all 125ms ease-out;
479 | }
480 |
481 | #share.email.open form {
482 | position: relative;
483 | z-index: 2;
484 | max-width: 33em;
485 | opacity: 1;
486 | }
487 |
488 |
489 | // Hint
490 | .hint-scale{
491 | @include transition( all 300ms ease );
492 | @include transform( scale(1.25) );
493 | position:absolute;
494 | top:50%;
495 | left:50%;
496 | width:250px;
497 | height:250px;
498 | margin-top:-125px;
499 | margin-left:-125px;
500 | padding:25px;
501 | background-color:rgba(0,0,0,0.6);
502 | border-radius:25px;
503 | border:3px solid #fff;
504 | z-index:1;
505 | opacity:0;
506 |
507 | &.visible{
508 | @include transform( scale(1) );
509 | opacity:1;
510 | }
511 | }
512 |
513 | .object-about .galleryLocation {
514 | text-align: center;
515 | border-top: 1px solid #ccc;
516 | margin-top: -0.5em;
517 | padding-top: 0.75em;
518 | }
519 | .galleryLocation img {
520 | border: 1px solid #ccc;
521 | max-width: 279px;
522 | }
523 | .galleryLocation img + p {
524 | margin-top: 0.25em;
525 | }
526 |
--------------------------------------------------------------------------------
/sass/generic.scss:
--------------------------------------------------------------------------------
1 | /**
2 | * Site and reusable element styles.
3 | */
4 |
5 | *,
6 | *:before,
7 | *:after {
8 | @include box-sizing( border-box );
9 | }
10 |
11 |
12 | html,
13 | body {
14 | position:fixed;
15 | width:100%;
16 | height:100%;
17 | margin: 0;
18 | padding: 0;
19 | font-size: 100%;
20 | text-rendering:optimizeLegibility;
21 | -moz-font-feature-settings:"kern=0";
22 | -webkit-font-feature-settings:"kern" 0;
23 | -o-font-feature-settings:"kern" 0;
24 | -ms-font-feature-settings:"kern" 0;
25 | font-feature-settings:"kern" 0;
26 | -webkit-text-size-adjust: 100%; /* Prevent font scaling in landscape while allowing user zoom */
27 | }
28 |
29 | /* Container styles */
30 | .container {
31 | @include transition( opacity 150ms ease );
32 | position:absolute;
33 | top:0;
34 | left:0;
35 | width:100%;
36 | height:100%;
37 | overflow:hidden;
38 | }
39 |
40 | /* Fluid images */
41 |
42 | img,
43 | object {
44 | max-width: 100%;
45 | outline:0;
46 | border:0;
47 | margin:0;
48 | padding:0;
49 | }
50 |
51 | /* Remove link highlighting */
52 | a {
53 | -webkit-tap-highlight-color: transparent;
54 | }
55 |
56 | /* Clearfix */
57 |
58 | .clearfix:after {
59 | content: ".";
60 | visibility: hidden;
61 | display: block;
62 | height: 0;
63 | clear: both;
64 | }
65 |
66 | * html .clearfix { zoom: 1; } /* IE6 */
67 | *:first-child+html .clearfix { zoom: 1; } /* IE7 */
68 |
69 | /* Vertical centering */
70 |
71 | .vcenter-table {
72 | display:table;
73 | width:100%;
74 | height:100%;
75 | }
76 | .vcenter-cell {
77 | display:table-cell;
78 | vertical-align:middle;
79 | }
80 |
81 | /* Type */
82 |
83 | html,
84 | body{
85 | font-family: 'MiaGrotesk-Light', sans-serif;
86 | line-height:1.4;
87 | }
88 |
89 | h1 { font-size: 1.6875em; }
90 | h2 { font-size: 1.375em; }
91 | h3 { font-size: 1.375em; }
92 | h4 { font-size: 1.125em; }
93 | h5 { font-size: 1.125em; }
94 | h6 { font-size: 1em; }
95 |
96 | /* Colors */
97 |
98 | html,
99 | body{
100 | background-color:#ededed;
101 | }
102 |
103 | /* Flatmaps */
104 |
105 | .flatmap {
106 | position:absolute;
107 | top:0;
108 | right:0;
109 | bottom:0;
110 | left:0;
111 | }
112 | .flatmap .hint {
113 | @include transition( opacity 250ms linear );
114 | position: absolute;
115 | right:15px;
116 | bottom:15px;
117 | margin: 0;
118 | padding: 10px;
119 | color: #444;
120 | background: rgba(255, 255, 255, 0.75);
121 | font-style:italic;
122 | white-space:nowrap;
123 | opacity:1;
124 | z-index: 3;
125 |
126 | // Override Leaflet font styles
127 | font-family: 'MiaGrotesk-Light', sans-serif !important;
128 | font-size: 16px !important;
129 | line-height:1.4 !important;
130 |
131 | // TODO: Target non-touch devices
132 | @media screen and (min-width:1025px) {
133 | display:none;
134 | }
135 |
136 | }
137 | .flatmap.zoomed .hint {
138 | opacity: 0;
139 | }
140 |
141 | /**
142 | * Button and Icon styles
143 | *
144 | * @extend these and define positioning and special styling.
145 | */
146 |
147 | .home-icon{
148 | @include icon('\e802');
149 | width:40px;
150 | height:40px;
151 | background-color:#222;
152 | border-radius:1000px;
153 | border:2px solid #fff;
154 | cursor:pointer;
155 |
156 | &:before {
157 | color:#fff;
158 | font-size:18px;
159 | margin-top:-9px;
160 | }
161 | }
162 |
163 | .minimize-icon {
164 | @include icon( '\e801' );
165 | @include transition( margin-top 100ms linear );
166 | width:40px;
167 | height:40px;
168 | border-radius:1000px;
169 | background-color:#222;
170 | border:2px solid #fff;
171 | cursor:pointer;
172 |
173 | &:before{
174 | color:#fff;
175 | font-size:20px;
176 | margin-top:-10px;
177 | }
178 |
179 | .contentMinimized &{
180 | @include icon( '\e800' );
181 |
182 | &:before{
183 | font-size:20px;
184 | margin-top:-10px;
185 | }
186 | }
187 | }
188 |
189 | .maximize-icon {
190 | @include icon( '\e800' );
191 | width:40px;
192 | height:40px;
193 | border-radius:1000px;
194 | background-color:#222;
195 | border:2px solid #fff;
196 | cursor:pointer;
197 |
198 | &:before{
199 | color:#fff;
200 | font-size:20px;
201 | margin-top:-10px;
202 | }
203 |
204 | }
205 |
206 | .meta-icon {
207 | @include icon( '\e813' );
208 | @include transition( all 125ms ease );
209 | width:40px;
210 | height:40px;
211 | background-color:#222;
212 | border-radius:1000px;
213 | border:2px solid #fff;
214 |
215 | // Icon
216 | &:before{
217 | color:#fff;
218 | font-size:20px;
219 | margin-top:-10px;
220 | }
221 |
222 | &.open,
223 | .showAttachmentMeta &{
224 | background-color:#fff;
225 | border-color:#222;
226 |
227 | // Icon
228 | &:before{
229 | color:#222;
230 | }
231 | }
232 | }
233 |
234 | .home-icon, .minimize-icon, .maximize-icon, .meta-icon {
235 | &:hover, &:active {
236 | border: 2px solid #222;
237 | }
238 | }
239 |
240 | /**
241 | * Navigation
242 | */
243 | .nav-button {
244 | position:fixed;
245 | margin-top:0;
246 | padding:10px 5px 5px;
247 | background-color:#222;
248 | color:#fff;
249 | font-size:0.7em;
250 | text-transform:uppercase;
251 | text-align:center;
252 | cursor:pointer;
253 | z-index:3;
254 |
255 | // -- rev -- //
256 | // top:50%;
257 | // width:45px;
258 | // height:45px;
259 | padding:0;
260 | width:70px;
261 | height:40px;
262 | border-width:0;
263 |
264 | // Icon
265 | &:before{
266 | top:50%;
267 | font-size:24px;
268 | margin-top:-12px;
269 | }
270 |
271 | @media #{$medium} {
272 | top:50%;
273 | width:60px;
274 | height:80px;
275 | margin-top:-40px;
276 | border:1px solid #222;
277 |
278 | &:before{
279 | margin-top:-24px;
280 | }
281 |
282 | &:after{
283 | position:relative;
284 | display:block;
285 | top:50%;
286 | width:80%;
287 | margin:5px auto 0;
288 | text-align:center;
289 | line-height:12px;
290 | }
291 | }
292 | }
293 | .nav-button-left {
294 | left:0;
295 | bottom:0;
296 | border-left:none;
297 | }
298 | .nav-button-right {
299 | right:0;
300 | bottom:0;
301 | border-right:none;
302 | }
303 | .prev-icon {
304 | @include icon( '\e808' );
305 |
306 | // Icon
307 | &:before{
308 | // -- rev -- //
309 | /*
310 | top:auto;
311 | bottom:10px;
312 | left:0;
313 | */
314 | }
315 |
316 | @media #{$medium} {
317 | // Text
318 | &:after{
319 | content:'Prev Page';
320 | }
321 | }
322 | }
323 | .next-icon {
324 | @include icon( '\e809' );
325 |
326 | // Icon
327 | &:before{
328 | // -- rev -- //
329 | /*
330 | top:auto;
331 | bottom:10px;
332 | left:0;
333 | */
334 | }
335 |
336 | @media #{$medium} {
337 | // Text
338 | &:after{
339 | content:'Next Page';
340 | }
341 | }
342 | }
343 | .return-icon {
344 | @include icon( '\e812' );
345 | background-color:#fff;
346 | color:#000;
347 |
348 | &.nav-button-left {
349 | // -- rev -- //
350 | // border-right:1px solid #ccc;
351 | }
352 |
353 | &.nav-button-right {
354 | // -- rev -- //
355 | // border-left:1px solid #ccc;
356 | }
357 |
358 | // Icon
359 | &:before{
360 | // -- rev -- //
361 | /*
362 | top:auto;
363 | bottom:10px;
364 | left:0;
365 | color:#222;
366 | */
367 | }
368 |
369 | @media #{$medium} {
370 | // Text
371 | &:after{
372 | content:'Back';
373 | }
374 | &.nav-button-left {
375 | border-right:1px solid #222;
376 | }
377 | &.nav-button-right {
378 | border-left:1px solid #222;
379 | }
380 | }
381 |
382 | &:active {
383 | color: #eee;
384 | }
385 | }
386 | .fullscreen-icon {
387 | @include icon('\e800');
388 | position:absolute;
389 | display:block;
390 | top:80px;
391 | right:10px;
392 | width:30px;
393 | height:30px;
394 | background-color:#222;
395 | border:2px solid #fff;
396 | border-radius:1000px;
397 | z-index:1001;
398 |
399 | &:before{
400 | color:#fff;
401 | font-size:16px;
402 | margin-top:-8px;
403 | }
404 |
405 | .contentMinimized &{
406 | background-color:#fff;
407 | border-color:#222;
408 | @include icon('\e801');
409 |
410 | &:before{
411 | color:#222;
412 | font-size:16px;
413 | margin-top:-8px;
414 | }
415 | }
416 | }
417 |
418 | .scrollable{
419 | -webkit-overflow-scrolling: touch;
420 | }
421 |
422 | %drawer{
423 | @include transition( opacity 400ms 200ms ease );
424 | @include box-shadow( 0 -5px 10px rgba(0,0,0,0.13) );
425 | position:absolute;
426 | top:100%;
427 | right:0;
428 | width:100%;
429 | max-width:24rem;
430 | padding:0 15px;
431 | z-index:2;
432 | background-color:#ededed;
433 |
434 | #object &{
435 | bottom:0;
436 | }
437 |
438 | #story &{
439 | bottom:40px;
440 | }
441 |
442 | @media #{$small} {
443 | @include box-shadow( 5px 0 10px rgba(0,0,0,0.13) );
444 | top:0;
445 | right:auto;
446 | left:-24rem;
447 |
448 | #story &{
449 | top:40px;
450 | bottom:0;
451 | }
452 | }
453 |
454 | @media #{$medium} {
455 | top:0;
456 | right:auto;
457 | bottom:0;
458 | left:0;
459 | }
460 | }
461 |
462 | %handle{
463 | // Base styles
464 | @include icon( '\e817' );
465 | display:block;
466 | width:70px;
467 | height:70px;
468 | background-color:rgba(237,237,237,0.4);
469 | &:before{
470 | font-size:30px;
471 | margin-top:-15px;
472 | }
473 |
474 | // Size and positioning
475 | position:fixed;
476 | margin:0;
477 | right:0;
478 | z-index:1;
479 |
480 | #object &{
481 | bottom:0;
482 | }
483 |
484 | #story &{
485 | bottom:40px;
486 | }
487 |
488 | @media #{$smallPortrait}{
489 | &.attached{
490 | position:absolute;
491 | top:0;
492 | bottom:auto;
493 | background-color:transparent;
494 | }
495 | }
496 |
497 | @media #{$small} {
498 | &:before{
499 | @include transform( rotate( 90deg ) );
500 | }
501 |
502 | // Size and positioning
503 | // On landscape and medium screens, button is attached regardless of class
504 | position:absolute;
505 | top:auto;
506 | right:-70px;
507 | bottom:0;
508 | left:auto;
509 | }
510 |
511 | @media #{$medium}{
512 | display:none;
513 | }
514 | }
515 |
516 | .glance {
517 | @include transition( opacity 300ms ease );
518 | @include transform( translate3d( 0, 0, 0 ) );
519 | @include no-select;
520 | @include box-shadow( inset 0 -10px 10px -5px rgba(0,0,0,0.4));
521 | background-color:rgba(255,255,255,0.65);
522 | position:absolute;
523 | display:none;
524 | width:100%;
525 | height:80px;
526 | top:-80px;
527 | left:0;
528 | margin:0;
529 | opacity:0;
530 | z-index:-1000;
531 |
532 | .drawerify-vertical.drawerify-full &{
533 | display:block;
534 | }
535 |
536 | .drawerify-open &{
537 | z-index:1;
538 | opacity:1;
539 | }
540 |
541 | p{
542 | @include no-select;
543 | margin:10px;
544 | border-radius:10px;
545 | line-height:60px;
546 | vertical-align:middle;
547 | font-weight:bold;
548 | font-size:1.25em;
549 | text-align:center;
550 | }
551 |
552 | &.translucent{
553 | opacity:0;
554 | }
555 |
556 | @media #{$small}{
557 | display:none;
558 | }
559 |
560 | &:active {
561 | -webkit-tap-highlight-color: rgba(0,0,0,0);
562 | }
563 |
564 | .drawerify-drawer.drawerify-closed &,
565 | .drawerify-drawer.drawerify-info & {
566 | display: none;
567 | }
568 | }
569 |
570 |
571 |
--------------------------------------------------------------------------------