Init version of highlighter.
This commit is contained in:
parent
8c651959a8
commit
e590248307
9 changed files with 241 additions and 27 deletions
|
@ -0,0 +1,179 @@
|
|||
class App.TicketZoomHighlighter extends App.Controller
|
||||
elements:
|
||||
'.textBubble-content': 'articles'
|
||||
'.js-highlight .marker-icon': 'highlighterControl'
|
||||
|
||||
events:
|
||||
'click .js-highlight': 'toggleHighlight'
|
||||
'click .js-highlightColor': 'pickColor'
|
||||
|
||||
colors: [
|
||||
{
|
||||
name: 'Yellow'
|
||||
color: "#f7e7b2"
|
||||
},
|
||||
{
|
||||
name: 'Green'
|
||||
color: "#bce7b6"
|
||||
},
|
||||
{
|
||||
name: 'Blue'
|
||||
color: "#b3ddf9"
|
||||
},
|
||||
{
|
||||
name: 'Pink'
|
||||
color: "#fea9c5"
|
||||
},
|
||||
{
|
||||
name: 'Purple'
|
||||
color: "#eac5ee"
|
||||
}
|
||||
]
|
||||
|
||||
activeColorIndex: 0
|
||||
highlightClassPrefix: 'highlight-'
|
||||
|
||||
constructor: ->
|
||||
super
|
||||
|
||||
#@articles = @el.closest('.content').find('.textBubble-content')
|
||||
|
||||
rangy.init()
|
||||
|
||||
@highlighter = rangy.createHighlighter(document, 'TextRange')
|
||||
|
||||
@addClassApplier entry for entry in @colors
|
||||
|
||||
@setColor()
|
||||
@render()
|
||||
|
||||
# store original highlight css data
|
||||
@storeOriginalHighlight()
|
||||
|
||||
@loadHighlights()
|
||||
|
||||
render: ->
|
||||
@html App.view('ticket_zoom/highlighter')
|
||||
colors: @colors
|
||||
activeColorIndex: @activeColorIndex
|
||||
|
||||
storeOriginalHighlight: =>
|
||||
@originalHighlight =
|
||||
fill: @highlighterControl.css('fill')
|
||||
opacity: @highlighterControl.css('opacity')
|
||||
|
||||
restoreOriginalHighlight: =>
|
||||
return if !@originalHighlight
|
||||
@highlighterControl.css('fill', @originalHighlight.fill)
|
||||
@highlighterControl.css('opacity', @originalHighlight.opacity)
|
||||
|
||||
highlightEnable: =>
|
||||
@isActive = true
|
||||
@highlighterControl.css('opacity', 1)
|
||||
|
||||
highlightDisable: =>
|
||||
@isActive = false
|
||||
@restoreOriginalHighlight()
|
||||
#@highlighterControl.css('opacity', @originalHighlight.opacity)
|
||||
|
||||
active: =>
|
||||
@isActive
|
||||
|
||||
# for testing purposes the highlights get stored in localStorage
|
||||
loadHighlights: ->
|
||||
if highlights = localStorage['highlights']
|
||||
@highlighter.deserialize localStorage['highlights']
|
||||
|
||||
# the serialization creates one string for the entiery ticket
|
||||
# containing the offsets and the highlight classes
|
||||
#
|
||||
# we have to check how it works with having open several tickets – it might break
|
||||
#
|
||||
# if classes can be changed in the admin interface
|
||||
# we have to watch out to not end up with empty highlight classes
|
||||
storeHighlights: ->
|
||||
localStorage['highlights'] = @highlighter.serialize()
|
||||
|
||||
# the colors is set via css classes (can't do it inline with rangy)
|
||||
# thus we have to create a stylesheet if the colors
|
||||
# can be changed in the admin interface
|
||||
addClassApplier: (entry) ->
|
||||
@highlighter.addClassApplier rangy.createCssClassApplier(@highlightClassPrefix + entry.name)
|
||||
|
||||
setColor: ->
|
||||
@highlightClass = @highlightClassPrefix + @colors[@activeColorIndex].name
|
||||
|
||||
if @isActive
|
||||
@articles.attr('data-highlightcolor', @colors[@activeColorIndex].name)
|
||||
|
||||
toggleHighlight: (e) =>
|
||||
if @isActive
|
||||
@restoreOriginalHighlight()
|
||||
else
|
||||
@highlightEnable()
|
||||
return
|
||||
|
||||
console.log('toggleHighlight', @isActive, @articles)
|
||||
if @isActive
|
||||
$(e.currentTarget).removeClass('active')
|
||||
@isActive = false
|
||||
@articles.off('mouseup', @onMouseUp)
|
||||
@articles.removeAttr('data-highlightcolor')
|
||||
else
|
||||
selection = rangy.getSelection()
|
||||
# if there's already something selected,
|
||||
# don't go into highlight mode
|
||||
# just toggle the selected
|
||||
if !selection.isCollapsed
|
||||
@toggleHighlightAtSelection $(selection.anchorNode).closest @articles.selector
|
||||
else
|
||||
# toggle ui
|
||||
$(e.currentTarget).addClass('active')
|
||||
|
||||
# activate selection background
|
||||
@articles.attr('data-highlightcolor', @colors[@activeColorIndex].name)
|
||||
|
||||
@isActive = true
|
||||
@articles.on('mouseup', @onMouseUp) #future: touchend
|
||||
|
||||
pickColor: (e) =>
|
||||
@$('.js-highlightColor .visibility-change.active').removeClass('active')
|
||||
$(e.currentTarget).find('.visibility-change').addClass('active')
|
||||
@activeColorIndex = $(e.currentTarget).attr('data-key')
|
||||
|
||||
|
||||
@isActive = true
|
||||
console.log('ooo', @activeColorIndex, @colors[@activeColorIndex].color, @colors[@activeColorIndex])
|
||||
@highlighterControl.css('fill', @colors[@activeColorIndex].color)
|
||||
@highlighterControl.css('opacity', 1)
|
||||
@setColor()
|
||||
|
||||
onMouseUp: (e) =>
|
||||
#@toggleHighlightAtSelection $(e.currentTarget).closest('.textBubble-content')# @articles.selector
|
||||
|
||||
#
|
||||
# toggle Highlight
|
||||
# ================
|
||||
#
|
||||
# - only works when the selection starts and ends inside an article
|
||||
# - clears highlights in selection
|
||||
# - or highlights the selection
|
||||
# - clears the selection
|
||||
|
||||
toggleHighlightAtSelection: (article) =>
|
||||
selection = rangy.getSelection()
|
||||
|
||||
if @highlighter.selectionOverlapsHighlight selection
|
||||
@highlighter.unhighlightSelection()
|
||||
else
|
||||
@highlighter.highlightSelection @highlightClass,
|
||||
selection: selection
|
||||
containerElementId: article.get(0).id
|
||||
|
||||
# remove selection
|
||||
selection.removeAllRanges()
|
||||
|
||||
@highlightDisable()
|
||||
|
||||
|
||||
#@storeHighlights()
|
|
@ -4,10 +4,14 @@
|
|||
<div class="scrollPageHeader">
|
||||
<small><%- @C('ticket_hook') %> <span class="ticket-number"><%- @ticket.number %></span></small>
|
||||
<div class="ticket-title"></div>
|
||||
<div class="highlighter"></div>
|
||||
<div class="overview-navigator"></div>
|
||||
</div>
|
||||
<div class="overview-navigator horizontal"></div>
|
||||
<div class="page-header">
|
||||
<div class="ticketZoom-controls">
|
||||
<div class="highlighter"></div>
|
||||
<div class="overview-navigator"></div>
|
||||
</div>
|
||||
<div class="ticketZoom-header">
|
||||
<div class="flex vertical center">
|
||||
<div class="js-avatar"></div>
|
||||
<div class="ticket-title"></div>
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<div class="btn btn--action btn--split--first js-highlight centered">
|
||||
<svg class="marker-icon"><use xlink:href="#icon-marker" /></svg>
|
||||
</div>
|
||||
<div class="dropdown dropdown--actions">
|
||||
<div class="btn btn--action btn--split--last btn--slim centered" data-toggle="dropdown" aria-expanded="true">
|
||||
<svg class="icon-arrow-down"><use xlink:href="#icon-arrow-down" /></svg>
|
||||
</div>
|
||||
<ul class="dropdown-menu dropdown-menu-right" role="menu">
|
||||
<% for entry, i in @colors: %>
|
||||
<li role="presentation">
|
||||
<a role="menuitem" tabindex="-1" class="js-highlightColor" data-key="<%= i %>">
|
||||
<span class="dropdown-iconSpacer">
|
||||
<span class="color-swatch icon" style="background: <%= entry.color %>"></span>
|
||||
</span>
|
||||
<%= entry.name %>
|
||||
<span class="dropdown-activeSpacer visibility-change<%= ' active' if i is @activeColorIndex %>">
|
||||
<span class="white checkmark icon" data-visible="active"></span>
|
||||
</span>
|
||||
</a>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
|
@ -1,4 +1,4 @@
|
|||
<div class="pagination-counter align-right" title="<%- @Ti(@title) %>">
|
||||
<div class="pagination-counter" title="<%- @Ti(@title) %>">
|
||||
<span class="pagination-item-current"><%= @current_position %></span>/<span class="pagination-total-items"><%= @total_count %></span>
|
||||
</div>
|
||||
<ul class="pagination">
|
||||
|
|
|
@ -1835,7 +1835,7 @@ footer {
|
|||
@extend .u-clickable, .zIndex-5;
|
||||
}
|
||||
|
||||
.logo .activity-counter {
|
||||
.icon-logo .activity-counter {
|
||||
height: 19px;
|
||||
min-width: 19px;
|
||||
position: absolute;
|
||||
|
@ -2740,6 +2740,7 @@ footer {
|
|||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
padding: 28px 0 0 0;
|
||||
}
|
||||
|
||||
.marker-icon {
|
||||
|
@ -2749,8 +2750,8 @@ footer {
|
|||
height: 19px;
|
||||
}
|
||||
|
||||
.ticketZoom .page-header {
|
||||
margin-top: 24px;
|
||||
.ticketZoom .ticketZoom-header {
|
||||
margin-top: 6px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
|
@ -4914,6 +4915,10 @@ label + .wizard-buttonList {
|
|||
}
|
||||
}
|
||||
|
||||
.highlighter {
|
||||
@extend .horizontal;
|
||||
}
|
||||
|
||||
[data-highlightcolor=Yellow]::selection { background: #f7e7b2; }
|
||||
[data-highlightcolor=Yellow]::-moz-selection { background: #f7e7b2; }
|
||||
.highlight-Yellow { background: #f7e7b2; }
|
||||
|
@ -4957,7 +4962,11 @@ label + .wizard-buttonList {
|
|||
}
|
||||
|
||||
.overview-navigator {
|
||||
display: inherit;
|
||||
@extend .horizontal;
|
||||
}
|
||||
|
||||
.overview-navigator .pagination {
|
||||
margin: 0 0 0 10px;
|
||||
}
|
||||
|
||||
.empty-space {
|
||||
|
|
|
@ -72,7 +72,7 @@ class AgentTicketActionLevel1Test < TestCase
|
|||
|
||||
# check if merged to ticket is shown now
|
||||
watch_for(
|
||||
css: '.active .page-header .ticket-number',
|
||||
css: '.active .ticketZoom-header .ticket-number',
|
||||
value: ticket1[:number],
|
||||
)
|
||||
watch_for(
|
||||
|
@ -128,7 +128,7 @@ class AgentTicketActionLevel1Test < TestCase
|
|||
|
||||
# check if merged to ticket is shown now
|
||||
watch_for(
|
||||
css: '.active .page-header .ticket-number',
|
||||
css: '.active .ticketZoom-header .ticket-number',
|
||||
value: ticket3[:number],
|
||||
)
|
||||
watch_for(
|
||||
|
|
|
@ -51,7 +51,7 @@ class AgentTicketActionLevel6Test < TestCase
|
|||
# check if ticket is shown
|
||||
location_check( url: '#ticket/zoom/' )
|
||||
sleep 2
|
||||
ticket_number = @browser.find_elements( { css: '.active .page-header .ticket-number' } )[0].text
|
||||
ticket_number = @browser.find_elements( { css: '.active .ticketZoom-header .ticket-number' } )[0].text
|
||||
|
||||
#
|
||||
# attachment checks - update ticket
|
||||
|
|
|
@ -87,7 +87,7 @@ class AgentTicketOverviewLevel1Test < TestCase
|
|||
)
|
||||
match(
|
||||
browser: browser2,
|
||||
css: '.active .page-header .ticket-number',
|
||||
css: '.active .ticketZoom-header .ticket-number',
|
||||
value: ticket3[:number],
|
||||
)
|
||||
|
||||
|
@ -102,7 +102,7 @@ class AgentTicketOverviewLevel1Test < TestCase
|
|||
)
|
||||
match(
|
||||
browser: browser2,
|
||||
css: '.active .page-header .ticket-number',
|
||||
css: '.active .ticketZoom-header .ticket-number',
|
||||
value: ticket2[:number],
|
||||
)
|
||||
|
||||
|
@ -117,7 +117,7 @@ class AgentTicketOverviewLevel1Test < TestCase
|
|||
)
|
||||
match(
|
||||
browser: browser2,
|
||||
css: '.active .page-header .ticket-number',
|
||||
css: '.active .ticketZoom-header .ticket-number',
|
||||
value: ticket1[:number],
|
||||
)
|
||||
|
||||
|
@ -138,7 +138,7 @@ class AgentTicketOverviewLevel1Test < TestCase
|
|||
)
|
||||
match(
|
||||
browser: browser2,
|
||||
css: '.active .page-header .ticket-number',
|
||||
css: '.active .ticketZoom-header .ticket-number',
|
||||
value: ticket1[:number],
|
||||
)
|
||||
click(
|
||||
|
@ -153,7 +153,7 @@ class AgentTicketOverviewLevel1Test < TestCase
|
|||
)
|
||||
match(
|
||||
browser: browser2,
|
||||
css: '.active .page-header .ticket-number',
|
||||
css: '.active .ticketZoom-header .ticket-number',
|
||||
value: ticket2[:number],
|
||||
)
|
||||
end
|
||||
|
|
|
@ -1080,7 +1080,7 @@ wait untill text in selector disabppears
|
|||
id.gsub!(//, )
|
||||
id.gsub!(%r{^.+?/(\d+)$}, '\\1')
|
||||
|
||||
element = instance.find_elements( { css: '.active .page-header .ticket-number' } )[0]
|
||||
element = instance.find_elements( { css: '.active .ticketZoom-header .ticket-number' } )[0]
|
||||
if element
|
||||
number = element.text
|
||||
ticket = {
|
||||
|
@ -1121,28 +1121,28 @@ wait untill text in selector disabppears
|
|||
data = params[:data]
|
||||
|
||||
if data[:title]
|
||||
#element = instance.find_elements( { :css => '.content.active .page-header .ticket-title-update' } )[0]
|
||||
#element = instance.find_elements( { :css => '.content.active .ticketZoom-header .ticket-title-update' } )[0]
|
||||
#element.clear
|
||||
#sleep 0.5
|
||||
#element = instance.find_elements( { :css => '.content.active .page-header .ticket-title-update' } )[0]
|
||||
#element = instance.find_elements( { :css => '.content.active .ticketZoom-header .ticket-title-update' } )[0]
|
||||
#element.send_keys( data[:title] )
|
||||
#sleep 0.5
|
||||
#element.send_keys( :tab )
|
||||
|
||||
instance.execute_script( '$(".content.active .page-header .ticket-title-update").focus()' )
|
||||
instance.execute_script( '$(".content.active .page-header .ticket-title-update").text("' + data[:title] + '")' )
|
||||
instance.execute_script( '$(".content.active .page-header .ticket-title-update").blur()' )
|
||||
instance.execute_script( '$(".content.active .page-header .ticket-title-update").trigger("blur")' )
|
||||
instance.execute_script( '$(".content.active .ticketZoom-header .ticket-title-update").focus()' )
|
||||
instance.execute_script( '$(".content.active .ticketZoom-header .ticket-title-update").text("' + data[:title] + '")' )
|
||||
instance.execute_script( '$(".content.active .ticketZoom-header .ticket-title-update").blur()' )
|
||||
instance.execute_script( '$(".content.active .ticketZoom-header .ticket-title-update").trigger("blur")' )
|
||||
# {
|
||||
# :where => :instance2,
|
||||
# :execute => 'sendkey',
|
||||
# :css => '.content.active .page-header .ticket-title-update',
|
||||
# :css => '.content.active .ticketZoom-header .ticket-title-update',
|
||||
# :value => 'TTT',
|
||||
# },
|
||||
# {
|
||||
# :where => :instance2,
|
||||
# :execute => 'sendkey',
|
||||
# :css => '.content.active .page-header .ticket-title-update',
|
||||
# :css => '.content.active .ticketZoom-header .ticket-title-update',
|
||||
# :value => :tab,
|
||||
# },
|
||||
end
|
||||
|
@ -1288,7 +1288,7 @@ wait untill text in selector disabppears
|
|||
data = params[:data]
|
||||
|
||||
if data[:title]
|
||||
title = instance.find_elements( { css: '.content.active .page-header .ticket-title-update' } )[0].text.strip
|
||||
title = instance.find_elements( { css: '.content.active .ticketZoom-header .ticket-title-update' } )[0].text.strip
|
||||
if title =~ /#{data[:title]}/i
|
||||
assert( true, "matching '#{data[:title]}' in title '#{title}'" )
|
||||
else
|
||||
|
@ -1328,7 +1328,7 @@ wait untill text in selector disabppears
|
|||
sleep 1
|
||||
instance.find_elements( { partial_link_text: params[:number] } )[0].click
|
||||
sleep 1
|
||||
number = instance.find_elements( { css: '.active .page-header .ticket-number' } )[0].text
|
||||
number = instance.find_elements( { css: '.active .ticketZoom-header .ticket-number' } )[0].text
|
||||
if number !~ /#{params[:number]}/
|
||||
screenshot( browser: instance, comment: 'ticket_open_by_overview_failed' )
|
||||
fail "unable to search/find ticket #{params[:number]}!"
|
||||
|
@ -1376,7 +1376,7 @@ wait untill text in selector disabppears
|
|||
|
||||
# open ticket
|
||||
instance.find_element( { partial_link_text: params[:number] } ).click
|
||||
number = instance.find_elements( { css: '.active .page-header .ticket-number' } )[0].text
|
||||
number = instance.find_elements( { css: '.active .ticketZoom-header .ticket-number' } )[0].text
|
||||
if number !~ /#{params[:number]}/
|
||||
screenshot( browser: instance, comment: 'ticket_open_by_search_failed' )
|
||||
fail "unable to search/find ticket #{params[:number]}!"
|
||||
|
|
Loading…
Reference in a new issue