diff --git a/client/src/css/abovetheline.css b/client/src/css/abovetheline.css index 0cbfd55..1645bbd 100644 --- a/client/src/css/abovetheline.css +++ b/client/src/css/abovetheline.css @@ -9,8 +9,8 @@ html{ body{ - font-size: 12px; - line-height: 20px; + font-size: 13px; + line-height: 24px; color: #1d1d1d; height: 100%; overflow: hidden; diff --git a/client/src/css/patch.css b/client/src/css/patch.css index 268004e..733975a 100644 --- a/client/src/css/patch.css +++ b/client/src/css/patch.css @@ -22,6 +22,12 @@ a.with-number{ cursor:pointer; } +header ul.menu ul.dropdown-menu li a{ + line-height: 20px; + line-height: 2em; + padding: 5px 0; +} + header ul.menu li a{ line-height: 70px; color: #8A8A8A; diff --git a/client/src/css/style.css b/client/src/css/style.css index a680162..6c37454 100644 --- a/client/src/css/style.css +++ b/client/src/css/style.css @@ -96,6 +96,10 @@ header ul.dropdown-menu li{ padding: 0 15px; } +header ul.dropdown-menu li a{ + line-height: 20px +} + a#header-title { color: #151515 ; margin-right: 50px; @@ -1948,6 +1952,11 @@ li.CodeMirror-hint-active { height: 18px; } +.btn.with-fa .fa{ + line-height: 17px; + font-size: 12px; +} + .btn.expanded { font-size: 13px; padding: 10px 20px; @@ -6821,12 +6830,17 @@ g.note.manual .note-borders{ max-width: 400px; border-radius: 3px; background: #383838; + box-shadow: 0 5px 10px rgba(0,0,0,.175); } .tour-tip p { color: #A9A2A2; } +.tour-tip p strong{ + color: white; +} + .tour-tip .tour-arrow { display: block; diff --git a/client/src/files.js b/client/src/files.js index eb47596..d2881d1 100644 --- a/client/src/files.js +++ b/client/src/files.js @@ -40,6 +40,7 @@ module.exports = { '/js/lib/angular-route.min.js', '/js/lib/angular-resource.min.js', '/js/lib/angular-cookies.min.js', + '/js/lib/angular-sanitize.min.js', '/js/lib/angular-local-storage.min.js', // translation mechanism diff --git a/client/src/js/app.js b/client/src/js/app.js index d2a65ff..b60a00f 100644 --- a/client/src/js/app.js +++ b/client/src/js/app.js @@ -26,6 +26,7 @@ angular 'ui.router', 'ngRoute', 'ngResource', + 'ngSanitize', 'ngCookies', 'ui.bootstrap', 'pascalprecht.translate',// angular-translate @@ -51,12 +52,14 @@ angular ANNOTATOR_HIDDEN: 'annotationEditorHidden', INFINITE_SCROLL: 'infinite_scroll', // proper angular events (directives needs to be alerted) - LOCATION_CHANGE_START: 'LOCATION_CHANGE_START', - STATE_CHANGE_SUCCESS: 'STATE_CHANGE_SUCCESS', + LOCATION_CHANGE_START: 'location_change_start', + STATE_CHANGE_SUCCESS: 'state_change_success', - STATE_VIEW_CONTENT_LOADED: 'STATE_VIEW_CONTENT_LOADED', + STATE_VIEW_CONTENT_LOADED: 'state_view_content_loaded', // sigma spefcific events - SIGMA_SET_ITEM: 'sigma_set_item' + SIGMA_SET_ITEM: 'sigma_set_item', + // start tour + START_GUIDED_TOUR: 'start_guided_tour', }) .constant("VIZ", { TIMELINE: 'timeline' @@ -94,11 +97,13 @@ angular */ .config(function ($translateProvider) { // $translateProvider.useMissingTranslationHandlerLog(); + $translateProvider.useSanitizeValueStrategy('sanitize'); $translateProvider.useStaticFilesLoader({ prefix: 'locale/locale-',// path to translations files suffix: '.json'// suffix, currently- extension of the translations }); $translateProvider.preferredLanguage('en_US');// is applied on first load + }) /* Local-storage module config. cfr diff --git a/client/src/js/controllers/core.js b/client/src/js/controllers/core.js index e15e513..2c06c07 100644 --- a/client/src/js/controllers/core.js +++ b/client/src/js/controllers/core.js @@ -83,6 +83,12 @@ angular.module('histograph') return $state; } + /* + force start the guided tour + */ + $scope.startGuidedTour = function() { + $rootScope.$emit(EVENTS.START_GUIDED_TOUR); + } // the current search query, if any // $scope.query = $routeParams.query || ''; diff --git a/client/src/js/controllers/guided-tour.js b/client/src/js/controllers/guided-tour.js index cfce762..6ea42fc 100644 --- a/client/src/js/controllers/guided-tour.js +++ b/client/src/js/controllers/guided-tour.js @@ -7,27 +7,44 @@ * */ angular.module('histograph') - .controller('GuidedTourCtrl', function ($rootScope, $scope, $log, $timeout, EVENTS) { + .controller('GuidedTourCtrl', function ($rootScope, $scope, $log, $timeout, localStorageService, EVENTS) { + 'use-strict'; $log.debug('GuidedTourCtrl ready'); $scope.currentStep = -1; $scope.currentView; - $scope.enable = true; // load from settings + $scope.enabled = true; // load from settings + $scope.consumed = false; + $scope.ignoreSkipTip = false; + $scope.steps = { 'explore.resources': { - title: 'The gallery', + title: 'The gallery', // default titles steps: [ - 0,1, 11 + { + id: 0, + title: 'Welcome to Histograph' + }, 1,2,3,{ + id: 4, + title: 'timeline' + },5 ] }, 'resource.resources': { + title: 'The resource page', steps: [ - 5,6 + 7,8,9,10,11,14 ] }, 'explore.projection': { + title: 'The graph view', // default titles + steps: [ + 12 + ] + }, + 'skip-tour': { steps: [ - 10 + 13 ] } }; @@ -35,6 +52,50 @@ angular.module('histograph') var currentState, __promise; + /* + Load the guided tour status from your local storage, if available. + Global guided tour can be disabled via cookies. + */ + $scope.loadCursors = function () { + var cursors = localStorageService.get('guidedtour'); + if(!cursors) { + $log.log('GuidedTourCtrl -> loadCursors(), filling localstorage ...'); + $scope.saveCursors(); + return + } + for(var i in cursors) { + + if($scope.steps[i]) { + $scope.steps[i].cursor = isNaN(cursors[i].cursor)? 0: cursors[i].cursor; + $scope.steps[i].consumed = cursors[i].consumed; + } + } + + if(cursors.enabled) + $scope.enabled = (!!cursors.enabled) || true; + // prevent the helper popoup that indicates how to start over to appear twice + if(cursors.ignoreSkipTip) { + $scope.ignoreSkipTip = true; + } + $log.log('GuidedTourCtrl -> loadCursors() - cursors:', cursors, '- enable:', $scope.enabled, '- steps:', $scope.steps); + + } + + $scope.saveCursors = function() { + var cursors = {}; + for(var i in $scope.steps) { + cursors[i] = { + cursor: $scope.steps[i].cursor || 0, + consumed: $scope.steps[i].consumed + } + } + cursors.enabled = $scope.enabled; + $log.log('GuidedTourCtrl -> saveCursors() - cursors:', cursors, '- enable:', cursors.enabled); + cursors.ignoreSkipTip = $scope.ignoreSkipTip; + localStorageService.set('guidedtour', cursors); + } + + /* According to the view we are in */ @@ -44,34 +105,100 @@ angular.module('histograph') $scope.previousStep = function() { - $scope.moveTo($scope.steps[currentState].cursor - 1); + var cursor = Math.max(0, $scope.steps[currentState].cursor - 1); + + if($scope.byebye) { + cursor++; + $scope.byebye = false; + } + + $scope.moveTo(cursor); + } + + $scope.finish = function(){ + // save the completion? + $scope.skip(); } + $scope.skip = function() { + $scope.steps[currentState].consumed=true; + $scope.saveCursors(); + + if($scope.ignoreSkipTip){ + $scope.currentStep = -1; + return; + }; + + $scope.currentStep = $scope.steps['skip-tour'].steps[0]; + $scope.hasPrevious = false; + $scope.hasNext = false; + $scope.byebye = true; + $scope.ttTitle = "see you later"; + + } + + $scope.confirmSkip = function(){ + $scope.currentStep = -1; + $scope.ignoreSkipTip=true; + + $scope.saveCursors(); + } + $scope.moveTo = function(index) { $scope.hasPrevious = index > 0; $scope.hasNext = index < $scope.steps[currentState].steps.length - 1; - $scope.currentStep = $scope.steps[currentState].steps[index]; + + + var stepId, + stepTitle; + // if there is a detailed step id + if(typeof $scope.steps[currentState].steps[index] == 'number'){ + stepId = $scope.steps[currentState].steps[index]; + stepTitle = $scope.steps[currentState].title; + } else { + stepId = $scope.steps[currentState].steps[index].id; + stepTitle = $scope.steps[currentState].steps[index].title; + } + + $scope.currentStep = stepId; $scope.steps[currentState].cursor = index; - $log.log('GuidedTourCtrl -> moveTo() cursor:', index, '/', $scope.steps[currentState].steps.length, '- aka touring step n:', $scope.steps[currentState].steps[index], '- has next:', $scope.hasNext, '- has previous:', $scope.hasPrevious ); + - $scope.ttTitle= [ - $scope.steps[currentState].title || '', + $scope.ttTitle= [stepTitle || ''].concat($scope.steps[currentState].steps.length > 1? [ ' (', (+$scope.steps[currentState].cursor + 1), ' of ', $scope.steps[currentState].steps.length, - ')' - ].join(''); + ')']: []).join(''); + + $scope.steps[currentState].consumed = index == $scope.steps[currentState].steps.length - 1; + + $scope.consumed = !!$scope.steps[currentState].consumed; + + $log.log('GuidedTourCtrl -> moveTo() cursor:', index+1, '/', $scope.steps[currentState].steps.length, '- aka touring step id:', stepId, '- has next:', $scope.hasNext, '- has previous:', $scope.hasPrevious, '- consumed:', $scope.steps[currentState].consumed); + $scope.saveCursors(); } + $scope.start = function() { + $log.log('GuidedTourCtrl -> start() state:', currentState) + if(!currentState) + return; + if($scope.forceStart) + $scope.steps[currentState].cursor = 0; // clone; + $scope.forceStart = false; + $scope.byebye = false; + $scope.consumed = false; + $scope.moveTo($scope.steps[currentState].cursor); + } /* Set the current step to the correct number according to the view we are in */ $scope.$on(EVENTS.STATE_CHANGE_SUCCESS, function(){ - $scope.currentStep = -1 + $scope.currentStep = -1; + currentState = false; }); $rootScope.$on(EVENTS.STATE_VIEW_CONTENT_LOADED, function(e, state) { @@ -80,18 +207,26 @@ angular.module('histograph') if(__promise) $timeout.cancel(__promise); - if(!$scope.enable) + if(!$scope.enabled) return; __promise = $timeout(function(){ - if($scope.steps[state.name] && !$scope.steps[state.name].consumed) { - - if(typeof $scope.steps[state.name].cursor == 'undefined') - $scope.steps[state.name].cursor = 0; // clone; - - - - $scope.moveTo($scope.steps[state.name].cursor); + if($scope.steps[state.name] && (!$scope.steps[state.name].consumed || $scope.forceStart)) { + $log.log('GuidedTourCtrl @EVENTS.STATE_VIEW_CONTENT_LOADED ready for', state.name) + $scope.start(); + } else if($scope.steps[state.name] && $scope.steps[state.name].consumed) { + $log.log('GuidedTourCtrl @EVENTS.STATE_VIEW_CONTENT_LOADED nothing to do, the guided tour has already been completed for the', state.name, 'view'); } }, 3500); }); + + $rootScope.$on(EVENTS.START_GUIDED_TOUR, function(){ + $scope.forceStart = true; + $scope.start(); + $log.log('GuidedTourCtrl @EVENTS.START_GUIDED_TOUR', currentState); + }) + + /* + load settings and current cursors from localstorage + */ + $scope.loadCursors(); }); \ No newline at end of file diff --git a/client/src/js/lib/angular-sanitize.min.js b/client/src/js/lib/angular-sanitize.min.js new file mode 100644 index 0000000..3b04e34 --- /dev/null +++ b/client/src/js/lib/angular-sanitize.min.js @@ -0,0 +1,16 @@ +/* + AngularJS v1.4.9 + (c) 2010-2015 Google, Inc. http://angularjs.org + License: MIT +*/ +(function(n,h,p){'use strict';function E(a){var f=[];r(f,h.noop).chars(a);return f.join("")}function g(a,f){var d={},c=a.split(","),b;for(b=0;b=c;d--)f.end&&f.end(e[d]);e.length=c}}"string"!==typeof a&&(a=null===a||"undefined"===typeof a?"":""+a);var b,k,e=[],m=a,l;for(e.last=function(){return e[e.length-1]};a;){l="";k=!0;if(e.last()&&w[e.last()])a=a.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*"+e.last()+"[^>]*>","i"),function(a,b){b=b.replace(H,"$1").replace(I,"$1");f.chars&&f.chars(q(b));return""}),c("",e.last());else{if(0===a.indexOf("\x3c!--"))b=a.indexOf("--",4),0<=b&&a.lastIndexOf("--\x3e", +b)===b&&(f.comment&&f.comment(a.substring(4,b)),a=a.substring(b+3),k=!1);else if(x.test(a)){if(b=a.match(x))a=a.replace(b[0],""),k=!1}else if(J.test(a)){if(b=a.match(y))a=a.substring(b[0].length),b[0].replace(y,c),k=!1}else K.test(a)&&((b=a.match(z))?(b[4]&&(a=a.substring(b[0].length),b[0].replace(z,d)),k=!1):(l+="<",a=a.substring(1)));k&&(b=a.indexOf("<"),l+=0>b?a:a.substring(0,b),a=0>b?"":a.substring(b),f.chars&&f.chars(q(l)))}if(a==m)throw L("badparse",a);m=a}c()}function q(a){if(!a)return"";A.innerHTML= +a.replace(//g,">")}function r(a,f){var d=!1,c=h.bind(a,a.push);return{start:function(a,k,e){a=h.lowercase(a);!d&&w[a]&&(d=a);d||!0!==C[a]||(c("<"),c(a),h.forEach(k,function(d,e){var k=h.lowercase(e),g="img"===a&&"src"===k|| +"background"===k;!0!==O[k]||!0===D[k]&&!f(d,g)||(c(" "),c(e),c('="'),c(B(d)),c('"'))}),c(e?"/>":">"))},end:function(a){a=h.lowercase(a);d||!0!==C[a]||(c(""));a==d&&(d=!1)},chars:function(a){d||c(B(a))}}}var L=h.$$minErr("$sanitize"),z=/^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/,y=/^<\/\s*([\w:-]+)[^>]*>/,G=/([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g,K=/^]*?)>/i, +I=/"\u201d\u2019]/i,d=/^mailto:/i;return function(c,b){function k(a){a&&g.push(E(a))}function e(a, +c){g.push("');k(c);g.push("")}if(!c)return c;for(var m,l=c,g=[],n,p;m=l.match(f);)n=m[0],m[2]||m[4]||(n=(m[3]?"http://":"mailto:")+n),p=m.index,k(l.substr(0,p)),e(n,m[0].replace(d,"")),l=l.substring(p+m[0].length);k(l);return a(g.join(""))}}])})(window,window.angular); +//# sourceMappingURL=angular-sanitize.min.js.map diff --git a/client/src/js/lib/angular-tour-tpls.min.js b/client/src/js/lib/angular-tour-tpls.min.js index 4b56abc..6093b6f 100644 --- a/client/src/js/lib/angular-tour-tpls.min.js +++ b/client/src/js/lib/angular-tour-tpls.min.js @@ -9,17 +9,9 @@ (function (window, document, undefined) { 'use strict'; angular.module('angular-tour', [ - 'angular-tour.tpls', 'angular-tour.tour' ]); - angular.module('angular-tour.tpls', ['tour/tour.tpl.html']); - angular.module('tour/tour.tpl.html', []).run([ - '$templateCache', - function ($templateCache) { - $templateCache.put('tour/tour.tpl.html', - '
\n' + ' \n' + '
\n' + '

\n' + '

\n' + ' \n' + ' \n' + '
\n' + '
\n' + ''); - } - ]); + angular.module('angular-tour.tour', []).constant('tourConfig', { placement: 'top', animation: true, @@ -28,7 +20,8 @@ margin: 28, backDrop: false, useSourceScope: false, - containerElement: 'body' + containerElement: 'body', + templateUrl: 'templates/partials/helpers/guidedtour-popup.html' }).controller('TourController', [ '$scope', 'orderedList', @@ -380,10 +373,10 @@ } }; } - ]).directive('tourPopup', function () { + ]).directive('tourPopup', function (tourConfig) { return { replace: true, - templateUrl: 'tour/tour.tpl.html', + templateUrl: tourConfig.templateUrl, scope: true, restrict: 'EA', link: function (scope, element, attrs) { diff --git a/client/src/locale/locale-en_US.json b/client/src/locale/locale-en_US.json index 8b5d69e..28388eb 100644 --- a/client/src/locale/locale-en_US.json +++ b/client/src/locale/locale-en_US.json @@ -9,12 +9,15 @@ "button.crowd.askmelater": "ask me later", "button.disagree": "I disagree", "button.edit": "edit", + "button.end": "ok, close", + "button.finish": "tour completed!", "button.login.with.twitter": "log in with your twitter account", "button.login.with.google": "log in with your google account", "button.more": "more", "button.next": "next", "button.previous": "previous", "button.myselection.explore": "explore connections", + "button.skip": "skip tour", "crowd.whois": "Do you know who is", "crowd.whois.description": "We miss some basic information about him/her and we're not sure about his/her identity", @@ -33,22 +36,23 @@ "grammar.sorting.date.desc": "by date (most recent first)", "grammar.sorting.date.asc": "by date (oldest first)", - "guided-tour.step.view.gallery": "You can choose between a gallery and a graph view", - "guided-tour.step.view.gallery.resource":"click on a resource", - - "guided-tour.step.filters.timeline": "You can highlight a specific period on the timeline. Drag this selection to observe change over time.", - "guided-tour.step.filters.type": "Both views can be **filtered** according to the type of document, its creation or publication date...", - "guided-tour.step.filters.related-to": "... or you can filter the view by *people*, *locations*, *institutions*, or *themes* you are interested in", - + "guided-tour.welcome": "Welcome to Histograph!

We use cookies to track your usage and preferences", + "guided-tour.skip": "You can access the guided tour from your personal space", + "guided-tour.step.view.gallery": "You can choose between a gallery and a graph view. You are now in the gallery view", + "guided-tour.step.view.gallery.resource":"click on a resource to continue the guided tour", + "guided-tour.step.filters.timeline": "You can highlight a specific period on the timeline. Drag your selection to observe change over time.", + "guided-tour.step.filters.type": "Both views can be filtered according to the type of document, its creation or publication date...", + "guided-tour.step.filters.related-to": "You can also filter by *people*, *locations*, *institutions*, or *themes*", "guided-tour.step.view.graph": "You can select graph views with different types of nodes (e.g. people or locations). A tie between two nodes indicates that they are mentioned together in a document. More frequent co-occurrences are represented by thicker ties. A click on a tie shows the documents which contain the two nodes.", - - "guided-tour.step.view.resource": "you can add this resources to your favourite list or to your current selection", - + + "guided-tour.step.view.resource": "this is a bla bla", + "guided-tour.step.view.resource.favourites": "you can add this resources to your favourite list or to your current selection", "guided-tour.step.view.resource.seealso": "This is the recommended resource list, based on the tag of this document.", - "guided-tour.step.view.resource.seealso.filters": "you can use the filter above to reduce the results in the recommended list", "guided-tour.step.view.resource.add": "you can add relevant people, location etc.. this will improve the results in the recommended section...", "guided-tour.step.view.resource.annotate": "select a text in the title and in the caption of the resource in order to ", + "guided-tour.step.view.resource.click.entity": "guided-tour.step.view.resource.click.entity", + "header.logout" : "log out", "header.myselection": "my selection", diff --git a/client/src/templates/partials/helpers/guidedtour-popup.html b/client/src/templates/partials/helpers/guidedtour-popup.html new file mode 100644 index 0000000..37a4e2b --- /dev/null +++ b/client/src/templates/partials/helpers/guidedtour-popup.html @@ -0,0 +1,33 @@ +
+ + +
\ No newline at end of file diff --git a/client/views/index.jade b/client/views/index.jade index 53a0b6d..3a3912d 100644 --- a/client/views/index.jade +++ b/client/views/index.jade @@ -93,12 +93,19 @@ html //- ul(class='dropdown-menu', role='menu', ) //- li(ng-repeat='lang in availableLanguages', ng-click='setLanguage(lang)') {{lang}} - li - a(href='#/u/'+user.id) - img(src=user.picture) - span {{user.username}} - li - a(href='/logout') logout + li#tip-user + span(uib-dropdown='') + a(uib-dropdown-toggle) + img(src=user.picture) + span {{user.username}} + ul.uib-dropdown-menu.dropdown-menu + li + a(style='cursor:pointer', ng-click='startGuidedTour()') start guided tour! + li + a(href='#/u/'+user.id) favourites + li + a(href='/logout') logout + @@ -203,25 +210,37 @@ html div(ng-controller='GuidedTourCtrl') tour#guided-tour(step="currentStep") - virtual-step(tourtip="{{'guided-tour.step.view.gallery' | translate}}", tourtip-element="#tip1", tourtip-placement="bottom") - virtual-step(tourtip="{{'guided-tour.step.filters.type' | translate}}" tourtip-element=".grammar-choice", tourtip-placement="bottom") - virtual-step(tourtip="{{'guided-tour.step.filters.related-to' | translate}}" tourtip-element=".grammar-choice.related-to", tourtip-placement="bottom") - virtual-step(tourtip="this is a person" tourtip-element=".tag.person", tourtip-placement="bottom") + //- explore.resources state + virtual-step(tourtip="guided-tour.welcome", tourtip-element=".view", tourtip-placement="center-top") + virtual-step(tourtip="guided-tour.step.view.gallery", tourtip-element="#tip1", tourtip-placement="bottom") + virtual-step(tourtip="guided-tour.step.filters.type" tourtip-element=".grammar-choice", tourtip-placement="bottom") + virtual-step(tourtip="guided-tour.step.filters.related-to" tourtip-element=".grammar-choice.related-to", tourtip-placement="bottom") + + virtual-step(tourtip="guided-tour.step.filters.timeline" tourtip-element="#timeline", tourtip-offset-horizontal="200", tourtip-placement="top") - virtual-step(tourtip="{{'guided-tour.step.filters.timeline' | translate}}" tourtip-element="#timeline", tourtip-offset-horizontal="200", tourtip-placement="top") + virtual-step(tourtip="guided-tour.step.view.gallery.resource" tourtip-element=".related h4 a", tourtip-offset-horizontal="0", tourtip-placement="bottom") + virtual-step(tourtip="this is a person" tourtip-element=".tag.person", tourtip-placement="bottom") + //- resource view steps - virtual-step(tourtip="{{'guided-tour.step.view.resource' | translate}}" tourtip-element=".resource.item .action", tourtip-offset-horizontal="0", tourtip-placement="bottom") - virtual-step(tourtip="{{'guided-tour.step.view.resource.seealso' | translate}}" tourtip-element="#see-also", tourtip-offset-horizontal="0", tourtip-placement="left") - virtual-step(tourtip="{{'guided-tour.step.view.resource.seealso.filters' | translate}}" tourtip-element=".grammar-choice.related-to", tourtip-offset-horizontal="0", tourtip-placement="bottom") - virtual-step(tourtip="{{'guided-tour.step.view.resource.add' | translate}}" tourtip-element=".resource.item .btn-contribute", tourtip-offset-horizontal="0", tourtip-placement="top") - virtual-step(tourtip="{{'guided-tour.step.view.resource.annotate' | translate}}" tourtip-element=".resource.item h3", tourtip-offset-horizontal="0", tourtip-placement="bottom") + virtual-step(tourtip="guided-tour.step.view.resource" tourtip-element=".resource.item", tourtip-offset-horizontal="0", tourtip-placement="center-top") + virtual-step(tourtip="guided-tour.step.view.resource.seealso" tourtip-element="#see-also", tourtip-offset-horizontal="0", tourtip-placement="center-top") + virtual-step(tourtip="guided-tour.step.view.resource.seealso.filters" tourtip-element=".grammar-choice.related-to", tourtip-offset-horizontal="0", tourtip-placement="bottom") + virtual-step(tourtip="guided-tour.step.view.resource.add" tourtip-element=".resource.item .btn-contribute", tourtip-offset-horizontal="0", tourtip-placement="top") + virtual-step(tourtip="guided-tour.step.view.resource.annotate" tourtip-element=".resource.item h3", tourtip-offset-horizontal="0", tourtip-placement="bottom") //- milkyway - virtual-step(tourtip="{{'guided-tour.step.view.graph' | translate}}" tourtip-element="#milkyway", tourtip-offset-horizontal="0", tourtip-placement="center-top") + virtual-step(tourtip="guided-tour.step.view.graph" tourtip-element="#milkyway", tourtip-offset-horizontal="0", tourtip-placement="center-top") + + //- guided tour, hidden + virtual-step(tourtip="guided-tour.skip" tourtip-element="#tip-user", tourtip-offset-horizontal="0", tourtip-placement="bottom") - virtual-step(tourtip="{{'guided-tour.step.view.gallery.resource' | translate}}" tourtip-element=".related h4 a", tourtip-offset-horizontal="0", tourtip-placement="bottom") + virtual-step(tourtip="guided-tour.step.view.resource.favourites" tourtip-element=".resource.item .actions", tourtip-offset-horizontal="0", tourtip-placement="bottom") + + + + div(id="messenger", class="tk-proxima-nova {{messaging? 'active': ''}}")