Appreciation Editor Complete / All Others Incomplete
The text editor for the appreciation page is complete, but all other files are empty, besides User Manager.
This commit is contained in:
@@ -1,4 +1,7 @@
|
||||
<template name="AppreciationEditor">
|
||||
<div id="appreciationEditor">
|
||||
<h1>Appreciation Editor</h1>
|
||||
<div id="editor"></div>
|
||||
<button id="save">Save</button>
|
||||
</div>
|
||||
</template>
|
||||
6
imports/ui/Admin/AppreciationEditor.import.styl
vendored
Normal file
6
imports/ui/Admin/AppreciationEditor.import.styl
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#appreciationEditor
|
||||
display: block
|
||||
.ck.ck-editor__editable_inline
|
||||
border-color: rgba(0,0,0,.2)
|
||||
.ck.ck-editor__editable_inline.ck-focused
|
||||
border-color: rgba(0,0,0,1)
|
||||
@@ -1,2 +1,77 @@
|
||||
import CKEditor from '@ckeditor/ckeditor5-build-balloon';
|
||||
import './AppreciationEditor.html';
|
||||
import swal from "sweetalert2";
|
||||
|
||||
import './AppreciationEditor.html';
|
||||
let originalData = "";
|
||||
|
||||
Tracker.autorun(function() {
|
||||
Meteor.subscribe("pages");
|
||||
});
|
||||
|
||||
Template.AppreciationEditor.onRendered(function() {
|
||||
let _this = this;
|
||||
|
||||
//#appreciationEditor'
|
||||
CKEditor.create(document.querySelector('#editor'), {}).then(editor => {
|
||||
_this.ckEditor = editor;
|
||||
|
||||
Tracker.autorun(function() {
|
||||
let doc = Meteor.collections.Pages.findOne({name: 'Appreciation'});
|
||||
|
||||
originalData = (doc === undefined ? "" : doc.html);
|
||||
editor.setData(originalData);
|
||||
});
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
});
|
||||
|
||||
Template.AppreciationEditor.onDestroyed(function() {
|
||||
let data = this.ckEditor.getData();
|
||||
|
||||
if(data != originalData) {
|
||||
swal({
|
||||
title: "Save Changes",
|
||||
text: "Would you like to save any changes you have made to this sheet?",
|
||||
type: "question",
|
||||
showCancelButton: true,
|
||||
confirmButtonColor: "#7cdd7f",
|
||||
confirmButtonText: "Yes",
|
||||
cancelButtonText: "No"
|
||||
}).then(
|
||||
function(isConfirm) {
|
||||
if(isConfirm) {
|
||||
Meteor.call('updatePage', 'Appreciation', data, function (error, result) {
|
||||
if (error) sAlert.error(error);
|
||||
else sAlert.success("Content Saved Successfully");
|
||||
});
|
||||
}
|
||||
},
|
||||
function(dismiss) {}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
Template.AppreciationEditor.helpers({
|
||||
// html: function() {
|
||||
// let doc = Meteor.collections.Pages.findOne({name: 'Appreciation'});
|
||||
//
|
||||
// return doc == undefined ? "" : doc.html;
|
||||
// }
|
||||
});
|
||||
|
||||
Template.AppreciationEditor.events({
|
||||
'click #save': function(event, template) {
|
||||
let data = template.ckEditor.getData();
|
||||
|
||||
if(data != originalData) {
|
||||
Meteor.call('updatePage', 'Appreciation', data, function (error, result) {
|
||||
if (error) sAlert.error(error);
|
||||
else sAlert.success("Content Saved Successfully");
|
||||
});
|
||||
}
|
||||
else {
|
||||
sAlert.success("Data has not changed!");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
#appreciationEditor
|
||||
display: block
|
||||
78
imports/ui/Admin/UserManagement.html
Normal file
78
imports/ui/Admin/UserManagement.html
Normal file
@@ -0,0 +1,78 @@
|
||||
<template name="UserManagement">
|
||||
<div id="userManagement">
|
||||
{{#if Template.subscriptionsReady}}
|
||||
<div class="tableControls">
|
||||
<div class="contentControls">
|
||||
<a class="loadMoreLink {{#if disableLoadMore}}disabled{{/if}}" href="javascript:">Load More...</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separatedTableHeader">
|
||||
<table class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="username">Username {{>UserSearch columnName='username'}}</th>
|
||||
<th class="email">Email {{>UserSearch columnName='email' collectionQueryColumnName='name' collection='Items' collectionResultColumnName='_id'}}</th>
|
||||
<th class="roles">Roles</th>
|
||||
<th class="actions">Actions <span class="newUserButton btn btn-success"><i class="fa fa-plus-circle" aria-hidden="true"></i><i class="fa fa-times-circle" aria-hidden="true"></i></span></th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
</div>
|
||||
<div class="listContianer">
|
||||
<div class="listRow">
|
||||
<div class="listCell">
|
||||
<div class="tableContainer mCustomScrollbar" data-mcs-theme="dark">
|
||||
<table class="dataTable table table-striped table-hover">
|
||||
<tbody>
|
||||
{{#if displayNewUser}}
|
||||
<tr>{{> UserEditor isNew=true}}</tr>
|
||||
{{/if}}
|
||||
{{#each users}}
|
||||
{{> User}}
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template name="User">
|
||||
<tr>
|
||||
{{#if editing}}
|
||||
{{> UserEditor}}
|
||||
{{else}}
|
||||
<td class="username tdLarge noselect nonclickable">{{username}}</td>
|
||||
<td class="email tdLarge noselect nonclickable">{{email}}</td>
|
||||
<td class="roles tdLarge noselect nonclickable">{{roles}}</td>
|
||||
<td class="actions center tdLarge"><i class="userRemove fa fa-times-circle fa-lg noselect clickable" aria-hidden="true"></i> / <i class="userEdit fa fa-pencil-square-o fa-lg noselect clickable" aria-hidden="true"></i></td>
|
||||
{{/if}}
|
||||
</tr>
|
||||
</template>
|
||||
|
||||
<template name="UserEditor">
|
||||
<td colspan="3" class="userEditor measureEditorTd">
|
||||
<div>
|
||||
<div class="username editorDiv"><label>User Name:</label><input name="username" class="form-control" type="text" value="{{username}}" autocomplete="off" required></div>
|
||||
<div class="email editorDiv"><label>User Email:</label><input name="email" class="form-control" type="text" value="{{email}}" autocomplete="off" required></div>
|
||||
<div class="rolesContainer editorDiv"><label>Roles:</label>
|
||||
<div class="roles center" style="font-size: 1.2em">
|
||||
{{#each allRoles}}
|
||||
<span class="role {{getRoleState this}} noselect">{{name}}</span>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="actions center measureEditorTd"><i class="editorApply fa fa-check-square-o fa-lg noselect clickable" aria-hidden="true"></i> / <i class="editorCancel fa fa-times-circle fa-lg noselect clickable" aria-hidden="true"></i></td>
|
||||
</template>
|
||||
|
||||
<template name="UserSearch">
|
||||
<div class="">
|
||||
<input type="text" class="searchInput" placeholder="Filter..." value="{{searchValue}}" style="width: 90%"/>
|
||||
</div>
|
||||
</template>
|
||||
152
imports/ui/Admin/UserManagement.import.styl
vendored
Normal file
152
imports/ui/Admin/UserManagement.import.styl
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
#userManagement
|
||||
display: table
|
||||
content-box: border-box
|
||||
padding: 10px 20px
|
||||
height: 100%
|
||||
width: 100%
|
||||
text-align: left
|
||||
position: relative
|
||||
|
||||
.tableControls
|
||||
display: table
|
||||
width: 100%
|
||||
text-align: right
|
||||
margin-right: 20px
|
||||
.contentControls
|
||||
vertical-align: bottom
|
||||
display: table-cell
|
||||
text-align: right
|
||||
min-width: 100px
|
||||
a
|
||||
font-size: 12px
|
||||
font-family: "Arial", san-serif
|
||||
font-weight: 800
|
||||
color: #2d1b8c
|
||||
text-decoration: none
|
||||
a:hover
|
||||
text-decoration: underline
|
||||
a.disabled
|
||||
visibility: hidden
|
||||
.editor
|
||||
height: 100%
|
||||
overflow-y: auto
|
||||
|
||||
.insert
|
||||
flex: none
|
||||
width: 100%
|
||||
|
||||
.col-md-6
|
||||
padding: 10px 30px 0 30px
|
||||
background: #EFEFEF
|
||||
border-radius: 1em
|
||||
|
||||
.formGroupHeading
|
||||
font-size: 1.6em
|
||||
font-family: "Arial Black", "Arial Bold", Gadget, sans-serif
|
||||
font-style: normal
|
||||
font-variant: normal
|
||||
font-weight: 500
|
||||
.table
|
||||
table-layout: fixed
|
||||
min-width: 100%
|
||||
thead, tbody
|
||||
> tr
|
||||
> .username
|
||||
width: 50%
|
||||
min-width: 100px
|
||||
> .email
|
||||
width: 50%
|
||||
min-width: 100px
|
||||
> .roles
|
||||
width: 260px
|
||||
min-width: 260px
|
||||
> .actions
|
||||
width: 80px
|
||||
min-width: 80px
|
||||
.separatedTableHeader
|
||||
.actions
|
||||
text-align: center
|
||||
.newUserButton
|
||||
margin-top: 4px
|
||||
padding: 0 12px
|
||||
.fa-plus-circle
|
||||
display: inline-block
|
||||
.fa-times-circle
|
||||
display: none
|
||||
.newUserButton.active
|
||||
background-color: #fb557b
|
||||
color: black
|
||||
.fa-times-circle
|
||||
display: inline-block
|
||||
.fa-plus-circle
|
||||
display: none
|
||||
.listContainer
|
||||
position: absolute
|
||||
top: 100px
|
||||
left: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
.listRow
|
||||
display: table-row
|
||||
.listCell
|
||||
display: table-cell
|
||||
position: relative
|
||||
height: 100%
|
||||
width: 100%
|
||||
.tableContainer
|
||||
position: absolute
|
||||
top: 0
|
||||
bottom: 0
|
||||
left: 0
|
||||
right: 0
|
||||
width: auto
|
||||
height: auto
|
||||
border: 0
|
||||
font-size: 12.5px
|
||||
overflow-y: auto
|
||||
table
|
||||
table-layout: fixed
|
||||
width: 100%
|
||||
thead
|
||||
display: none
|
||||
visibility: hidden
|
||||
.userRemove
|
||||
color: red
|
||||
.userEdit
|
||||
color: darkblue
|
||||
.editorApply
|
||||
color: green
|
||||
.editorCancel
|
||||
color: red
|
||||
.userEditor > div
|
||||
display: table
|
||||
> div
|
||||
display: table-cell
|
||||
padding: 10px
|
||||
.roles
|
||||
.role
|
||||
vertical-align: middle
|
||||
td.roles
|
||||
.role
|
||||
padding: 4px 4px
|
||||
border: 1px solid #555
|
||||
border-radius: .25em
|
||||
background: white
|
||||
color: #999
|
||||
cursor: pointer
|
||||
.selected
|
||||
color: black
|
||||
|
||||
div.roles
|
||||
padding: 4px 0
|
||||
.role
|
||||
padding: 4px 4px
|
||||
border: 1px solid #555
|
||||
border-radius: .25em
|
||||
background: white
|
||||
color: #999
|
||||
cursor: pointer
|
||||
.selected
|
||||
color: black
|
||||
.center
|
||||
vertical-align: middle !important
|
||||
223
imports/ui/Admin/UserManagement.js
Normal file
223
imports/ui/Admin/UserManagement.js
Normal file
@@ -0,0 +1,223 @@
|
||||
|
||||
import './UserManagement.html';
|
||||
import '/imports/util/selectize/selectize.js'
|
||||
|
||||
let QUERY_LIMIT = 100;
|
||||
let QUERY_LIMIT_INCREMENT = 100;
|
||||
let PREFIX = "UserManagement";
|
||||
|
||||
Tracker.autorun(function() {
|
||||
Meteor.subscribe("users", Session.get(PREFIX + 'searchQuery'));
|
||||
Meteor.subscribe("roles");
|
||||
});
|
||||
|
||||
Template.UserManagement.onCreated(function() {
|
||||
Session.set(PREFIX + "displayNewUser", false);
|
||||
Session.set(PREFIX + "queryLimit", QUERY_LIMIT);
|
||||
});
|
||||
Template.UserManagement.onRendered(function() {
|
||||
$(".tableContainer").mCustomScrollbar({
|
||||
scrollButtons: {enable:true},
|
||||
theme: "light-thick",
|
||||
scrollbarPosition: "outside",
|
||||
scrollEasing: "linear"
|
||||
});
|
||||
});
|
||||
Template.UserManagement.helpers({
|
||||
displayNewUser: function() {
|
||||
return Session.get(PREFIX + "displayNewUser");
|
||||
},
|
||||
users: function() {
|
||||
let skipCount = Session.get(PREFIX + 'skipCount') || 0;
|
||||
let query = Session.get(PREFIX + 'searchQuery');
|
||||
let dbQuery = [];
|
||||
|
||||
if(query) {
|
||||
_.each(_.keys(query), function(key) {
|
||||
if(_.isFunction(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key]();
|
||||
else if(_.isObject(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key]; //Will look something like: {$in: [xxx,xxx,xxx]}
|
||||
else if(_.isNumber(query[key])) dbQuery.push({[key]: query[key]}); //dbQuery[key] = query[key];
|
||||
else {
|
||||
//dbQuery[key] = {$regex: query[key], $options: 'i'};
|
||||
let searchValue = query[key];
|
||||
let searches = searchValue && searchValue.length > 0 ? searchValue.split(/\s+/) : undefined;
|
||||
|
||||
for(let search of searches) {
|
||||
dbQuery.push({[key]: {$regex: '\\b' + search, $options: 'i'}});
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(!Session.get(PREFIX + "showHidden")) {
|
||||
//Ignore any hidden elements by showing those not hidden, or those without the hidden field.
|
||||
dbQuery.push({$or: [{hidden: false}, {hidden: {$exists:false}}]});
|
||||
}
|
||||
|
||||
dbQuery = dbQuery.length > 0 ? {$and: dbQuery} : {};
|
||||
Session.set(PREFIX + 'userCount', Meteor.collections.Users.find(dbQuery).count()); //Always get a full count.
|
||||
return Meteor.collections.Users.find(dbQuery, {limit: Session.get(PREFIX + "queryLimit"), skip: skipCount, sort: {username: 1}});
|
||||
},
|
||||
disableLoadMore: function() {
|
||||
return Session.get(PREFIX + 'userCount') - (Session.get(PREFIX + 'skipCount') || 0) - Session.get(PREFIX + "queryLimit") <= 0;
|
||||
}
|
||||
});
|
||||
Template.UserManagement.events({
|
||||
'click .loadMoreLink': function(event, template) {
|
||||
event.preventDefault();
|
||||
Session.set(PREFIX + 'queryLimit', Session.get(PREFIX + "queryLimit") + QUERY_LIMIT_INCREMENT);
|
||||
},
|
||||
'click .newUserButton': function(event, template) {
|
||||
if(template.$('.newUserButton').hasClass('active')) {
|
||||
Session.set(PREFIX + 'displayNewUser', false);
|
||||
}
|
||||
else {
|
||||
Session.set(PREFIX + 'displayNewUser', true);
|
||||
Session.set(PREFIX + "editedUser", undefined); //Clear the edited user so that only one editor is open at a time.
|
||||
}
|
||||
template.$('.newUserButton').toggleClass('active');
|
||||
}
|
||||
});
|
||||
|
||||
Template.User.onCreated(function() {
|
||||
this.edited = new ReactiveVar();
|
||||
});
|
||||
Template.User.events({
|
||||
"click .userEdit": function(event, template) {
|
||||
//template.edited.set(this);
|
||||
Session.set(PREFIX + "editedUser", this._id);
|
||||
Session.set(PREFIX + 'displayNewUser', false); //Ensure the new measure editor is closed.
|
||||
template.parentTemplate().$('.newUserButton').removeClass('active');
|
||||
},
|
||||
"click .userRemove": function(event, template) {
|
||||
let _this = this;
|
||||
bootbox.confirm({
|
||||
message: "Delete the user?",
|
||||
buttons: {confirm: {label: "Yes", className: 'btn-success'}, cancel: {label: "No", className: "btn-danger"}},
|
||||
callback: function(result) {
|
||||
if(result) {
|
||||
Meteor.call('deleteUser', _this._id, function(error, result) {
|
||||
if(error) {
|
||||
sAlert.error(error);
|
||||
}
|
||||
else {
|
||||
sAlert.success("User removed.");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Template.User.helpers({
|
||||
email: function() {
|
||||
return this.emails && this.emails.length > 0 ? this.emails[0].address : "";
|
||||
},
|
||||
editing: function() {
|
||||
let editedUser = Session.get(PREFIX + "editedUser");
|
||||
|
||||
return editedUser == this._id;
|
||||
}
|
||||
});
|
||||
|
||||
Template.UserEditor.helpers({
|
||||
email: function() {
|
||||
return this.emails && this.emails.length > 0 ? this.emails[0].address : "";
|
||||
},
|
||||
allRoles: function() {
|
||||
return Meteor.collections.UserRoles.find();
|
||||
},
|
||||
getRoleState: function(role) {
|
||||
let user = Template.parentData(1);
|
||||
|
||||
return !user.isNew && user.roles.includes(role.name) ? "selected" : "";
|
||||
}
|
||||
});
|
||||
Template.UserEditor.events({
|
||||
"click .editorCancel": function(event, template) {
|
||||
Session.set(PREFIX + "editedUser", undefined);
|
||||
Session.set(PREFIX + 'displayNewUser', false);
|
||||
template.parentTemplate().$('.newUserButton').removeClass('active');
|
||||
},
|
||||
"click .editorApply": function(event, template) {
|
||||
let user = {};
|
||||
let roles = [];
|
||||
|
||||
user.username = template.$('input[name="username"]').val();
|
||||
user.email = template.$('input[name="email"]').val();
|
||||
|
||||
let roleSpans = template.$('.role.selected');
|
||||
for(let i = 0; i < roleSpans.length; i++) {
|
||||
roles.push($(roleSpans[i]).text());
|
||||
}
|
||||
|
||||
user.roles = roles;
|
||||
|
||||
if(Session.get(PREFIX + 'displayNewUser')) {
|
||||
Meteor.call('insertUser', user, function(error, result) {
|
||||
if(error) {
|
||||
sAlert.error(error);
|
||||
}
|
||||
else {
|
||||
sAlert.success("User created.");
|
||||
Session.set(PREFIX + 'displayNewUser', false);
|
||||
template.parentTemplate().$('.newUserButton').removeClass('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
user._id = this._id;
|
||||
Meteor.call("updateUser", user, function(error, result) {
|
||||
if(error) sAlert.error(error);
|
||||
else {
|
||||
sAlert.success("User updated.");
|
||||
Session.set(PREFIX + "editedUser", undefined);
|
||||
template.parentTemplate().$('.newUserButton').removeClass('active');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
"click .role": function(event, template) {
|
||||
$(event.target).toggleClass("selected");
|
||||
}
|
||||
});
|
||||
|
||||
Template.UserSearch.events({
|
||||
"keyup .searchInput": _.throttle(function(event, template) {
|
||||
let searchQuery = Session.get(PREFIX + 'searchQuery') || {};
|
||||
let searchFields = Session.get(PREFIX + 'searchFields') || {};
|
||||
let searchValue = template.$('.searchInput').val();
|
||||
|
||||
if(searchValue) {
|
||||
if(this.number) searchValue = parseFloat(searchValue);
|
||||
|
||||
if(this.collection) {
|
||||
let ids = Meteor.collections[this.collection].find({[this.collectionQueryColumnName]: {$regex: searchValue, $options: 'i'}}, {fields: {[this.collectionResultColumnName]: 1}}).fetch();
|
||||
|
||||
//Convert the ids to an array of ids instead of an array of objects containing an id.
|
||||
for(let i = 0; i < ids.length; i++) {ids[i] = ids[i]._id;}
|
||||
searchQuery[this.columnName] = {$in: ids};
|
||||
searchFields[this.columnName] = searchValue;
|
||||
}
|
||||
else {
|
||||
searchFields[this.columnName] = searchQuery[this.columnName] = searchValue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
//Remove columns from the search query whose values are empty so we don't bother the database with them.
|
||||
delete searchQuery[this.columnName];
|
||||
delete searchFields[this.columnName];
|
||||
}
|
||||
|
||||
Session.set(PREFIX + 'searchQuery', searchQuery);
|
||||
Session.set(PREFIX + 'skipCount', 0); //Reset the paging of the results.
|
||||
}, 500)
|
||||
});
|
||||
Template.UserSearch.helpers({
|
||||
searchValue: function() {
|
||||
let searchFields = Session.get(PREFIX + 'searchFields');
|
||||
|
||||
return (searchFields && searchFields[this.columnName]) ? searchFields[this.columnName] : '';
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user