attachment + animation

This commit is contained in:
Felix Niklas 2014-09-04 02:54:33 +02:00
parent 47d450181c
commit f7b4ac30ad
4 changed files with 135 additions and 99 deletions

View file

@ -319,7 +319,14 @@ class Sidebar extends App.Controller
class Edit extends App.Controller class Edit extends App.Controller
elements: elements:
'textarea' : 'textarea' 'textarea' : 'textarea'
'.js-edit-control' : 'editControls' '.edit-control-item' : 'editControlItem'
'.edit-controls': 'editControls'
'.recipient-picker': 'recipientPicker'
'.recipient-list': 'recipientList'
'.recipient-list .list-arrow': 'recipientListArrow'
'.js-attachment': 'attachmentHolder'
'.js-attachment-text': 'attachmentText'
'.bubble-placeholder-hint': 'bubblePlaceholderHint'
events: events:
'click .submit': 'update' 'click .submit': 'update'
@ -329,9 +336,9 @@ class Edit extends App.Controller
'click .pop-selected': 'show_selectable_types' 'click .pop-selected': 'show_selectable_types'
'focus textarea': 'open_textarea' 'focus textarea': 'open_textarea'
'input textarea': 'detect_empty_textarea' 'input textarea': 'detect_empty_textarea'
'click .recipient-picker': 'show_recipients' 'click .recipient-picker': 'toggle_recipients'
'click .recipient-list': 'stopPropagation' 'click .recipient-list': 'stopPropagation'
'click .list-entry-type div': 'change_recipient_type' 'click .list-entry-type div': 'change_type'
'submit .recipient-list form': 'add_recipient' 'submit .recipient-list form': 'add_recipient'
constructor: -> constructor: ->
@ -465,33 +472,36 @@ class Edit extends App.Controller
) )
@subscribeIdTextModule = ticket.subscribe( callback ) @subscribeIdTextModule = ticket.subscribe( callback )
show_recipients: => toggle_recipients: =>
if !@pickRecipientsCatcher
@show_recipients()
else
@hide_recipients()
show_recipients: ->
padding = 15 padding = 15
toggle = @el.find('.recipient-picker')
list = @el.find('.recipient-list')
arrow = list.find('.list-arrow')
toggle.addClass('is-open') @recipientPicker.addClass('is-open')
list.removeClass('hide') @recipientList.removeClass('hide')
toggleDimensions = toggle.get(0).getBoundingClientRect() pickerDimensions = @recipientPicker.get(0).getBoundingClientRect()
availableHeight = toggle.scrollParent().outerHeight() availableHeight = @recipientPicker.scrollParent().outerHeight()
top = toggleDimensions.height/2 - list.height()/2 top = pickerDimensions.height/2 - @recipientList.height()/2
bottomDistance = availableHeight - padding - (toggleDimensions.top + top + list.height()) bottomDistance = availableHeight - padding - (pickerDimensions.top + top + @recipientList.height())
if bottomDistance < 0 if bottomDistance < 0
top += bottomDistance top += bottomDistance
arrowCenter = -top + toggleDimensions.height/2 arrowCenter = -top + pickerDimensions.height/2
arrow.css('top', arrowCenter) @recipientListArrow.css('top', arrowCenter)
list.css('top', top) @recipientList.css('top', top)
$.Velocity.hook(list, 'transformOriginX', "0") $.Velocity.hook(@recipientList, 'transformOriginX', "0")
$.Velocity.hook(list, 'transformOriginY', "#{ arrowCenter }px") $.Velocity.hook(@recipientList, 'transformOriginY', "#{ arrowCenter }px")
list.velocity @recipientList.velocity
properties: properties:
scale: [ 1, 0 ] scale: [ 1, 0 ]
opacity: [ 1, 0 ] opacity: [ 1, 0 ]
@ -499,26 +509,27 @@ class Edit extends App.Controller
speed: 300 speed: 300
easing: [ 0.34, 1.61, 0.7, 1 ] easing: [ 0.34, 1.61, 0.7, 1 ]
@selectTypeCatcher = new App.clickCatcher @pickRecipientsCatcher = new App.clickCatcher
holder: @el.offsetParent() holder: @el.offsetParent()
callback: @hide_recipients callback: @hide_recipients
zIndexScale: 6 zIndexScale: 6
hide_recipients: => hide_recipients: =>
list = @el.find('.recipient-list') @pickRecipientsCatcher.remove()
@pickRecipientsCatcher = null
@el.find('.recipient-picker').removeClass('is-open') @recipientPicker.removeClass('is-open')
list.velocity @recipientList.velocity
properties: properties:
scale: [ 0, 1 ] scale: [ 0, 1 ]
opacity: [ 0, 1 ] opacity: [ 0, 1 ]
options: options:
speed: 300 speed: 300
easing: [ 500, 20 ] easing: [ 500, 20 ]
complete: -> list.addClass('hide') complete: -> @recipientList.addClass('hide')
change_recipient_type: (e) -> change_type: (e) ->
$(e.target).addClass('active').siblings('.active').removeClass('active') $(e.target).addClass('active').siblings('.active').removeClass('active')
# store $(this).data('value') # store $(this).data('value')
@ -548,6 +559,7 @@ class Edit extends App.Controller
@set_type $(e.target).data('value') @set_type $(e.target).data('value')
@hide_type() @hide_type()
@selectTypeCatcher.remove() @selectTypeCatcher.remove()
@selectTypeCatcher = null
hide_type: => hide_type: =>
@el.find('.pop-selector').addClass('hide') @el.find('.pop-selector').addClass('hide')
@ -567,35 +579,43 @@ class Edit extends App.Controller
open_textarea: => open_textarea: =>
if !@textareaCatcher and !@textarea.val() if !@textareaCatcher and !@textarea.val()
@el.addClass('mode--edit') @el.addClass('is-open')
@textarea.velocity
properties:
height: "#{ @textareaHeight.open - 38 }px"
marginBottom: 38
options:
duration: 300
easing: 'easeOutQuad'
# scroll to bottom # scroll to bottom
@textarea.velocity "scroll", @textarea.velocity "scroll",
container: @textarea.scrollParent() container: @textarea.scrollParent()
offset: @textareaHeight.open - @textareaHeight.closed offset: 99999
duration: 300 duration: 300
easing: 'easeOutQuad' easing: 'easeOutQuad'
@textarea.velocity
properties:
height: "#{ @textareaHeight.open }px"
options:
speed: 300
easing: 'easeOutQuad'
queue: false queue: false
@editControls.velocity @editControlItem.velocity "transition.slideRightIn",
duration: 300
stagger: 50
drag: true
# move attachment text to the left bottom (bottom happens automatically)
@attachmentHolder.velocity
properties: properties:
translateY: [ translateX: -@attachmentText.position().left + "px"
(i) -> (i+1) * 38,
'easeOutQuad',
0
]
opacity: [ 1, [ 0.34, 1.61, 0.7, 1 ], 0]
scale: [ 1, 'easeOutQuad', 0 ]
options: options:
speed: 300 duration: 300
stagger: (i) -> i*100 easing: 'easeOutQuad'
@bubblePlaceholderHint.velocity
properties:
opacity: 0
options:
duration: 300
@add_textarea_catcher() @add_textarea_catcher()
@ -613,28 +633,30 @@ class Edit extends App.Controller
close_textarea: => close_textarea: =>
@remove_textarea_catcher() @remove_textarea_catcher()
if !@textarea.val() if !@textarea.val()
@el.removeClass('mode--edit')
@textarea.velocity @textarea.velocity
properties: properties:
height: "#{ @textareaHeight.closed }px" height: "#{ @textareaHeight.closed }px"
marginBottom: 0
options: options:
speed: 300 duration: 300
easing: 'easeOutQuad'
complete: => @el.removeClass('is-open')
@attachmentHolder.velocity
properties:
translateX: 0
options:
duration: 300
easing: 'easeOutQuad' easing: 'easeOutQuad'
@editControls.velocity @bubblePlaceholderHint.velocity
properties: properties:
translateY: [ opacity: 1
0,
'easeOutQuad',
(i) -> (i+1) * 38
]
scale: [ 0, [ 0.34, 1.61, 0.7, 1 ], 1 ]
opacity: [ 0, 'easeOutQuad', 1 ]
options: options:
speed: 300 duration: 300
stagger: 300
backwards: true @editControlItem.css('display', 'none')
autosaveStop: => autosaveStop: =>
@clearInterval( 'autosave' ) @clearInterval( 'autosave' )

View file

@ -1,8 +1,8 @@
<form class="ticket-update <% if @formChanged: %>form-changed<% end %>"> <form class="ticket-update <% if @formChanged: %>form-changed<% end %>">
<div class="bubble-grid horizontal"> <div class="bubble-grid horizontal">
<div class="vertical center u-positionOrigin"> <div class="vertical center edit-controls">
<div class="avatar user-popover zIndex-5" data-id="<%= @S('id') %>" style="background-image: url(<%- @S('image') %>)"></div> <div class="avatar user-popover zIndex-5" data-id="<%= @S('id') %>" style="background-image: url(<%- @S('image') %>)"></div>
<div class="dark pop-select zIndex-7 js-edit-control"> <div class="dark pop-select zIndex-7 edit-control-item">
<div class="pop-selected u-clickable centered"> <div class="pop-selected u-clickable centered">
<div class="gray <%- @type %> channel icon"></div> <div class="gray <%- @type %> channel icon"></div>
</div> </div>
@ -23,12 +23,12 @@
</div> </div>
</div> </div>
</div> </div>
<div class="u-positionOrigin js-edit-control"> <div class="u-positionOrigin zIndex-7 edit-control-item">
<div class="recipient-picker zIndex-5 u-clickable horizontal centered"> <div class="recipient-picker u-clickable horizontal centered">
<div class="recipients icon"></div> <div class="recipients icon"></div>
<div class="recipient-count">3</div> <div class="recipient-count">3</div>
</div> </div>
<div class="recipient-list zIndex-7 hide"> <div class="recipient-list hide">
<div class="list-arrow"></div> <div class="list-arrow"></div>
<div class="list-head horizontal"> <div class="list-head horizontal">
<%- @T('Recipients') %> <%- @T('Recipients') %>
@ -64,7 +64,7 @@
</form> </form>
</div> </div>
</div> </div>
<div class="visibility-toggle zIndex-7 u-clickable js-edit-control"> <div class="visibility-toggle zIndex-7 u-clickable edit-control-item">
<div class="internal-visibility centered" title="<%- @T("unset internal") %>"> <div class="internal-visibility centered" title="<%- @T("unset internal") %>">
<div class="internal visibility icon"></div> <div class="internal visibility icon"></div>
</div> </div>
@ -78,9 +78,13 @@
<div class="text-bubble"> <div class="text-bubble">
<div class="bubble-arrow"></div> <div class="bubble-arrow"></div>
<textarea></textarea> <textarea></textarea>
<div class="bubble-placeholder u-unclickable"> <!-- .text-bubble grows with textarea (and expanding clone) -->
Antwort eingeben oder <div class="article-attachment js-attachment u-unclickable">
<span class="highlight u-clickable js-upload">Dateien wählen</span> <span class="bubble-placeholder-hint">Antwort eingeben oder</span>
<span class="highlight u-clickable edit-upload-button js-attachment-text">
Dateien wählen..
<input multiple="multiple" type="file" name="file" style="position: absolute; right: 0px; top: 0px; font-family: Arial; font-size: 118px; margin: 0px; padding: 0px; cursor: pointer; opacity: 0;">
</span>
</div> </div>
</div> </div>
</div> </div>

View file

@ -9,7 +9,7 @@
//= require ./app/lib/core/jquery-ui-1.8.23.custom.min.js //= require ./app/lib/core/jquery-ui-1.8.23.custom.min.js
//= require ./app/lib/core/underscore-1.6.0.js //= require ./app/lib/core/underscore-1.6.0.js
//= require ./app/lib/animations/jquery.velocity.min.js //= require ./app/lib/animations/velocity.min.js
//= require ./app/lib/animations/velocity.ui.js //= require ./app/lib/animations/velocity.ui.js
//not_used= require_tree ./app/lib/spine //not_used= require_tree ./app/lib/spine

View file

@ -80,15 +80,14 @@ small {
height: 100%; height: 100%;
position: absolute; position: absolute;
cursor: default; cursor: default;
background: rgba(255,255,0,.13);
} }
.clickCatcher + .clickCatcher { .debug .clickCatcher {
background: rgba(255,0,255,.13); background: hsla(0,100%,50%,.13);
} }
.clickCatcher + .clickCatcher + .clickCatcher { .debug .clickCatcher + .clickCatcher {
background: rgba(0,255,128,.21); background: hsla(50,100%,50%,.13);
} }
#app > nav { #app > nav {
@ -2798,32 +2797,39 @@ footer {
margin-bottom: 3px; margin-bottom: 3px;
} }
.ticket-edit .js-edit-control { .edit-controls {
position: relative;
}
.edit-control-item {
width: 38px; width: 38px;
height: 36px; height: 36px;
position: absolute; position: absolute;
top: 0; top: 38px;
transform: scale(0); display: none;
} }
.ticket-edit .js-edit-control:not(:last-child) { .edit-control-item:nth-child(3) {
top: 74px;
}
.edit-control-item:nth-child(4) {
top: 110px;
}
.edit-control-item:not(:last-child) {
border-bottom: 1px solid #e6e6e6; border-bottom: 1px solid #e6e6e6;
} }
.ticket-edit .pop-selectable .icon { .pop-selectable .icon {
opacity: 0.3; opacity: 0.3;
pointer-events: none; pointer-events: none;
} }
.ticket-edit .pop-selectable:hover .icon { .pop-selectable:hover .icon {
opacity: 1; opacity: 1;
} }
.ticket-edit button[type=submit] {
margin: 5px 0;
float: right;
}
.visibility-toggle > * { .visibility-toggle > * {
height: 36px; height: 36px;
width: 38px; width: 38px;
@ -2970,20 +2976,18 @@ footer {
border-color: #b3b3b3; border-color: #b3b3b3;
white-space: normal; white-space: normal;
border-radius: 5px; border-radius: 5px;
overflow: hidden;
} }
.ticket-edit textarea { .ticket-edit textarea {
width: 100%; width: 100%;
height: 38px; height: 38px;
padding: 10px 20px; padding: 10px;
vertical-align: bottom; vertical-align: bottom;
border: none; border: none;
background: none; background: none;
outline: none; outline: none;
} resize: none;
.ticket-edit.mode--edit .bubble-placeholder {
opacity: 0;
} }
.ticket-edit .bubble-arrow:after { .ticket-edit .bubble-arrow:after {
@ -2991,22 +2995,28 @@ footer {
box-shadow: none; box-shadow: none;
} }
.bubble-placeholder { .article-attachment {
position: absolute; position: absolute;
bottom: 0;
left: 10px;
width: 100%;
height: 38px;
padding: 10px 0;
color: #b3b3b3; color: #b3b3b3;
left: 20px;
top: 10px;
} }
.pop-select { .edit-upload-button {
position: relative; position: relative;
} display: inline-block;
overflow: hidden;
vertical-align: bottom;
}
.pop-selector { .pop-selector {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
} }
.pop-selected, .pop-selected,
.pop-selectable { .pop-selectable {