From b60b0a8b5cbf31b3c94dbd54a199617ed0340b65 Mon Sep 17 00:00:00 2001 From: Felix Niklas Date: Fri, 20 Nov 2015 15:43:23 +0100 Subject: [PATCH] chat designer: remove tabs, add documentation --- .../app/controllers/_channel/chat.coffee | 114 ++++-- .../app/lib/base/highlight.pack.js | 1 + .../app/views/channel/chat.jst.eco | 385 ++++++++++-------- app/assets/stylesheets/application.css | 1 + app/assets/stylesheets/bootstrap.css | 7 - app/assets/stylesheets/highlighter-github.css | 123 ++++++ app/assets/stylesheets/zammad.scss | 22 +- public/assets/chat/chat.coffee | 11 +- 8 files changed, 445 insertions(+), 219 deletions(-) create mode 100644 app/assets/javascripts/app/lib/base/highlight.pack.js create mode 100644 app/assets/stylesheets/highlighter-github.css diff --git a/app/assets/javascripts/app/controllers/_channel/chat.coffee b/app/assets/javascripts/app/controllers/_channel/chat.coffee index 886705b07..de7a861a3 100644 --- a/app/assets/javascripts/app/controllers/_channel/chat.coffee +++ b/app/assets/javascripts/app/controllers/_channel/chat.coffee @@ -1,35 +1,4 @@ -class App.ChannelChat extends App.ControllerTabs - header: 'Chat Widget' - addTab: true - - constructor: -> - super - - @title @header, true - - @load() - - load: => - @tabs = [] - @ajax( - id: 'chat_index' - type: 'GET' - url: @apiPath + '/chats' - processData: true - success: (data, status, xhr) => - App.Collection.loadAssets(data.assets) - for chat in App.Chat.all() - tab = - name: chat.name - target: "chat-#{chat.id}" - controller: App.ChannelChatDesigner - params: - model: chat - @tabs.push tab - @render() - ) - -class App.ChannelChatDesigner extends App.Controller +class App.ChannelChat extends App.Controller events: 'click .js-add': 'new' 'click .js-edit': 'edit' @@ -48,6 +17,72 @@ class App.ChannelChatDesigner extends App.Controller '.js-chat': 'chat' '.js-testurl-input': 'urlInput' '.js-backgroundColor': 'chatBackground' + '.js-paramsBlock': 'paramsBlock' + '.js-code': 'code' + + apiOptions: [ + { + name: 'channel' + default: "'default'" + type: 'String' + description: 'Name of the chat-channel.' + } + { + name: 'show' + default: true + type: 'Boolean' + description: 'Show the chat when ready.' + } + { + name: 'target' + default: "$('body')" + type: 'jQuery Object' + description: 'Where to append the chat to.' + } + { + name: 'host' + default: "(Empty)" + type: 'String' + description: "If left empty, the host gets auto-detected - in this case %s. The auto-detection reads out the host from the ",rE:!0,sL:["actionscript","javascript","handlebars"]}},c,{cN:"pi",b:/<\?\w+/,e:/\?>/,r:10},{cN:"tag",b:"",c:[{cN:"title",b:/[^ \/><\n\t]+/,r:0},e]}]}});hljs.registerLanguage("ruby",function(e){var c="[a-zA-Z_]\\w*[!?=]?|[-+~]\\@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?",r="and false then defined module in return redo if BEGIN retry end for true self when next until do begin unless END rescue nil else break undef not super class case require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor",b={cN:"doctag",b:"@[A-Za-z]+"},a={cN:"value",b:"#<",e:">"},n=[e.C("#","$",{c:[b]}),e.C("^\\=begin","^\\=end",{c:[b],r:10}),e.C("^__END__","\\n$")],s={cN:"subst",b:"#\\{",e:"}",k:r},t={cN:"string",c:[e.BE,s],v:[{b:/'/,e:/'/},{b:/"/,e:/"/},{b:/`/,e:/`/},{b:"%[qQwWx]?\\(",e:"\\)"},{b:"%[qQwWx]?\\[",e:"\\]"},{b:"%[qQwWx]?{",e:"}"},{b:"%[qQwWx]?<",e:">"},{b:"%[qQwWx]?/",e:"/"},{b:"%[qQwWx]?%",e:"%"},{b:"%[qQwWx]?-",e:"-"},{b:"%[qQwWx]?\\|",e:"\\|"},{b:/\B\?(\\\d{1,3}|\\x[A-Fa-f0-9]{1,2}|\\u[A-Fa-f0-9]{4}|\\?\S)\b/}]},i={cN:"params",b:"\\(",e:"\\)",k:r},d=[t,a,{cN:"class",bK:"class module",e:"$|;",i:/=/,c:[e.inherit(e.TM,{b:"[A-Za-z_]\\w*(::\\w+)*(\\?|\\!)?"}),{cN:"inheritance",b:"<\\s*",c:[{cN:"parent",b:"("+e.IR+"::)?"+e.IR}]}].concat(n)},{cN:"function",bK:"def",e:"$|;",c:[e.inherit(e.TM,{b:c}),i].concat(n)},{cN:"constant",b:"(::)?(\\b[A-Z]\\w*(::)?)+",r:0},{cN:"symbol",b:e.UIR+"(\\!|\\?)?:",r:0},{cN:"symbol",b:":",c:[t,{b:c}],r:0},{cN:"number",b:"(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b",r:0},{cN:"variable",b:"(\\$\\W)|((\\$|\\@\\@?)(\\w+))"},{b:"("+e.RSR+")\\s*",c:[a,{cN:"regexp",c:[e.BE,s],i:/\n/,v:[{b:"/",e:"/[a-z]*"},{b:"%r{",e:"}[a-z]*"},{b:"%r\\(",e:"\\)[a-z]*"},{b:"%r!",e:"![a-z]*"},{b:"%r\\[",e:"\\][a-z]*"}]}].concat(n),r:0}].concat(n);s.c=d,i.c=d;var o="[>?]>",l="[\\w#]+\\(\\w+\\):\\d+:\\d+>",u="(\\w+-)?\\d+\\.\\d+\\.\\d(p\\d+)?[^>]+>",N=[{b:/^\s*=>/,cN:"status",starts:{e:"$",c:d}},{cN:"prompt",b:"^("+o+"|"+l+"|"+u+")",starts:{e:"$",c:d}}];return{aliases:["rb","gemspec","podspec","thor","irb"],k:r,i:/\/\*/,c:n.concat(N).concat(d)}});hljs.registerLanguage("coffeescript",function(e){var c={keyword:"in if for while finally new do return else break catch instanceof throw try this switch continue typeof delete debugger super then unless until loop of by when and or is isnt not",literal:"true false null undefined yes no on off",built_in:"npm require console print module global window document"},n="[A-Za-z$_][0-9A-Za-z$_]*",r={cN:"subst",b:/#\{/,e:/}/,k:c},t=[e.BNM,e.inherit(e.CNM,{starts:{e:"(\\s*/)?",r:0}}),{cN:"string",v:[{b:/'''/,e:/'''/,c:[e.BE]},{b:/'/,e:/'/,c:[e.BE]},{b:/"""/,e:/"""/,c:[e.BE,r]},{b:/"/,e:/"/,c:[e.BE,r]}]},{cN:"regexp",v:[{b:"///",e:"///",c:[r,e.HCM]},{b:"//[gim]*",r:0},{b:/\/(?![ *])(\\\/|.)*?\/[gim]*(?=\W|$)/}]},{cN:"property",b:"@"+n},{b:"`",e:"`",eB:!0,eE:!0,sL:"javascript"}];r.c=t;var s=e.inherit(e.TM,{b:n}),i="(\\(.*\\))?\\s*\\B[-=]>",o={cN:"params",b:"\\([^\\(]",rB:!0,c:[{b:/\(/,e:/\)/,k:c,c:["self"].concat(t)}]};return{aliases:["coffee","cson","iced"],k:c,i:/\/\*/,c:t.concat([e.C("###","###"),e.HCM,{cN:"function",b:"^\\s*"+n+"\\s*=\\s*"+i,e:"[-=]>",rB:!0,c:[s,o]},{b:/[:\(,=]\s*/,r:0,c:[{cN:"function",b:i,e:"[-=]>",rB:!0,c:[o]}]},{cN:"class",bK:"class",e:"$",i:/[:="\[\]]/,c:[{bK:"extends",eW:!0,i:/[:="\[\]]/,c:[s]},s]},{cN:"attribute",b:n+":",e:":",rB:!0,rE:!0,r:0}])}});hljs.registerLanguage("javascript",function(e){return{aliases:["js"],k:{keyword:"in of if for while finally var new function do return void else break catch instanceof with throw case default try this switch continue typeof delete let yield const export super debugger as async await",literal:"true false null undefined NaN Infinity",built_in:"eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent encodeURI encodeURIComponent escape unescape Object Function Boolean Error EvalError InternalError RangeError ReferenceError StopIteration SyntaxError TypeError URIError Number Math Date String RegExp Array Float32Array Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect Promise"},c:[{cN:"pi",r:10,b:/^\s*['"]use (strict|asm)['"]/},e.ASM,e.QSM,{cN:"string",b:"`",e:"`",c:[e.BE,{cN:"subst",b:"\\$\\{",e:"\\}"}]},e.CLCM,e.CBCM,{cN:"number",v:[{b:"\\b(0[bB][01]+)"},{b:"\\b(0[oO][0-7]+)"},{b:e.CNR}],r:0},{b:"("+e.RSR+"|\\b(case|return|throw)\\b)\\s*",k:"return throw case",c:[e.CLCM,e.CBCM,e.RM,{b:/\s*[);\]]/,r:0,sL:"xml"}],r:0},{cN:"function",bK:"function",e:/\{/,eE:!0,c:[e.inherit(e.TM,{b:/[A-Za-z$_][0-9A-Za-z$_]*/}),{cN:"params",b:/\(/,e:/\)/,eB:!0,eE:!0,c:[e.CLCM,e.CBCM]}],i:/\[|%/},{b:/\$[(.]/},{b:"\\."+e.IR,r:0},{bK:"import",e:"[;$]",k:"import from as",c:[e.ASM,e.QSM]},{cN:"class",bK:"class",e:/[{;=]/,eE:!0,i:/[:"\[\]]/,c:[{bK:"extends"},e.UTM]}],i:/#/}}); \ No newline at end of file diff --git a/app/assets/javascripts/app/views/channel/chat.jst.eco b/app/assets/javascripts/app/views/channel/chat.jst.eco index 2da6a4e68..f5afc037c 100644 --- a/app/assets/javascripts/app/views/channel/chat.jst.eco +++ b/app/assets/javascripts/app/views/channel/chat.jst.eco @@ -1,188 +1,239 @@ -

<%- @T('You can create chat widgets for your webpages to allow visitors to chat with you.') %>

- -<% if _.isEmpty(@chats): %> -

<%- @T('You have no configured chat\'s right now.') %>

-<% else: %> - - - - - - - - - - -<% for chat in @chats: %> - - - -
<%- @T('Name') %><%- @T('Note') %><%- @T('Max Queue') %><%- @T('Delete') %>
- - - - - - -
-
- <%- @Icon('trash') %> <%- @T('Remove') %> -
-
-<% end %> -
- - - -
- <%- @Icon('plus-small') %> <%- @T('Add') %> -
- -
-<% end %> - -

<%- @T('Designer') %>

- -
- -
-
-
iPhone 6
-
<%- @T('Fit Width') %>
-
MacBook
-
+ +
+

<%- @T('You can create chat widgets for your webpages to allow visitors to chat with you.') %>

-
-
-
- -
-
-
- - -
-
-
-
- <%- @T('Online') %> - - - - +

<%- @T('Channels') %>

+

<%- @T('You can create multiple chat channels.') %>

+ + + + + + + + + + + <% for chat in @chats: %> + + + +
<%- @T('Name') %><%- @T('Note') %><%- @T('Max Queue') %><%- @T('Delete') %>
+ + + + + + +
+
+ <%- @Icon('trash') %> <%- @T('Remove') %> +
-
- - - <%- @T('John Smith') %> - -
-
- - <%- @T('Chat with us!') %> -
- -
-
<%- @T('Today') %> 14:45
-
- <%- @T('Hello! I need help with your product.') %> -
-
- <%- @T('Hi! Which one of our products?') %> -
-
-
- - -
+ <% end %> +
+ <%- @Icon('plus-small') %> +
+ +

<%- @T('Designer') %>

+ +
+ +
+
+
iPhone 6
+
<%- @T('Fit Width') %>
+
MacBook
-
-
-
-
-
- -
-
- -
- <%- @T('Shown when the chat is closed.') %> +
+
+ + +
-
-
- +
+ + +
+
+
+
+ <%- @T('Online') %> + + + + +
+
+ + + <%- @T('John Smith') %> + +
+
+ + <%- @T('Chat with us!') %> +
+
+
+
<%- @T('Today') %> 14:45
+
+ <%- @T('Hello! I need help with your product.') %> +
+
+ <%- @T('Hi! Which one of our products?') %> +
+
+
+ + +
+
-
- -
- <%- @T('Can be in any CSS color format.') %>
-
-
- -
-
- -
- <%- @T('The default font size is 12px.') %> -
-
+
-
+
+
+
+
+ +
+
+ +
+ <%- @T('Shown when the chat is closed.') %> +
+
+
+ +
+
+ +
+ <%- @T('Can be in any CSS color format.') %> +
+
+
+ +
+
+ +
+ <%- @T('The default font size is 12px.') %> +
+
+ +
+ + + + + + + + + + + +
<%- @T('Options') %>
+ +
+ +
+
+ +

<%- @T('Usage') %>

+ +

<%- @T('Insert the widget-code into the source code of every page the chat should be visible on. It should be placed at the end of the page source code before the `</body>` closing tag.') %>

+ +

Requirements

+

<%- @T("Zammad Chat requires jQuery. If you don't already use it on your website include it like this:") %>

+
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
+ +

<%- @T('Auto-show chat') %>

+

<%- @T('The chat will show up once the connection to the server got established and if there is someone online to chat with.') %>

+ +
<script src="<%= @baseurl %>/assets/chat/chat.min.js"></script>
+<script>
+$(function() {
+  new ZammadChat({
+
+  });
+});
+</script>
+ +

<%- @T('Manually open chat') %>

+

<%- marked(@T('If you want to open the chat by the press of a button set the option `show` to `false` and add the class `open-zammad-chat` to the button.')) %>

+
<button class="open-zammad-chat">Chat with us</button>
+
+<script src="<%= @baseurl %>/assets/chat/chat.min.js"></script>
+<script>
+$(function() {
+  new ZammadChat({
+
+    show: false
+  });
+});
+</script>
+ +

<%- @T("Why doesn't the chat show up?") %>

+

+ <%- @T('There can be several reasons for the chat to not show up:') %> +

    +
  1. <%- @T('The browser is outdated. It does not support WebSocket - the technology we use for the chat.') %> +
  2. <%- @T('The is no agent online.') %> +
  3. <%- @T('The chat is turned off.') %> +
  4. <%- @T('There are too many people in queue for the chat.') %> +
+ <%- marked(@T('When you turn on debubbing by setting the option `debug` to `true` the reason gets printed to the javascript console.')) %> +

+ +

<%- @T('Options') %>

- - + + <% for option in @apiOptions: %> - -
<%- @T('Options') %>
<%- @T('Options') %> + <%- @T('Default') %> + <%- @T('Type') %> + <%- @T('Description') %>
- -
- + <%- @T(option.name) %> + <%= option.default %> + <%= option.type %> + <%- @T(option.description, option.descriptionSubstitute) %> + <% end %>
- -

<%- @T('You need to add the following Java Script code snipped to your web page') %>: - -

-<script src="<%= @baseurl %>/assets/chat/chat.min.js"></script>
-
-<script>
-$(function() {
-new ZammadChat({
-
-});
-});
-</script>
- - -
\ No newline at end of file +
\ No newline at end of file diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 0f610228b..2a62fb00b 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -11,6 +11,7 @@ *= require ./sew.css *= require ./font.css *= require ./svg-dimensions.css + *= require ./highlighter-github.css *= require ./zammad.scss * *= require_tree ./custom/ diff --git a/app/assets/stylesheets/bootstrap.css b/app/assets/stylesheets/bootstrap.css index b089d663c..efc8624aa 100644 --- a/app/assets/stylesheets/bootstrap.css +++ b/app/assets/stylesheets/bootstrap.css @@ -687,13 +687,6 @@ pre, samp { font-family: Menlo, Monaco, Consolas, "Courier New", monospace; } -code { - padding: 2px 4px; - font-size: 90%; - color: #c7254e; - background-color: #f9f2f4; - border-radius: 4px; -} kbd kbd { padding: 0; font-size: 100%; diff --git a/app/assets/stylesheets/highlighter-github.css b/app/assets/stylesheets/highlighter-github.css new file mode 100644 index 000000000..791537e41 --- /dev/null +++ b/app/assets/stylesheets/highlighter-github.css @@ -0,0 +1,123 @@ +/* + +github.com style (c) Vasily Polovnyov + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #333; + background: #f8f8f8; + -webkit-text-size-adjust: none; +} + +.hljs-comment, +.diff .hljs-header { + color: #998; + font-style: italic; +} + +.hljs-keyword, +.css .rule .hljs-keyword, +.hljs-winutils, +.nginx .hljs-title, +.hljs-subst, +.hljs-request, +.hljs-status { + color: #333; + font-weight: bold; +} + +.hljs-number, +.hljs-hexcolor, +.ruby .hljs-constant { + color: #008080; +} + +.hljs-string, +.hljs-tag .hljs-value, +.hljs-doctag, +.tex .hljs-formula { + color: #d14; +} + +.hljs-title, +.hljs-id, +.scss .hljs-preprocessor { + color: #900; + font-weight: bold; +} + +.hljs-list .hljs-keyword, +.hljs-subst { + font-weight: normal; +} + +.hljs-class .hljs-title, +.hljs-type, +.vhdl .hljs-literal, +.tex .hljs-command { + color: #458; + font-weight: bold; +} + +.hljs-tag, +.hljs-tag .hljs-title, +.hljs-rule .hljs-property, +.django .hljs-tag .hljs-keyword { + color: #000080; + font-weight: normal; +} + +.hljs-attribute, +.hljs-variable, +.lisp .hljs-body, +.hljs-name { + color: #008080; +} + +.hljs-regexp { + color: #009926; +} + +.hljs-symbol, +.ruby .hljs-symbol .hljs-string, +.lisp .hljs-keyword, +.clojure .hljs-keyword, +.scheme .hljs-keyword, +.tex .hljs-special, +.hljs-prompt { + color: #990073; +} + +.hljs-built_in { + color: #0086b3; +} + +.hljs-preprocessor, +.hljs-pragma, +.hljs-pi, +.hljs-doctype, +.hljs-shebang, +.hljs-cdata { + color: #999; + font-weight: bold; +} + +.hljs-deletion { + background: #fdd; +} + +.hljs-addition { + background: #dfd; +} + +.diff .hljs-change { + background: #0086b3; +} + +.hljs-chunk { + color: #aaa; +} diff --git a/app/assets/stylesheets/zammad.scss b/app/assets/stylesheets/zammad.scss index 30f049ccc..a1299ee27 100644 --- a/app/assets/stylesheets/zammad.scss +++ b/app/assets/stylesheets/zammad.scss @@ -255,10 +255,9 @@ pre { color: #333; word-break: break-all; word-wrap: break-word; - background: hsl(197,20%,93%); - border: 1px solid hsl(198,18%,86%); + background: white; + border: 1px solid hsl(0,0%,90%); border-radius: 3px; - box-shadow: 0 1px 3px rgba(0,0,0,.05) inset; } pre code { padding: 0; @@ -269,6 +268,23 @@ pre code { border-radius: 0; } +.hljs, +code { + background: none; + padding: 2px 4px; + font-size: 0.88em; +} + +code:not(.hljs) { + border: 1px solid rgba(0,0,0,.2); + border-radius: 3px; + white-space: nowrap; +} + +pre code.hljs { + font-size: 1em; +} + .textarea::placeholder, .form-control::placeholder, .token-input::placeholder { diff --git a/public/assets/chat/chat.coffee b/public/assets/chat/chat.coffee index 10747d815..331250471 100644 --- a/public/assets/chat/chat.coffee +++ b/public/assets/chat/chat.coffee @@ -14,8 +14,8 @@ do($ = window.jQuery, window) -> port: 6042 debug: false fontSize: undefined - buttonSelector: '.open-zammad-chat' - hiddenButtonClass: 'is-inactive' + buttonClass: 'open-zammad-chat' + inactiveClass: 'is-inactive' title: 'Chat with us!' _messageCount: 0 @@ -87,6 +87,9 @@ do($ = window.jQuery, window) -> @input = @el.find('.zammad-chat-input') + # disable open button + $(".#{ @options.buttonClass }").addClass @inactiveClass + @el.find('.js-chat-open').click @open @el.find('.js-chat-close').click @close @el.find('.zammad-chat-controls').on 'submit', @onSubmit @@ -154,14 +157,14 @@ do($ = window.jQuery, window) -> @reopenSession pipe.data onReady: => - $(@options.buttonSelector).click(@open).removeClass(@hiddenButtonClass) + $(".#{ @options.buttonClass }").click(@open).removeClass(@inactiveClass) if @options.show @show() onError: (message) => @log 'debug', message - $(@options.buttonSelector).hide() + $(".#{ @options.buttonClass }").hide() reopenSession: (data) => unfinishedMessage = sessionStorage.getItem 'unfinished_message'