From d534d43ad01f262f370d487939b0010b8ec207fc Mon Sep 17 00:00:00 2001 From: Martin Edenhofer Date: Sun, 21 Jun 2015 01:31:41 +0200 Subject: [PATCH] Show placeholder if no activity stream is shown. --- .../_dashboard/activity_stream.js.coffee | 4 + .../_dashboard/first_steps_clues.js.coffee | 317 ++++++++++++++++++ .../app/controllers/dashboard.js.coffee | 6 + 3 files changed, 327 insertions(+) create mode 100644 app/assets/javascripts/app/controllers/_dashboard/first_steps_clues.js.coffee diff --git a/app/assets/javascripts/app/controllers/_dashboard/activity_stream.js.coffee b/app/assets/javascripts/app/controllers/_dashboard/activity_stream.js.coffee index 529d0c6be..268a13cae 100644 --- a/app/assets/javascripts/app/controllers/_dashboard/activity_stream.js.coffee +++ b/app/assets/javascripts/app/controllers/_dashboard/activity_stream.js.coffee @@ -38,6 +38,10 @@ class App.DashboardActivityStream extends App.Controller @render(items) render: (items) -> + if _.isEmpty(items) + @$('.activity-description').removeClass('hidden') + return + items = @prepareForObjectList(items) html = $('
') diff --git a/app/assets/javascripts/app/controllers/_dashboard/first_steps_clues.js.coffee b/app/assets/javascripts/app/controllers/_dashboard/first_steps_clues.js.coffee new file mode 100644 index 000000000..89200ec9f --- /dev/null +++ b/app/assets/javascripts/app/controllers/_dashboard/first_steps_clues.js.coffee @@ -0,0 +1,317 @@ +class App.FirstStepsClues extends App.Controller + clues: [ + { + container: '.search-holder' + headline: 'Suche' + text: 'Um alles zu finden nutze den *-Platzhalter' + } + { + container: '.user-menu' + headline: 'Erstellen' + text: 'Hier kannst du Tickets, Kunden und Organisationen anlegen.' + actions: [ + 'click .add .js-action', + 'hover .add' + ] + } + { + container: '.user-menu' + headline: 'Persönliches Menü' + text: 'Hier findest du den Logout, den Weg zu deinen Einstellungen und deinen Verlauf.' + actions: [ + 'click .user .js-action', + 'hover .user' + ] + } + { + container: '.main-navigation .overviews' + headline: 'Übersichten' + text: 'Hier findest du eine Liste aller Tickets.' + actions: [ + 'hover' + ] + } + { + container: '.main-navigation .dashboard' + headline: 'Dashboard' + text: 'Hier siehst du auf einem Blick ob sich alle Agenten an die Spielregeln halten.' + actions: [ + 'hover' + ] + } + ] + + elements: + '.js-positionOrigin': 'modalWindow' + '.js-backdrop': 'backdrop' + + events: + 'click': 'stopPropagation' + 'click .js-next': 'next' + 'click .js-previous': 'previous' + 'click .js-close': 'close' + + constructor: -> + super + + ### + + options + clues: list of clues + onComplete: a callback for when the user is done + + ### + @el = $('body') + @options.onComplete = -> null + @position = 0 + @render() + + stopPropagation: (event) -> + event.stopPropagation() + + next: (event) => + event.stopPropagation() + @navigate 1 + + previous: (event) => + event.stopPropagation() + @navigate -1 + + close: => + @cleanUp() + @options.onComplete() + @remove() + + remove: -> + @$('.modal').remove() + + navigate: (direction) -> + @cleanUp => + @position += direction + + if @position < @clues.length + @showClue() + else + @options.onComplete() + @remove() + + cleanUp: (callback) -> + @hideWindow => + clue = @clues[@position] + container = $(clue.container) + container.removeClass('selected-clue') + + # undo click perform by doing it again + if clue.actions + @perform clue.actions, container + + callback() + + render: => + html = App.view('layout_ref/clues') + console.log('HH', html) + @el.append(html) + #@modalWindow = $('.js-positionOrigin') + #@backdrop = $('.js-backdrop') + @backdrop.velocity + properties: + opacity: [1, 0] + options: + duration: 300 + complete: @showClue + + showClue: => + clue = @clues[@position] + container = $(clue.container) + container.addClass('selected-clue') + console.log('showClue', clue, clue.container) + if clue.actions + @perform clue.actions, container + + # calculate bounding box after actions + # to take toggled child nodes into account + boundingBox = @getVisibleBoundingBox(container.get(0)) + + center = + x: boundingBox.left + boundingBox.width/2 + y: boundingBox.top + boundingBox.height/2 + + @modalWindow.html App.view('layout_ref/clue_content') + headline: clue.headline + text: clue.text + position: @position + max: @clues.length + + @placeWindow(boundingBox) + + @backdrop.velocity + properties: + translateX: center.x + translateY: center.y + translateZ: 0 + options: + duration: 300 + complete: @showWindow + + showWindow: => + @modalWindow.velocity + properties: + scale: [1, 0.2] + opacity: [1, 0] + options: + duration: 300 + easing: [0.34,1.61,0.7,1] + + hideWindow: (callback) => + @modalWindow.velocity + properties: + scale: [0.2, 1] + opacity: 0 + options: + duration: 200 + complete: callback + + + placeWindow: (target) -> + # reset scale in order to get correct measurements + $.Velocity.hook(@modalWindow, 'scale', 1) + + modal = @modalWindow.get(0).getBoundingClientRect() + position = '' + left = 0 + top = 0 + maxWidth = $(window).width() + maxHeight = $(window).height() + + # try to place it parallel to the larger side + if target.height > target.width + # try to place it aside + # prefer right + if target.right + modal.width <= maxWidth + left = target.right + position = 'right' + else + # place left + left = target.left - modal.width + position = 'left' + + if position + top = target.top + target.height/2 - modal.height/2 + else if target.height <= target.width or !position + # try to place it above or below + # prefer above + if target.top - modal.height >= 0 + top = target.top - modal.height + position = 'above' + else + top = target.bottom + position = 'below' + + if position + left = target.left + target.width/2 - modal.width/2 + + # keep it inside the window + # horizontal + if left < 0 + moveArrow = modal.width/2 + left + left = 0 + else if left + modal.width > maxWidth + moveArrow = modal.width/2 + maxWidth - (left + modal.width) + left = maxWidth - modal.width + + if top < 0 + moveArrow = modal.height/2 + height + top = 0 + else if top + modal.height > maxHeight + moveArrow = modal.height/2 + maxHeight - (top + modal.height) + top = maxHeight - modal.height + + transformOrigin = @getTransformOrigin(modal, position) + + if moveArrow + parameter = if position is 'above' or position is 'below' then 'left' else 'top' + # move arrow + @modalWindow.find('.js-arrow').css(parameter, moveArrow) + + # adjust transform origin + if position is 'above' or position is 'below' + transformOrigin.x = moveArrow + else + transformOrigin.y = moveArrow + + # place window + @modalWindow + .attr 'data-position', position + .css + left: left + top: top + transformOrigin: "#{transformOrigin.x}px #{transformOrigin.y}px" + + getTransformOrigin: (modal, position) -> + positionDictionary = + above: + x: modal.width/2 + y: modal.height + below: + x: modal.width/2 + y: 0 + left: + x: modal.width + @transformOriginPadding + y: modal.height/2 + right: + x: -@transformOriginPadding + y: modal.height/2 + + return positionDictionary[position] + + getVisibleBoundingBox: (el) -> + ### + + getBoundingClientRect doesn't take + absolute-positioned child nodes into account + + ### + children = el.querySelectorAll('*') + bb = el.getBoundingClientRect() + dimensions = + left: bb.left, + right: bb.right, + top: bb.top, + bottom: bb.bottom + + for child in children + + continue if getComputedStyle(child).position is not 'absolute' + + bb = child.getBoundingClientRect() + + continue if bb.width is 0 or bb.height is 0 + + if bb.left < dimensions.left + dimensions.left = bb.left + if bb.top < dimensions.top + dimensions.top = bb.top + if bb.right > dimensions.right + dimensions.right = bb.right + if bb.bottom > dimensions.bottom + dimensions.bottom = bb.bottom + + dimensions.width = dimensions.right - dimensions.left + dimensions.height = dimensions.bottom - dimensions.top + + dimensions + + perform: (actions, container) -> + for action in actions + if action.indexOf(" ") < 0 + # 'click' + eventName = action + target = container + else + # 'click .target' + eventName = action.substr 0, action.indexOf(' ') + target = container.find( action.substr action.indexOf(' ') + 1 ) + + switch eventName + when 'click' then target.trigger('click') + when 'hover' then target.toggleClass('is-hovered') \ No newline at end of file diff --git a/app/assets/javascripts/app/controllers/dashboard.js.coffee b/app/assets/javascripts/app/controllers/dashboard.js.coffee index d7f9b70c4..1449e9c0c 100644 --- a/app/assets/javascripts/app/controllers/dashboard.js.coffee +++ b/app/assets/javascripts/app/controllers/dashboard.js.coffee @@ -1,6 +1,7 @@ class App.Dashboard extends App.Controller events: 'click .tabs .tab': 'toggle' + 'click .intro': 'clues' constructor: -> super @@ -29,6 +30,11 @@ class App.Dashboard extends App.Controller @renderWidgetClockFace 25 + clues: => + new App.FirstStepsClues( + el: @el + ) + renderWidgetClockFace: (time) => canvas = @el.find 'canvas' ctx = canvas.get(0).getContext '2d'