Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New point auto-suggest #172

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions @client/edit_point.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ window.EditPoint = ReactiveComponent
position: 'absolute'
right: 0
top: -21
onInput: (event) =>
if event and event.target
setStateNewPointInput(extractWords(event.target.value))

INPUT
id:'is_pro'
Expand Down Expand Up @@ -242,6 +245,8 @@ window.EditPoint = ReactiveComponent
your_points.editing_points = _.without your_points.editing_points, @props.point

save your_points
clearStateNewPointInput()


savePoint : (ev) ->

Expand Down
8 changes: 7 additions & 1 deletion @client/point.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ window.Point = ReactiveComponent

current_user = fetch('/current_user')

new_point_words = getStateNewPointInput()

renderIncluders = (draw_all_includers) =>

Expand Down Expand Up @@ -111,6 +112,9 @@ window.Point = ReactiveComponent
else
append = null

do_display = [email protected]_point_matches_new_input or !new_point_words or (new_point_words.length <= 0) or \
containsAnyWord(point.nutshell, new_point_words)

LI
key: "point-#{point.id}"
'data-id': @props.point
Expand All @@ -121,6 +125,8 @@ window.Point = ReactiveComponent
if (is_selected && e.which == 27) || e.which == 13 || e.which == 32
@selectPoint(e)
e.preventDefault()
style:
display: if do_display then null else 'none'

if @props.rendered_as == 'decision_board_point'
DIV
Expand Down Expand Up @@ -178,7 +184,7 @@ window.Point = ReactiveComponent
DIV
className: 'point_nutshell'

splitParagraphs point.nutshell, append
splitParagraphs point.nutshell, append, new_point_words



Expand Down
66 changes: 49 additions & 17 deletions @client/pro_con_widget.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,18 @@ window.getProposalMode = (proposal) ->
local_state.mode


window.clearStateNewPointInput = -> setStateNewPointInput(null)

window.setStateNewPointInput = ( new_point_input ) ->
state_of_new_point_input = fetch('new_point_input')
state_of_new_point_input['words'] = new_point_input
save state_of_new_point_input

window.getStateNewPointInput = ( new_point_input ) ->
state_of_new_point_input = fetch('new_point_input')
return if state_of_new_point_input then state_of_new_point_input['words'] else null


window.update_proposal_mode = (proposal, proposal_mode, triggered_by) ->
can_opine = canUserOpine proposal
proposal = fetch proposal
Expand All @@ -31,6 +43,8 @@ window.update_proposal_mode = (proposal, proposal_mode, triggered_by) ->
(can_opine == Permission.DISABLED && your_opinion.key))

proposal_mode = 'results'
else
clearStateNewPointInput()

local_state = fetch shared_local_key proposal
if local_state.mode != proposal_mode
Expand Down Expand Up @@ -326,6 +340,28 @@ window.Reasons = ReactiveComponent
local_proposal.has_focus = has_focus
save local_proposal

# Collect point lists, and check whether any existing point matches the new point being written.
points_community_cons = buildPointsList \
proposal, 'cons', \
(if mode == 'results' then 'score' else 'last_inclusion'), \
mode == 'crafting' && !TABLET_SIZE(), \
mode == 'crafting' || TABLET_SIZE() || (just_you && mode == 'results')
points_community_pros = buildPointsList \
proposal, 'pros', \
(if mode == 'results' then 'score' else 'last_inclusion'), \
mode == 'crafting' && !TABLET_SIZE(), \
mode == 'crafting' || TABLET_SIZE() || (just_you && mode == 'results')
points_my_pros = (p for p in your_opinion.point_inclusions or [] \
when fetch(p).is_pro)
points_my_cons = (p for p in your_opinion.point_inclusions or [] \
when !fetch(p).is_pro)
new_point_words = getStateNewPointInput()
any_point_matches_new_input = false
if new_point_words
all_points = [].concat( points_community_cons, points_community_pros, points_my_pros, points_my_cons )
all_points_data = (fetch(point) for point in all_points)
any_point_matches_new_input = Boolean( all_points_data.some( (point) => containsAnyWord(point.nutshell, new_point_words) ) )

DIV
className: "slow-thought #{if mode == 'crafting' then 'crafting' else 'summary'}"
style:
Expand Down Expand Up @@ -393,6 +429,9 @@ window.Reasons = ReactiveComponent
DecisionBoard
key: 'decisionboard'
proposal: proposal.key
points_my_cons: points_my_cons
points_my_pros: points_my_pros
any_point_matches_new_input: any_point_matches_new_input

DIV
style:
Expand All @@ -407,15 +446,11 @@ window.Reasons = ReactiveComponent
valence: 'cons'
points_draggable: mode == 'crafting'
drop_target: false
points: buildPointsList \
proposal, 'cons', \
(if mode == 'results' then 'score' else 'last_inclusion'), \
mode == 'crafting' && !TABLET_SIZE(), \
mode == 'crafting' || TABLET_SIZE() || (just_you && mode == 'results')
points: points_community_cons
style:
visibility: if !TABLET_SIZE() && mode == 'crafting' && !has_community_points then 'hidden'
in_viewport: @local.in_viewport

any_point_matches_new_input: any_point_matches_new_input

#community pros
PointsList
Expand All @@ -427,14 +462,11 @@ window.Reasons = ReactiveComponent
valence: 'pros'
points_draggable: mode == 'crafting'
drop_target: false
points: buildPointsList \
proposal, 'pros', \
(if mode == 'results' then 'score' else 'last_inclusion'), \
mode == 'crafting' && !TABLET_SIZE(), \
mode == 'crafting' || TABLET_SIZE() || (just_you && mode == 'results')
points: points_community_pros
style:
visibility: if !TABLET_SIZE() && mode == 'crafting' && !has_community_points then 'hidden'
in_viewport: @local.in_viewport
any_point_matches_new_input: any_point_matches_new_input

if !show_all_points
BUTTON
Expand Down Expand Up @@ -681,8 +713,8 @@ window.DecisionBoard = ReactiveComponent
points_editable: true
points_draggable: true
drop_target: are_points_in_wings
points: (p for p in your_opinion.point_inclusions or [] \
when fetch(p).is_pro)
points: @props.points_my_pros
any_point_matches_new_input: @props.any_point_matches_new_input

PointsList
key: 'your_con_points'
Expand All @@ -693,9 +725,8 @@ window.DecisionBoard = ReactiveComponent
points_editable: true
points_draggable: true
drop_target: are_points_in_wings
points: (p for p in your_opinion.point_inclusions or [] \
when !fetch(p).is_pro)

points: @props.points_my_cons
any_point_matches_new_input: @props.any_point_matches_new_input

DIV style: {clear: 'both'}

Expand Down Expand Up @@ -1000,6 +1031,7 @@ window.PointsList = ReactiveComponent
your_points_key: @props.reasons_key
enable_dragging: @props.points_draggable
in_viewport: @props.in_viewport
any_point_matches_new_input: @props.any_point_matches_new_input

else if points.length == 0 && @props.rendered_as == 'community_point' && mode == "results"
opinion_views = fetch 'opinion_views'
Expand Down Expand Up @@ -1501,4 +1533,4 @@ GroupSelectionRegion = ReactiveComponent
color: focus_color()
left: "min(#{wrapper_width - name_width}px, max(0px, calc(#{left}px - #{name_width / 2}px)))" #Math.min(wrapper_width - name_width - 10, Math.max(0, left - name_width / 2))
title


45 changes: 44 additions & 1 deletion @client/shared.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -506,9 +506,43 @@ safe_string = (user_content) ->

user_content

window.splitParagraphs = (user_content, append) ->

window.STOP_WORDS = new Set( [
"a", "about", "above", "after", "again", "against", "all", "am", "an", "and", "any", "are", "aren't",
"as", "at", "be", "because", "been", "before", "being", "below", "between", "both", "but", "by",
"can't", "cannot", "could", "couldn't", "did", "didn't", "do", "does", "doesn't", "doing", "don't",
"down", "during", "each", "few", "for", "from", "further", "had", "hadn't", "has", "hasn't", "have",
"haven't", "having", "he", "he'd", "he'll", "he's", "her", "here", "here's", "hers", "herself", "him",
"himself", "his", "how", "how's", "i", "i'd", "i'll", "i'm", "i've", "if", "in", "into", "is", "isn't",
"it", "it's", "its", "itself", "let's", "me", "more", "most", "mustn't", "my", "myself", "nor", "not",
"of", "off", "on", "once", "only", "or", "other", "ought", "our", "ours", "ourselves", "out", "over",
"own", "same", "shan't", "she", "she'd", "she'll", "she's", "should", "shouldn't", "so", "some", "such",
"than", "that", "that's", "the", "their", "theirs", "them", "themselves", "then", "there", "there's",
"these", "they", "they'd", "they'll", "they're", "they've", "this", "those", "through", "to", "too",
"under", "until", "up", "very", "was", "wasn't", "we", "we'd", "we'll", "we're", "we've", "were",
"weren't", "what", "what's", "when", "when's", "where", "where's", "which", "while", "who", "who's",
"whom", "why", "why's", "with", "won't", "would", "wouldn't", "you", "you'd", "you'll", "you're",
"you've", "your", "yours", "yourself", "yourselves" ] )

window.extractWords = ( text ) ->
# Split discarding non-alpha-numeric delimiters, lowercase, filter stop-words
words = if text then text.toLowerCase().split( /\W+/ ) else []
return words.filter( (w) -> !STOP_WORDS.has(w) and (1 < w.length) )

window.containsAnyWord = ( text, words ) ->
return words and extractTokens(text).some( (token) => words.find((word) => (word==token.toLowerCase())) )

window.extractTokens = ( text ) ->
# Split keeping delimiters, punctuation, original case
tokens = if text then text.split( /(\W+)/ ) else []
return tokens


window.splitParagraphs = (user_content, append, highlightWords) ->
if !user_content
return SPAN null

highlightWords = highlightWords or null

user_content = safe_string user_content

Expand All @@ -527,6 +561,15 @@ window.splitParagraphs = (user_content, append) ->
if text.substring(0,5) == 'link:'
A key: idx, href: text.substring(5, text.length), target: '_blank',
text.substring(5, text.length)
else if highlightWords
SPAN
key: idx
for token,tokenIndex in extractTokens(text)
SPAN
key:tokenIndex
style:
backgroundColor: if highlightWords.includes(token.toLowerCase()) then 'yellow' else null
token
else
SPAN key: idx, text

Expand Down