diff --git a/app/assets/javascripts/app/controllers/_click_catcher.js.coffee b/app/assets/javascripts/app/controllers/_click_catcher.js.coffee index 56378fa9a..751768872 100644 --- a/app/assets/javascripts/app/controllers/_click_catcher.js.coffee +++ b/app/assets/javascripts/app/controllers/_click_catcher.js.coffee @@ -14,6 +14,7 @@ class App.clickCatcher extends Spine.Controller render: -> @el.addClass("zIndex-#{ @zIndexScale }") if @zIndexScale @el.on('click', @triggerCallback) + @el.height(@holder.prop('scrollHeight')) @el.appendTo(@holder) remove: -> diff --git a/app/assets/javascripts/app/controllers/layout_ref.js.coffee b/app/assets/javascripts/app/controllers/layout_ref.js.coffee index 0c2d98bf3..565af9ba4 100644 --- a/app/assets/javascripts/app/controllers/layout_ref.js.coffee +++ b/app/assets/javascripts/app/controllers/layout_ref.js.coffee @@ -10,15 +10,39 @@ App.Config.set( 'layout_ref', Index, 'Routes' ) class Content extends App.ControllerContent + elements: + '.js-textarea' : 'textarea' + '.attachmentPlaceholder': 'attachmentPlaceholder' + '.attachmentPlaceholder-inputHolder': 'attachmentInputHolder' + '.attachmentPlaceholder-hint': 'attachmentHint' + '.ticket-edit': 'ticketEdit' + '.attachments': 'attachmentsHolder' + '.attachmentUpload': 'attachmentUpload' + '.attachmentUpload-progressBar':'progressBar' + '.js-percentage': 'progressText' + events: 'hide.bs.dropdown .js-recipientDropdown': 'hideOrganisationMembers' - 'click .js-organisation': 'showOrganisationMembers' - 'click .js-back': 'hideOrganisationMembers' + 'click .js-organisation': 'showOrganisationMembers' + 'click .js-back': 'hideOrganisationMembers' + 'focus .js-textarea': 'open_textarea' + 'input .js-textarea': 'detect_empty_textarea' + 'dragenter': 'onDragenter' + 'dragleave': 'onDragleave' + 'drop': 'onFileDrop' + 'change input[type=file]': 'onFilePick' constructor: -> super @render() + @textareaHeight = + open: 148 + closed: 38 + + @dragEventCounter = 0 + @attachments = [] + for avatar in @$('.user.avatar') avatar = $(avatar) size = if avatar.hasClass('big') then 50 else 40 @@ -94,6 +118,168 @@ class Content extends App.ControllerContent speed: 300 complete: => @organisationList.addClass('hide') + detect_empty_textarea: => + if !@textarea.text() + @add_textarea_catcher() + else + @remove_textarea_catcher() + + open_textarea: => + if !@textareaCatcher and !@textarea.text() and !@attachments.length + @ticketEdit.addClass('is-open') + + @textarea.velocity + properties: + minHeight: "#{ @textareaHeight.open - 38 }px" + marginBottom: 38 + options: + duration: 300 + easing: 'easeOutQuad' + complete: => @add_textarea_catcher() + + # scroll to bottom + # @textarea.velocity "scroll", + # container: @textarea.scrollParent() + # offset: 99999 + # duration: 300 + # easing: 'easeOutQuad' + # queue: false + + # @editControlItem.velocity "transition.slideRightIn", + # duration: 300 + # stagger: 50 + # drag: true + + # move attachment text to the left bottom (bottom happens automatically) + + @attachmentPlaceholder.velocity + properties: + translateX: -@attachmentInputHolder.position().left + "px" + options: + duration: 300 + easing: 'easeOutQuad' + + @attachmentHint.velocity + properties: + opacity: 0 + options: + duration: 300 + + add_textarea_catcher: -> + @textareaCatcher = new App.clickCatcher + holder: @ticketEdit.offsetParent() + callback: @close_textarea + zIndexScale: 4 + + remove_textarea_catcher: -> + return if !@textareaCatcher + @textareaCatcher.remove() + @textareaCatcher = null + + close_textarea: => + @remove_textarea_catcher() + if !@textarea.text() && !@attachments.length + + @textarea.velocity + properties: + minHeight: "#{ @textareaHeight.closed }px" + marginBottom: 0 + options: + duration: 300 + easing: 'easeOutQuad' + complete: => @ticketEdit.removeClass('is-open') + + @attachmentPlaceholder.velocity + properties: + translateX: 0 + options: + duration: 300 + easing: 'easeOutQuad' + + @attachmentHint.velocity + properties: + opacity: 1 + options: + duration: 300 + + # @editControlItem.css('display', 'none') + + onDragenter: (event) => + # on the first event, + # open textarea (it will only open if its closed) + @open_textarea() if @dragEventCounter is 0 + + @dragEventCounter++ + @ticketEdit.addClass('is-dropTarget') + + onDragleave: (event) => + @dragEventCounter-- + + @ticketEdit.removeClass('is-dropTarget') if @dragEventCounter is 0 + + onFileDrop: (event) => + event.preventDefault() + event.stopPropagation() + files = event.originalEvent.dataTransfer.files + @ticketEdit.removeClass('is-dropTarget') + + @queueUpload(files) + + onFilePick: (event) => + @open_textarea() + @queueUpload(event.target.files) + + queueUpload: (files) -> + @uploadQueue ?= [] + + # add files + for file in files + @uploadQueue.push(file) + + @workOfUploadQueue() + + workOfUploadQueue: => + if !@uploadQueue.length + return + + file = @uploadQueue.shift() + # console.log "working of", file, "from", @uploadQueue + @fakeUpload file.name, file.size, @workOfUploadQueue + + humanFileSize: (size) => + i = Math.floor( Math.log(size) / Math.log(1024) ) + return ( size / Math.pow(1024, i) ).toFixed(2) * 1 + ' ' + ['B', 'kB', 'MB', 'GB', 'TB'][i] + + updateUploadProgress: (progress) => + @progressBar.width(progress + "%") + @progressText.text(progress) + + if progress is 100 + @attachmentPlaceholder.removeClass('hide') + @attachmentUpload.addClass('hide') + + fakeUpload: (fileName, fileSize, callback) -> + @attachmentPlaceholder.addClass('hide') + @attachmentUpload.removeClass('hide') + + progress = 0; + duration = fileSize / 1024 + + for i in [0..100] + setTimeout @updateUploadProgress, i*duration/100 , i + + setTimeout (=> + callback() + @renderAttachment(fileName, fileSize) + ), duration + + renderAttachment: (fileName, fileSize) => + @attachments.push([fileName, fileSize]) + @attachmentsHolder.append App.view('ticket_zoom/attachment') + fileName: fileName + fileSize: @humanFileSize(fileSize) + + App.Config.set( 'layout_ref/content', Content, 'Routes' ) diff --git a/app/assets/javascripts/app/views/layout_ref/content.jst.eco b/app/assets/javascripts/app/views/layout_ref/content.jst.eco index 2ddeb5226..71f7d8254 100644 --- a/app/assets/javascripts/app/views/layout_ref/content.jst.eco +++ b/app/assets/javascripts/app/views/layout_ref/content.jst.eco @@ -40,6 +40,64 @@ +
+ +

Article Reply

+ +
+
+
+
+
+
+ +
+ +
+
+ Antwort eingeben oder + + Dateien wählen.. + + +
+
+
+
+ <%- @T(' Uploading ') %> (0%) ... +
+
+
<%- @T('Cancel Upload') %> +
+
+
+
+
+
+
+ <%- @T('Drop Files here') %> +
+
+
+
+
+

diff --git a/app/assets/javascripts/app/views/ticket_zoom/attachment.jst.eco b/app/assets/javascripts/app/views/ticket_zoom/attachment.jst.eco new file mode 100644 index 000000000..6d853379f --- /dev/null +++ b/app/assets/javascripts/app/views/ticket_zoom/attachment.jst.eco @@ -0,0 +1,7 @@ +
+
<%- @fileName %>
+
<%- @fileSize %>
+
+
<%- @T('Delete File') %> +
+
\ No newline at end of file diff --git a/app/assets/stylesheets/zzz.css.erb b/app/assets/stylesheets/zzz.css.erb index ea4590261..38b154d10 100644 --- a/app/assets/stylesheets/zzz.css.erb +++ b/app/assets/stylesheets/zzz.css.erb @@ -89,7 +89,7 @@ small { } .clickCatcher { - bottom: 0; + top: 0; left: 0; width: 100%; height: 100%; @@ -105,6 +105,25 @@ small { background: hsla(50,100%,50%,.13); } +[contenteditable] { + margin: -1px; + display: block; + white-space: pre-wrap; + outline-style: none; + border: 1px solid transparent; + border-radius: 3px; +} +[contenteditable]:hover, +[contenteditable]:focus { + border-color: hsl(145,51%,45%); +} +[contenteditable].invalid { + border-color: #F92; +} +[contenteditable] > .placeholder { + color: #999; +} + .close, .close:hover { float: none; @@ -2586,6 +2605,19 @@ footer { margin-bottom: 3px; } + .dropArea { + background: white; + border: 5px solid; + color: hsl(202,66%,55%); + font-size: 20px; + margin: 5px; + display: none; + } + + .ticket-edit.is-dropTarget .dropArea { + display: block; + } + .edit-controls { position: relative; } @@ -2764,10 +2796,11 @@ footer { border-color: #b3b3b3; white-space: normal; border-radius: 5px; - overflow: hidden; } - .ticket-edit .text-bubble [contenteditable] { + .ticket-edit .text-bubble [contenteditable], + .ticket-edit textarea, + .ticketEdit-body { width: 100%; /*height: 38px;*/ min-height: 20px; @@ -2778,6 +2811,11 @@ footer { resize: none; } + .ticketEdit-body { + height: auto; + min-height: 38px; + } + .ticket-edit .bubble-arrow:after { border-color: #b3b3b3; box-shadow: none; @@ -2787,19 +2825,75 @@ footer { position: absolute; bottom: 0; left: 10px; - width: 100%; + right: 10px; height: 38px; padding: 10px 0; color: #b3b3b3; } - .edit-upload-button { + .attachments:not(:empty) { + padding: 9px 5px; + border-top: 1px solid hsl(0,0%,93%); + margin-bottom: 50px; + } + + .attachment { + font-size: 13px; + padding: 3px 10px 3px 7px; + cursor: default; + } + + .attachment:hover { + background: hsl(200,20%,97%); + } + + .attachment-name { + margin-right: 5px; + } + + .attachment-delete { + color: hsl(198,19%,72%); + text-decoration: underline; + display: none; + } + + .attachment:hover .attachment-delete { + display: block; + } + + .attachment-delete .icon { + opacity: 0.2; + margin-right: 5px; + } + + .attachmentPlaceholder-inputHolder { position: relative; display: inline-block; overflow: hidden; vertical-align: bottom; } + .attachmentUpload { + color: hsl(198,19%,72%); + } + + .attachmentUpload-cancel { + text-decoration: underline; + } + + .attachmentUpload .delete.icon { + opacity: 0.33; + margin-right: 5px; + } + + .attachmentUpload-progressBar { + position: absolute; + height: 4px; + background: hsl(202,66%,55%); + left: 0; + bottom: -5px; + } + .pop-selector { position: absolute; top: 0; @@ -3437,25 +3531,6 @@ footer { margin-top: 1px; } -[contenteditable] { - margin: -1px; - display: block; - white-space: pre-wrap; - outline-style: none; - border: 1px solid transparent; - border-radius: 3px; -} -[contenteditable]:hover, -[contenteditable]:focus { - border-color: hsl(145,51%,45%); -} -[contenteditable].invalid { - border-color: #F92; -} -[contenteditable] > .placeholder { - color: #999; -} - .userSearch { margin-bottom: 20px; }