Merge branch 'smart-annotations' of https://github.com/biosistemika/scinote-web into zd_SCI_834

This commit is contained in:
zmagod 2017-01-10 14:22:04 +01:00
commit fc76a4ae6d
10 changed files with 204 additions and 97 deletions

View file

@ -1,72 +0,0 @@
(function() {
'use strict';
$(document).on(
'focus',
'[data-atwho-users-edit]',
function() {
if (_.isUndefined($(this).data('atwho'))) {
$(this)
.atwho({
at: '@',
callbacks: {
remoteFilter: function(query, callback) {
$.getJSON(
'/organizations/1/atwho_users.json',
{query: query},
function(data) {
callback(data.users);
}
);
},
tplEval: function(_tpl, map) {
var res;
try {
res = '';
res += '<li class="atwho-li atwho-li-user">';
res += '<img src="' + map.img_url + '" height="20" width="20" />';
res += '&nbsp;';
res += '<span data-full-name>';
res += map.full_name;
res += '</span>';
res += '&nbsp;';
res += '<i class="fa fa-circle" aria-hidden="true"></i>';
res += '&nbsp;';
res += '<small data-email>';
res += map.email;
res += '</small>';
res += '</li>';
} catch (_error) {
res = '';
}
return res;
},
highlighter: function(li, query) {
var li2 = $(li);
li2.addClass('highlighted');
var prevVal =
li2
.find('[data-full-name]')
.html();
var newVal =
prevVal
.replace(query, '<strong>' + query + '</strong>');
li2.find('[data-full-name]').html(newVal);
prevVal =
li2
.find('[data-email]')
.html();
newVal =
prevVal
.replace(query, '<strong>' + query + '</strong>');
li2.find('[data-email]').html(newVal);
return li2.html();
}
},
insertTpl: '[${atwho-at}${full_name}~${id}]',
limit: 5,
startWithSpace: true
});
}
});
})();

View file

@ -0,0 +1,110 @@
(function() {
'use strict';
$(document).on(
'focus',
'[data-atwho-users-edit]',
function() {
// Only initialize if URL is present and
// atwho is not initialized yet
if (
$(document.body).is('[data-atwho-users-url]') &&
_.isUndefined($(this).data('atwho'))
) {
var dataUrl = $(document.body).attr('data-atwho-users-url');
$(this)
.atwho({
at: '@',
callbacks: {
remoteFilter: function(query, callback) {
$.getJSON(
dataUrl,
{query: query},
function(data) {
callback(data.users);
}
);
},
sorter: function(query, items, _searchKey) {
// Sorting is already done on server-side
return items;
},
tplEval: function(_tpl, map) {
var res;
try {
res = '';
res += '<li class="atwho-li atwho-li-user" ';
res += 'data-id="' + map.id + '" ';
res += 'data-full-name="' + map.full_name + '">';
res += '<img src="' + map.img_url + '" class="avatar" />';
res += '<span data-val="full-name">';
res += map.full_name;
res += '</span>';
res += '<small>';
res += '&nbsp;';
res += '&#183;';
res += '&nbsp;';
res += '<span data-val="email">';
res += map.email;
res += '</span>';
res += '</small>';
res += '</li>';
} catch (_error) {
res = '';
}
return res;
},
highlighter: function(li, query) {
function highlight(el, sel, re) {
var prevVal = el.find(sel).html();
var newVal = prevVal.replace(re, '<strong>$&</strong>');
el.find(sel).html(newVal);
}
if (!query) {
return li;
}
var $li = $(li);
var re = new RegExp(query, 'gi');
highlight($li, '[data-val=full-name]', re);
highlight($li, '[data-val=email]', re);
return $li[0].outerHTML;
},
beforeInsert: function(value, li) {
var res = '';
res += '[@' + li.attr('data-full-name');
res += '~' + li.attr('data-id') + ']';
return res;
}
},
headerTpl:
'<div class="atwho-header-user">' +
'<div class="title"><%= I18n.t("atwho.users.title") %></div>' +
'<div class="help">' +
'<div>' +
'<strong><%= I18n.t("atwho.users.navigate_1") %></strong> ' +
'<%= I18n.t("atwho.users.navigate_2") %>' +
'</div>' +
'<div>' +
'<strong><%= I18n.t("atwho.users.confirm_1") %></strong> ' +
'<%= I18n.t("atwho.users.confirm_2") %>' +
'</div>' +
'<div>' +
'<strong><%= I18n.t("atwho.users.dismiss_1") %></strong> ' +
'<%= I18n.t("atwho.users.dismiss_2") %>' +
'</div>' +
'<div class="dismiss">' +
'<span class="glyphicon glyphicon-remove"></span>' +
'</div>' +
'</div>' +
'</div>',
limit: <%= Constants::ATWHO_SEARCH_LIMIT %>,
startsWithSpace: true,
acceptSpaceBar: true
});
}
}
);
})();

View file

@ -25,6 +25,7 @@ $color-emperor: #555;
$color-mine-shaft: #333; $color-mine-shaft: #333;
$color-nero: #262626; $color-nero: #262626;
$color-black: #000; $color-black: #000;
$color-cloud: rgba(0, 0, 0, .1);
// Miscelaneous colors // Miscelaneous colors
$color-mystic: #eaeff2; $color-mystic: #eaeff2;

View file

@ -1716,10 +1716,10 @@ th.custom-field .modal-tooltiptext {
margin-top: 18px; margin-top: 18px;
background: $color-white; background: $color-white;
color: $color-black; color: $color-black;
border: 1px solid #DDD; border: 1px solid $color-emperor;
border-radius: 3px; border-radius: 3px;
box-shadow: 0 0 5px rgba(0,0,0,0.1); box-shadow: 0 0 5px $color-cloud;
min-width: 120px; min-width: 520px;
max-height: 200px; max-height: 200px;
overflow: auto; overflow: auto;
z-index: 11110 !important; z-index: 11110 !important;
@ -1756,13 +1756,54 @@ th.custom-field .modal-tooltiptext {
li { li {
display: block; display: block;
padding: 5px 10px; padding: 5px 10px;
border-bottom: 1px solid #DDD; border-bottom: 1px solid $color-emperor;
cursor: pointer; cursor: pointer;
} }
} }
} }
// <End of overrides> // <End of overrides>
.atwho-header-user {
padding-top: 7px;
padding-bottom: 7px;
height: 34px;
background-color: $color-gallery;
border-bottom: 1px solid $color-emperor;
clear: both;
> div {
display: inline;
}
.title {
float: left;
margin-left: 15px;
}
.help {
float: right;
div {
display: inline;
margin-right: 15px;
font-size: smaller;
}
div strong {
color: $color-black;
}
.dismiss {
color: $color-emperor;
}
.dismiss:hover {
color: $color-black;
cursor: pointer;
}
}
}
.atwho-li-user { .atwho-li-user {
.avatar { .avatar {

View file

@ -10,8 +10,12 @@ class AtWhoController < ApplicationController
.limit(Constants::ATWHO_SEARCH_LIMIT) .limit(Constants::ATWHO_SEARCH_LIMIT)
.as_json .as_json
# Add avatars, convert to JSON # Add avatars, Base62, convert to JSON
res.each do |user_obj| res.each do |user_obj|
user_obj['full_name'] =
user_obj['full_name']
.truncate(Constants::NAME_TRUNCATION_LENGTH_DROPDOWN)
user_obj['id'] = user_obj['id'].base62_encode
user_obj['img_url'] = avatar_path(user_obj['id'], :icon_small) user_obj['img_url'] = avatar_path(user_obj['id'], :icon_small)
end end

View file

@ -62,13 +62,13 @@ class Organization < ActiveRecord::Base
.strip .strip
.gsub('_', '\\_') .gsub('_', '\\_')
.gsub('%', '\\%') .gsub('%', '\\%')
.split(/\s+/)
.map { |t| '%' + t + '%' }
else else
a_query = query a_query = query
end end
users.where_attributes_like(attributes, a_query) users
.where.not(confirmed_at: nil)
.where_attributes_like(attributes, a_query)
end end
# Writes to user log # Writes to user log

View file

@ -14,7 +14,12 @@
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
</head> </head>
<body class="<%= yield :body_class %>"> <body
class="<%= yield :body_class %>"
<% if user_signed_in? && current_organization.present? %>
data-atwho-users-url="<%= atwho_users_organization_path(current_organization) %>"
<% end %>
>
<span style="display: none;" data-hook="body-js"></span> <span style="display: none;" data-hook="body-js"></span>
<span style="display: none;" data-hook="application-body-html"></span> <span style="display: none;" data-hook="application-body-html"></span>

View file

@ -1451,6 +1451,16 @@ en:
assign_user_to_organization: "<i>%{assigned_user}</i> was added as %{role} to team <strong>%{organization}</strong> by <i>%{assigned_by_user}</i>." assign_user_to_organization: "<i>%{assigned_user}</i> was added as %{role} to team <strong>%{organization}</strong> by <i>%{assigned_by_user}</i>."
unassign_user_from_organization: "<i>%{unassigned_user}</i> was removed from team <strong>%{organization}</strong> by <i>%{unassigned_by_user}</i>." unassign_user_from_organization: "<i>%{unassigned_user}</i> was removed from team <strong>%{organization}</strong> by <i>%{unassigned_by_user}</i>."
atwho:
users:
title: "People"
navigate_1: "up/down"
navigate_2: "to navigate"
confirm_1: "enter/tab"
confirm_2: "to confirm"
dismiss_1: "esc"
dismiss_2: "to dismiss"
# This section contains general words that can be used in any parts of # This section contains general words that can be used in any parts of
# application. # application.

View file

@ -0,0 +1,5 @@
class AddIndexToUsersFullName < ActiveRecord::Migration
def change
add_index :users, :full_name
end
end

View file

@ -11,7 +11,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20161125153600) do ActiveRecord::Schema.define(version: 20170105162500) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
@ -639,20 +639,20 @@ ActiveRecord::Schema.define(version: 20161125153600) do
add_index "user_projects", ["user_id"], name: "index_user_projects_on_user_id", using: :btree add_index "user_projects", ["user_id"], name: "index_user_projects_on_user_id", using: :btree
create_table "users", force: :cascade do |t| create_table "users", force: :cascade do |t|
t.string "full_name", null: false t.string "full_name", null: false
t.string "initials", null: false t.string "initials", null: false
t.string "email", default: "", null: false t.string "email", default: "", null: false
t.string "encrypted_password", default: "", null: false t.string "encrypted_password", default: "", null: false
t.string "reset_password_token" t.string "reset_password_token"
t.datetime "reset_password_sent_at" t.datetime "reset_password_sent_at"
t.datetime "remember_created_at" t.datetime "remember_created_at"
t.integer "sign_in_count", default: 0, null: false t.integer "sign_in_count", default: 0, null: false
t.datetime "current_sign_in_at" t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at" t.datetime "last_sign_in_at"
t.string "current_sign_in_ip" t.string "current_sign_in_ip"
t.string "last_sign_in_ip" t.string "last_sign_in_ip"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
t.string "avatar_file_name" t.string "avatar_file_name"
t.string "avatar_content_type" t.string "avatar_content_type"
t.integer "avatar_file_size" t.integer "avatar_file_size"
@ -661,7 +661,7 @@ ActiveRecord::Schema.define(version: 20161125153600) do
t.datetime "confirmed_at" t.datetime "confirmed_at"
t.datetime "confirmation_sent_at" t.datetime "confirmation_sent_at"
t.string "unconfirmed_email" t.string "unconfirmed_email"
t.string "time_zone", default: "UTC" t.string "time_zone", default: "UTC"
t.string "invitation_token" t.string "invitation_token"
t.datetime "invitation_created_at" t.datetime "invitation_created_at"
t.datetime "invitation_sent_at" t.datetime "invitation_sent_at"
@ -669,18 +669,21 @@ ActiveRecord::Schema.define(version: 20161125153600) do
t.integer "invitation_limit" t.integer "invitation_limit"
t.integer "invited_by_id" t.integer "invited_by_id"
t.string "invited_by_type" t.string "invited_by_type"
t.integer "invitations_count", default: 0 t.integer "invitations_count", default: 0
t.integer "tutorial_status", default: 0, null: false t.integer "tutorial_status", default: 0, null: false
t.boolean "assignments_notification", default: true t.boolean "assignments_notification", default: true
t.boolean "recent_notification", default: true t.boolean "recent_notification", default: true
t.boolean "assignments_notification_email", default: false t.boolean "assignments_notification_email", default: false
t.boolean "recent_notification_email", default: false t.boolean "recent_notification_email", default: false
t.integer "current_organization_id" t.integer "current_organization_id"
t.boolean "system_message_notification_email", default: false t.boolean "system_message_notification_email", default: false
t.string "authentication_token", limit: 30
end end
add_index "users", ["authentication_token"], name: "index_users_on_authentication_token", unique: true, using: :btree
add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree add_index "users", ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true, using: :btree
add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
add_index "users", ["full_name"], name: "index_users_on_full_name", using: :btree
add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree
add_index "users", ["invitations_count"], name: "index_users_on_invitations_count", using: :btree add_index "users", ["invitations_count"], name: "index_users_on_invitations_count", using: :btree
add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id", using: :btree add_index "users", ["invited_by_id"], name: "index_users_on_invited_by_id", using: :btree