Skip to content
This repository was archived by the owner on Feb 20, 2020. It is now read-only.

ability to at-mention users in bucket comments #383

Open
wants to merge 22 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
f7ad863
[WIP] playing around with at mention
jlopker Sep 22, 2017
86121bc
Merge branch 'master' into feature/at-mention
jlopker Sep 27, 2017
dd710a8
ability to pick a username
jlopker Sep 28, 2017
8bb7a31
Merge branch 'master' into feature/at-mention
jlopker Nov 15, 2017
340a206
styling mentio
jlopker Nov 15, 2017
0ed3eed
styles
jlopker Nov 20, 2017
42eddbf
Merge branch 'master' into feature/at-mention
jlopker Nov 27, 2017
ea9cdad
[WIP] at mentions highlighting with bugs
jlopker Nov 28, 2017
64a208e
Merge branch 'master' into feature/at-mention
jlopker Dec 16, 2017
e7b5311
less buggy, creates list of mentioned users to send to backend
jlopker Dec 16, 2017
f6a85d5
switch to html5mode, remove dep on ecstatic, use plain express for ro…
jlopker Dec 16, 2017
e4433bf
remove comment print out
jlopker Dec 16, 2017
0af76cd
added user profile pages, updated angular-record-store
jlopker Dec 31, 2017
27cf1e6
show mobile view
jlopker Jan 5, 2018
14546fb
Merge branch 'master' into feature/at-mention
jlopker Jan 30, 2018
7fe521d
show/hide for different screens to make sure that the mentio widget d…
jlopker Feb 7, 2018
39ba4f1
convert at-mentions into markup before sending to the backend
jlopker Feb 8, 2018
5333084
add loadbar to user page
jlopker Feb 9, 2018
72e0f2c
Merge branch 'master' into feature/at-mention
jlopker Feb 9, 2018
25fbe3e
using jquery to convert contenteditable div content into markdown
jlopker Feb 22, 2018
1ed3a3e
remove previous bucket_id option
jlopker Feb 22, 2018
831d0b9
fix for firefox
jlopker Feb 27, 2018
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
1 change: 1 addition & 0 deletions Gulpfile.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ assetPaths = {
"node_modules/font-awesome/**/*": "build/fonts/font-awesome"
"node_modules/angular-material/angular-material.css" : "build/styles"
"node_modules/angular-material-data-table/dist/md-data-table.min.css" : "build/styles"
"app/directives/bucket-page-activity-card/mentio-menu.tpl.html" : "build"
}

assets = (isWatch) ->
Expand Down
2 changes: 2 additions & 0 deletions app/components/bucket-page/bucket-page.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ module.exports =
controller: (CurrentUser, Error, LoadBar, $location, Records, $scope, $stateParams, Toast, UserCan, $window) ->

LoadBar.start()
$scope.windowWidth = $window.innerWidth
$scope.xsWidth = 768
bucketId = parseInt $stateParams.bucketId
Records.buckets.findOrFetchById(bucketId)
.then (bucket) ->
Expand Down
4 changes: 2 additions & 2 deletions app/components/bucket-page/bucket-page.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<md-content class="bucket-page__content">
<md-button class="bucket-page__group-btn" ng-click="back()">{{ group.name }}</md-button>

<div layout="row" layout-align="start start" class="bucket-page__desktop-layout-container">
<div layout="row" layout-align="start start" class="bucket-page__desktop-layout-container" ng-if="windowWidth >= xsWidth">
<div layout="column" layout-align="center center" class="bucket-page__left-column">
<bucket-page-header-card></bucket-page-header-card>
<bucket-page-activity-card></bucket-page-activity-card>
Expand All @@ -18,7 +18,7 @@
</div>
</div>

<div layout="column" layout-align="center center" class="bucket-page__mobile-layout-container">
<div layout="column" layout-align="center center" class="bucket-page__mobile-layout-container" ng-if="windowWidth <= xsWidth">
<bucket-page-header-card></bucket-page-header-card>
<bucket-page-manage-card ng-if="userCanManageBucket() && !bucket.paidAt"></bucket-page-manage-card>
<bucket-page-status-card></bucket-page-status-card>
Expand Down
22 changes: 22 additions & 0 deletions app/components/user-page/user-page.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module.exports =
resolve:
userValidated: ($auth) ->
$auth.validateUser()
membershipsLoaded: ->
global.cobudgetApp.membershipsLoaded
url: '/users/:userId'
template: require('./user-page.html')
controller: (CurrentUser, Error, $location, Records, $scope, $stateParams, LoadBar) ->

LoadBar.start()

userId = parseInt($stateParams.userId)

Records.users.fetchUserById(userId)
.then (data) ->
LoadBar.stop()
$scope.user = data.user
.catch ->
Error.set('user not found')

return
24 changes: 24 additions & 0 deletions app/components/user-page/user-page.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div class="user-page">
<md-toolbar class="md-whiteframe-z1 user-page__toolbar">
<div class="md-toolbar-tools">
<span class="user-page__header-text">User Profile</span>
</div>
</md-toolbar>

<md-content class="user-page__content">
<div layout="row" layout-align="center center" class="user-page__container">
<div class="user-page__avatar" layout="column" layout-align="center center">
<div>{{ user.name[0] | uppercase }}</div>
</div>

<div layout="column" layout-align="center start" class="user-page__name-container" flex>
<span class="user-page__name">{{ user.name }}</span>

<span class="user-page__email">{{ user.email }}</span>

<span class="user-page__activity">User joined on {{ user.confirmed_at | exactDate }}</span>
</div>
</div>

</md-content>
</div>
51 changes: 51 additions & 0 deletions app/components/user-page/user-page.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.user-page__toolbar {
background: $cobudget-gunmetal !important;
}

.user-page__content {
max-width: 640px;
margin: 0 auto;
}

.user-page__group-list-subheader {
color: $cob-pink;
padding-left: 10px;
}

.user-page__container {
margin-bottom: 10px;
margin-top: 50px;
width: 100%;
}

.user-page__avatar {
width: 100px;
height: 100px;
border-radius: 50%;
background: rgba(0,0,0,0.27);
color: white;
font-size: 50px;
margin-right: 10px;
}

.user-page__name-container {
min-width: 0;
}

.user-page__name {
width: 100%;
@include truncatedText;
@include fontLarge;
}

.user-page__email {
width: 100%;
@include truncatedText;
@include fontMedium;
}

.user-page__activity {
margin-top: 3px;
color: $grey-on-white;
font-size: 11px;
}
5 changes: 4 additions & 1 deletion app/configs/marked.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@
global.cobudgetApp.config (markedProvider) ->
markedProvider.setRenderer
link: (href, title, text) ->
'<a href=\'' + href + '\'' + (if title then ' title=\'' + title + '\'' else '') + ' target=\'_blank\'>' + text + '</a>'
if href.startsWith('uid:')
'<a href=\'#/users/' + href.replace('uid:','') + '\'' + ' target=\'_blank\'>' + text + '</a>'
else
'<a href=\'' + href + '\'' + (if title then ' title=\'' + title + '\'' else '') + ' target=\'_blank\'>' + text + '</a>'
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,38 @@ global.cobudgetApp.directive 'bucketPageActivityCard', () ->
restrict: 'E'
template: require('./bucket-page-activity-card.html')
replace: true
controller: (Records, $scope, Toast) ->
controller: (Records, $scope, Toast, $filter) ->

$scope.newComment = Records.comments.build(bucketId: $scope.bucket.id)

$scope.createComment = ->
$scope.commentCreated = true
newComment = jQuery('.bucket-page__comment-input').clone()

newComment[0].innerHTML = newComment[0].innerHTML
.replace(/(<a(.*?)<\/a>)/g, '')
.replace(/(<!---)/g, '')
.replace(/(-->)/g, '')
.replace(/<div>/gi,'\n')
.replace(/<\/div>/gi,'')
.replace(/<br>/gi,'\n')
$scope.newComment.body = newComment.text()

$scope.newComment.save().then ->
Toast.show('You posted a comment')
$scope.newComment = Records.comments.build(bucketId: $scope.bucket.id)
$scope.commentCreated = false

$scope.getUserText = (item) ->
return '<a href="/users/'+item.userId+'" name='+item.userId+'>@' + item.name + '</a><!---[@' + item.name + '](uid:' + item.userId + ')-->'

$scope.searchUsers = (term) ->
$scope.users = $filter('filter')($scope.allUsers, term)

Records.memberships.fetchByGroupId($scope.group.id).then ->
$scope.allUsers = _.map $scope.group.settledMemberships(), (membership) ->
{name: membership.member().name, email: membership.member().email, userId: membership.member().id}
$scope.users = $scope.allUsers

$scope.openUserPage = ->
$location.path('/user/:id').search('previous_bucket_id', $scope.bucket.id)
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,25 @@
<md-card class="bucket-page__comment-form-card">
<form name='commentForm' class="bucket-page__comment-form" ng-submit="createComment()">
<md-input-container class="bucket-page__comment-input-container" md-no-float>
<textarea type="text" class="bucket-page__comment-input" required placeholder="Ask a question, offer support, give an update..." name="body" ng-model="newComment.body" />
<div contenteditable mentio
mentio-typed-term="typedTerm"
mentio-require-leading-space="true"
class="bucket-page__comment-input"
placeholder="Ask a question, offer support, give an update..."
mentio-id="'newComment.bodyInput'"
ng-model="newComment.bodyInput"
></div>
</md-input-container>

<mentio-menu
mentio-for="'newComment.bodyInput'"
mentio-trigger-char="'@'"
mentio-items="users"
mentio-template-url="/mentio-menu.tpl.html"
mentio-select="getUserText(item)"
mentio-search="searchUsers(term)"
></mentio-menu>

<div class="bucket-page__submit-comment-container">
<a class="bucket-page__comment-form-markdown-link" href="https://www.loomio.org/markdown" target="_blank">formatting help</a>
<md-input-container class="bucket-page__submit-comment-btn-container">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
background: #F8F8F8;
padding: 13px 16px !important;
}
.menu-highlighted {
color: $cob-pink;
}

md-list-item.bucket-page__comment::before {
min-height: auto;
Expand Down Expand Up @@ -79,6 +82,10 @@ md-list-item.bucket-page__comment::before {
display: block;
}

.bucket-page__comment-input-container textarea {
border: 1px solid #8C8C8C !important;
}

.bucket-page__comment-input {
font-size: 15px !important;
line-height: 17px !important;
Expand Down Expand Up @@ -112,3 +119,31 @@ md-list-item.bucket-page__comment::before {
background: $cob-pink !important;
color: white !important;
}

.mentio-menu {
box-shadow: 0 1px 3px rgba(0,0,0,.12), 0 1px 2px rgba(0,0,0,.24);
padding: 0;
}

.mentio-menu__ul {
padding: 0;
margin: 0;
}

.mentio-menu__item {
height: auto;
cursor: pointer;
min-height: 0;
}

.mentio-menu__item > .md-button {
margin: 0;
}

.mentio-menu__item.active, .mentio-menu__item:hover {
background: #ebebeb;
}

.mentio-menu__item:not(:last-child) {
border-bottom: 1px solid #dcdcdc;
}
35 changes: 35 additions & 0 deletions app/directives/bucket-page-activity-card/contenteditable.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
null

### @ngInject ###

global.cobudgetApp.directive 'contenteditable', ($sce) ->
restrict: 'A'
require: '?ngModel'
link: (scope, element, attrs, ngModel) ->

read = ->
html = element.html()
# When we clear the content editable the browser leaves a <br> behind
# If strip-br attribute is provided then we strip this out
if attrs.stripBr and html == '<br>'
html = ''
ngModel.$setViewValue html
return

if !ngModel
return
# do nothing if no ng-model
# Specify how UI should be updated

ngModel.$render = ->
if ngModel.$viewValue != element.html()
element.html $sce.getTrustedHtml(ngModel.$viewValue or '')
return

# Listen for change events to enable binding
element.on 'blur keyup change', ->
scope.$apply read
return
read()
# initialize
return
9 changes: 9 additions & 0 deletions app/directives/bucket-page-activity-card/mentio-menu.tpl.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<md-menu-content class="mentio-menu" style="display:block">
<ul class="mentio-menu__ul">
<md-menu-item class="mentio-menu__item" mentio-menu-item="user" ng-repeat="user in items track by $index">
<md-button aria-label="{{user.name}}">
<strong ng-bind-html="user.name | mentioHighlight:typedTerm:'menu-highlighted' | unsafe"></strong>
</md-button>
</md-menu-item>
</ul>
</md-menu-content>
2 changes: 2 additions & 0 deletions app/directives/group-page-funders/group-page-funders.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ global.cobudgetApp.directive 'groupPageFunders', () ->
Records.memberships.fetchByGroupId($scope.group.id).then ->
$scope.fundersLoaded = true

console.log $scope.group.settledMemberships()

$scope.toggleMemberAdmin = (membership) ->
membership.isAdmin = !membership.isAdmin
params =
Expand Down
4 changes: 3 additions & 1 deletion app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ require('angular-chart.js')
require('angular-autodisable/angular-autodisable')
require('highcharts-ng')
require('angular-material-data-table')
require('ment.io')

if (process.env.NODE_ENV != 'production') {
global.localStorage.debug = "*"
Expand All @@ -52,7 +53,8 @@ global.cobudgetApp = angular.module('cobudget', [
'chart.js',
'ngAutodisable',
'highcharts-ng',
'md.data.table'
'md.data.table',
'mentio'
])
.constant('config', require('app/configs/app'))

Expand Down
1 change: 1 addition & 0 deletions app/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
@import './components/group-page/group-page.scss';
@import './components/create-bucket-page/create-bucket-page.scss';
@import './components/bucket-page/bucket-page.scss';
@import './components/user-page/user-page.scss';
@import './components/edit-bucket-page/edit-bucket-page.scss';
@import './components/admin-page/admin-page.scss';
@import './components/confirm-account-page/confirm-account-page.scss';
Expand Down
6 changes: 6 additions & 0 deletions app/records-interfaces/user-records-interface.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ global.cobudgetApp.factory 'UserRecordsInterface', (config, BaseRecordsInterface
updatePassword: (params) ->
@remote.post('update_password', params)

fetchUserById: (userId) ->
deferred = $q.defer()
@remote.get(userId, {}).then (user) ->
deferred.resolve(user)
deferred.promise

fetchMe: ->
deferred = $q.defer()
if @find(global.cobudgetApp.currentUserId)
Expand Down
7 changes: 4 additions & 3 deletions app/routes.coffee
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
### @ngInject ###

# Since Angular 1.6 the default hash-prefix used for $location has changed from the empty string
# to the bank ('!'). Since we're sending out links with only the hash, this needs to be set
# to the empty string
global.cobudgetApp.config(['$locationProvider', ($locationProvider) ->
# to the bank ('!'). Since we're sending out links with only the hash, this needs to be set
# to the empty string
global.cobudgetApp.config(['$locationProvider', ($locationProvider) ->
$locationProvider.hashPrefix('')])

global.cobudgetApp.config ($stateProvider, $urlRouterProvider) ->
Expand All @@ -15,6 +15,7 @@ global.cobudgetApp.config ($stateProvider, $urlRouterProvider) ->
.state 'create-bucket', require('app/components/create-bucket-page/create-bucket-page.coffee')
.state 'bucket', require('app/components/bucket-page/bucket-page.coffee')
.state 'edit-bucket', require('app/components/edit-bucket-page/edit-bucket-page.coffee')
.state 'user', require('app/components/user-page/user-page.coffee')
.state 'admin', require('app/components/admin-page/admin-page.coffee')
.state 'confirm-account', require('app/components/confirm-account-page/confirm-account-page.coffee')
.state 'group-setup', require('app/components/group-setup-page/group-setup-page.coffee')
Expand Down
Loading