Upgraded to Meteor 1.6.0.1 and NodeJS 8.9.3. Added weekly/daily property to venues to support graphing and tracking of actual income from farmers markets (they don't usually match with expected income). Added workers objects to help illustrate who did what work (who was at the market on a specific week for example, or who prep'd and who canned a batch of jam). Fixed some bugs in the venue page. Re-design of the menu to allow for more menu options.
This commit is contained in:
@@ -4,27 +4,27 @@
|
|||||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||||
# but you can also edit it by hand.
|
# but you can also edit it by hand.
|
||||||
|
|
||||||
meteor-base@1.1.0 # Packages every Meteor app needs to have
|
meteor-base@1.2.0 # Packages every Meteor app needs to have
|
||||||
mobile-experience@1.0.5 # Packages for a great mobile UX
|
mobile-experience@1.0.5 # Packages for a great mobile UX
|
||||||
mongo@1.2.2 # The database Meteor supports right now
|
mongo@1.3.1 # The database Meteor supports right now
|
||||||
blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views
|
blaze-html-templates@1.0.4 # Compile .html files into Meteor Blaze views
|
||||||
reactive-var@1.0.11 # Reactive variable for tracker
|
reactive-var@1.0.11 # Reactive variable for tracker
|
||||||
reactive-dict@1.1.9 # ???
|
reactive-dict@1.2.0 # ???
|
||||||
tracker@1.1.3 # Meteor's client-side reactive programming library
|
tracker@1.1.3 # Meteor's client-side reactive programming library
|
||||||
tomwasd:history-polyfill # Adds IE 8/9 support for HTML5 history.
|
tomwasd:history-polyfill # Adds IE 8/9 support for HTML5 history.
|
||||||
email@1.2.3 # Adds the Meteor/Email package for sending lost password emails
|
email@1.2.3 # Adds the Meteor/Email package for sending lost password emails
|
||||||
|
|
||||||
standard-minifier-css@1.3.5 # CSS minifier run for production mode
|
standard-minifier-css@1.3.5 # CSS minifier run for production mode
|
||||||
standard-minifier-js@2.1.2 # JS minifier run for production mode
|
standard-minifier-js@2.2.0 # JS minifier run for production mode
|
||||||
es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers.
|
es5-shim@4.6.15 # ECMAScript 5 compatibility for older browsers.
|
||||||
poorvavyas:es6-shim
|
poorvavyas:es6-shim
|
||||||
ecmascript@0.8.3 # Enable ECMAScript2015+ syntax in app code
|
ecmascript@0.9.0 # Enable ECMAScript2015+ syntax in app code
|
||||||
|
|
||||||
#accounts-ui
|
#accounts-ui
|
||||||
#accounts-base
|
#accounts-base
|
||||||
accounts-password@1.4.0
|
accounts-password@1.5.0
|
||||||
useraccounts:core
|
useraccounts:core
|
||||||
useraccounts:bootstrap
|
useraccounts:unstyled
|
||||||
useraccounts:flow-routing # Configures email flows. Used for AccountsTemplates class.
|
useraccounts:flow-routing # Configures email flows. Used for AccountsTemplates class.
|
||||||
alanning:roles # Adds roles to the user mix. https://atmospherejs.com/alanning/roles && https://github.com/alanning/meteor-roles/blob/master/examples/flow-router/
|
alanning:roles # Adds roles to the user mix. https://atmospherejs.com/alanning/roles && https://github.com/alanning/meteor-roles/blob/master/examples/flow-router/
|
||||||
|
|
||||||
@@ -33,9 +33,9 @@ arillo:flow-router-helpers # Provides various template helpers such as {{pathFo
|
|||||||
#tomwasd:flow-router-seo
|
#tomwasd:flow-router-seo
|
||||||
kadira:blaze-layout
|
kadira:blaze-layout
|
||||||
|
|
||||||
shell-server@0.2.4 # ???
|
shell-server@0.3.0 # ???
|
||||||
meteortoys:allthings
|
meteortoys:allthings
|
||||||
stylus@2.513.9
|
stylus@2.513.13
|
||||||
session@1.1.7
|
session@1.1.7
|
||||||
##browser-policy # Adds support for specifying browser level security rules related to content and what's allowed to laod on the page.
|
##browser-policy # Adds support for specifying browser level security rules related to content and what's allowed to laod on the page.
|
||||||
check@1.2.5 # Allows for checking the structure and types of arguments passed to Meteor methods and publications.
|
check@1.2.5 # Allows for checking the structure and types of arguments passed to Meteor methods and publications.
|
||||||
@@ -61,6 +61,6 @@ juliancwirko:s-alert # Client error/alert handling
|
|||||||
jcbernack:reactive-aggregate # Allows us to create a new client collection (from the server) with the contents being an aggregate of server data. Note that aggregation can only be done on the server currently as mini-mongo does not support it.
|
jcbernack:reactive-aggregate # Allows us to create a new client collection (from the server) with the contents being an aggregate of server data. Note that aggregation can only be done on the server currently as mini-mongo does not support it.
|
||||||
ostrio:logger
|
ostrio:logger
|
||||||
ostrio:loggermongo
|
ostrio:loggermongo
|
||||||
dynamic-import@0.1.3
|
dynamic-import@0.2.0
|
||||||
markdown@1.0.12
|
markdown@1.0.12
|
||||||
wcrisman:jquery-custom-scrollbar
|
wcrisman:jquery-custom-scrollbar
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
METEOR@1.5.2.2
|
METEOR@1.6.0.1
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
accounts-base@1.3.4
|
accounts-base@1.4.0
|
||||||
accounts-password@1.4.0
|
accounts-password@1.5.0
|
||||||
alanning:roles@1.2.16
|
alanning:roles@1.2.16
|
||||||
aldeed:collection2@2.10.0
|
aldeed:collection2@2.10.0
|
||||||
aldeed:collection2-core@1.2.0
|
aldeed:collection2-core@1.2.0
|
||||||
@@ -7,35 +7,35 @@ aldeed:schema-deny@1.1.0
|
|||||||
aldeed:schema-index@1.1.1
|
aldeed:schema-index@1.1.1
|
||||||
aldeed:simple-schema@1.5.3
|
aldeed:simple-schema@1.5.3
|
||||||
aldeed:template-extension@4.1.0
|
aldeed:template-extension@4.1.0
|
||||||
allow-deny@1.0.9
|
allow-deny@1.1.0
|
||||||
arillo:flow-router-helpers@0.5.2
|
arillo:flow-router-helpers@0.5.2
|
||||||
autoupdate@1.3.12
|
autoupdate@1.3.12
|
||||||
babel-compiler@6.20.0
|
babel-compiler@6.24.7
|
||||||
babel-runtime@1.0.1
|
babel-runtime@1.1.1
|
||||||
base64@1.0.10
|
base64@1.0.10
|
||||||
binary-heap@1.0.10
|
binary-heap@1.0.10
|
||||||
blaze@2.3.2
|
blaze@2.3.2
|
||||||
blaze-html-templates@1.1.2
|
blaze-html-templates@1.1.2
|
||||||
blaze-tools@1.0.10
|
blaze-tools@1.0.10
|
||||||
boilerplate-generator@1.2.0
|
boilerplate-generator@1.3.1
|
||||||
caching-compiler@1.1.9
|
caching-compiler@1.1.9
|
||||||
caching-html-compiler@1.1.2
|
caching-html-compiler@1.1.2
|
||||||
callback-hook@1.0.10
|
callback-hook@1.0.10
|
||||||
check@1.2.5
|
check@1.2.5
|
||||||
coffeescript@1.0.17
|
coffeescript@1.0.17
|
||||||
ddp@1.3.1
|
ddp@1.4.0
|
||||||
ddp-client@2.1.3
|
ddp-client@2.2.0
|
||||||
ddp-common@1.2.9
|
ddp-common@1.3.0
|
||||||
ddp-rate-limiter@1.0.7
|
ddp-rate-limiter@1.0.7
|
||||||
ddp-server@2.0.2
|
ddp-server@2.1.1
|
||||||
deps@1.0.12
|
deps@1.0.12
|
||||||
diff-sequence@1.0.7
|
diff-sequence@1.0.7
|
||||||
dynamic-import@0.1.3
|
dynamic-import@0.2.1
|
||||||
ecmascript@0.8.3
|
ecmascript@0.9.0
|
||||||
ecmascript-runtime@0.4.1
|
ecmascript-runtime@0.5.0
|
||||||
ecmascript-runtime-client@0.4.3
|
ecmascript-runtime-client@0.5.0
|
||||||
ecmascript-runtime-server@0.4.1
|
ecmascript-runtime-server@0.5.0
|
||||||
ejson@1.0.14
|
ejson@1.1.0
|
||||||
email@1.2.3
|
email@1.2.3
|
||||||
es5-shim@4.6.15
|
es5-shim@4.6.15
|
||||||
fortawesome:fontawesome@4.7.0
|
fortawesome:fontawesome@4.7.0
|
||||||
@@ -43,7 +43,7 @@ geojson-utils@1.0.10
|
|||||||
hot-code-push@1.0.4
|
hot-code-push@1.0.4
|
||||||
html-tools@1.0.11
|
html-tools@1.0.11
|
||||||
htmljs@1.0.11
|
htmljs@1.0.11
|
||||||
http@1.2.12
|
http@1.3.0
|
||||||
id-map@1.0.9
|
id-map@1.0.9
|
||||||
jcbernack:reactive-aggregate@0.7.0
|
jcbernack:reactive-aggregate@0.7.0
|
||||||
jquery@1.11.10
|
jquery@1.11.10
|
||||||
@@ -52,12 +52,12 @@ kadira:blaze-layout@2.3.0
|
|||||||
kadira:flow-router@2.12.1
|
kadira:flow-router@2.12.1
|
||||||
launch-screen@1.1.1
|
launch-screen@1.1.1
|
||||||
livedata@1.0.18
|
livedata@1.0.18
|
||||||
localstorage@1.1.1
|
localstorage@1.2.0
|
||||||
logging@1.1.17
|
logging@1.1.19
|
||||||
markdown@1.0.12
|
markdown@1.0.12
|
||||||
mdg:validation-error@0.2.0
|
mdg:validation-error@0.2.0
|
||||||
meteor@1.7.2
|
meteor@1.8.2
|
||||||
meteor-base@1.1.0
|
meteor-base@1.2.0
|
||||||
meteorhacks:aggregate@1.3.0
|
meteorhacks:aggregate@1.3.0
|
||||||
meteorhacks:collection-utils@1.2.0
|
meteorhacks:collection-utils@1.2.0
|
||||||
meteortoys:allthings@4.0.0
|
meteortoys:allthings@4.0.0
|
||||||
@@ -78,32 +78,32 @@ meteortoys:throttle@4.0.0
|
|||||||
meteortoys:toggle@4.0.0
|
meteortoys:toggle@4.0.0
|
||||||
meteortoys:toykit@4.0.1
|
meteortoys:toykit@4.0.1
|
||||||
minifier-css@1.2.16
|
minifier-css@1.2.16
|
||||||
minifier-js@2.1.4
|
minifier-js@2.2.2
|
||||||
minimongo@1.3.2
|
minimongo@1.4.3
|
||||||
mizzao:bootboxjs@4.4.0
|
mizzao:bootboxjs@4.4.0
|
||||||
mobile-experience@1.0.5
|
mobile-experience@1.0.5
|
||||||
mobile-status-bar@1.0.14
|
mobile-status-bar@1.0.14
|
||||||
modules@0.10.0
|
modules@0.11.1
|
||||||
modules-runtime@0.8.0
|
modules-runtime@0.9.1
|
||||||
momentjs:moment@2.18.1
|
momentjs:moment@2.20.0
|
||||||
mongo@1.2.2
|
mongo@1.3.1
|
||||||
mongo-dev-server@1.0.1
|
mongo-dev-server@1.1.0
|
||||||
mongo-id@1.0.6
|
mongo-id@1.0.6
|
||||||
mongo-livedata@1.0.12
|
mongo-livedata@1.0.12
|
||||||
msavin:jetsetter@4.0.0
|
msavin:jetsetter@4.0.0
|
||||||
msavin:mongol@4.0.1
|
msavin:mongol@4.0.1
|
||||||
npm-bcrypt@0.9.3
|
npm-bcrypt@0.9.3
|
||||||
npm-mongo@2.2.30
|
npm-mongo@2.2.33
|
||||||
observe-sequence@1.0.16
|
observe-sequence@1.0.16
|
||||||
ordered-dict@1.0.9
|
ordered-dict@1.0.9
|
||||||
ostrio:logger@2.0.3
|
ostrio:logger@2.0.5
|
||||||
ostrio:loggermongo@2.0.1
|
ostrio:loggermongo@2.0.3
|
||||||
poorvavyas:es6-shim@0.21.1
|
poorvavyas:es6-shim@0.21.1
|
||||||
promise@0.9.0
|
promise@0.10.0
|
||||||
raix:eventemitter@0.1.3
|
raix:eventemitter@0.1.3
|
||||||
random@1.0.10
|
random@1.0.10
|
||||||
rate-limit@1.0.8
|
rate-limit@1.0.8
|
||||||
reactive-dict@1.1.9
|
reactive-dict@1.2.0
|
||||||
reactive-var@1.0.11
|
reactive-var@1.0.11
|
||||||
reload@1.1.11
|
reload@1.1.11
|
||||||
retry@1.0.9
|
retry@1.0.9
|
||||||
@@ -111,14 +111,14 @@ routepolicy@1.0.12
|
|||||||
service-configuration@1.0.11
|
service-configuration@1.0.11
|
||||||
session@1.1.7
|
session@1.1.7
|
||||||
sha@1.0.9
|
sha@1.0.9
|
||||||
shell-server@0.2.4
|
shell-server@0.3.1
|
||||||
softwarerero:accounts-t9n@1.3.11
|
softwarerero:accounts-t9n@1.3.11
|
||||||
spacebars@1.0.15
|
spacebars@1.0.15
|
||||||
spacebars-compiler@1.1.3
|
spacebars-compiler@1.1.3
|
||||||
srp@1.0.10
|
srp@1.0.10
|
||||||
standard-minifier-css@1.3.5
|
standard-minifier-css@1.3.5
|
||||||
standard-minifier-js@2.1.2
|
standard-minifier-js@2.2.3
|
||||||
stylus@2.513.9
|
stylus@2.513.13
|
||||||
templating@1.3.2
|
templating@1.3.2
|
||||||
templating-compiler@1.3.3
|
templating-compiler@1.3.3
|
||||||
templating-runtime@1.3.2
|
templating-runtime@1.3.2
|
||||||
@@ -128,10 +128,10 @@ tracker@1.1.3
|
|||||||
ui@1.0.13
|
ui@1.0.13
|
||||||
underscore@1.0.10
|
underscore@1.0.10
|
||||||
url@1.1.0
|
url@1.1.0
|
||||||
useraccounts:bootstrap@1.14.2
|
|
||||||
useraccounts:core@1.14.2
|
useraccounts:core@1.14.2
|
||||||
useraccounts:flow-routing@1.14.2
|
useraccounts:flow-routing@1.14.2
|
||||||
|
useraccounts:unstyled@1.14.2
|
||||||
wcrisman:jquery-custom-scrollbar@3.0.0
|
wcrisman:jquery-custom-scrollbar@3.0.0
|
||||||
webapp@1.3.19
|
webapp@1.4.0
|
||||||
webapp-hashing@1.0.9
|
webapp-hashing@1.0.9
|
||||||
zimme:active-route@2.3.2
|
zimme:active-route@2.3.2
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import '/imports/util/de.combo.js';
|
|||||||
import '/imports/util/resize/ResizeSensor.js';
|
import '/imports/util/resize/ResizeSensor.js';
|
||||||
import '/imports/util/resize/ElementQueries.js';
|
import '/imports/util/resize/ElementQueries.js';
|
||||||
import '/imports/ui/layouts/Body.js';
|
import '/imports/ui/layouts/Body.js';
|
||||||
import '/imports/ui/layouts/Full.js';
|
import '/imports/ui/layouts/Login.js';
|
||||||
import '/imports/ui/accounts/accounts.js';
|
import '/imports/ui/accounts/accounts.js';
|
||||||
import '/imports/util/select2/select2.css';
|
import '/imports/util/select2/select2.css';
|
||||||
import '/imports/util/select2/select2.full.js';
|
import '/imports/util/select2/select2.full.js';
|
||||||
|
|||||||
@@ -169,7 +169,7 @@ body
|
|||||||
@import "../imports/util/bootstrap-like-btn.import.styl"
|
@import "../imports/util/bootstrap-like-btn.import.styl"
|
||||||
|
|
||||||
@import "../imports/ui/layouts/Body.import.styl"
|
@import "../imports/ui/layouts/Body.import.styl"
|
||||||
@import "../imports/ui/layouts/Full.import.styl"
|
@import "../imports/ui/layouts/Login.import.styl"
|
||||||
|
|
||||||
@import "../imports/ui/UserManagement.import.styl"
|
@import "../imports/ui/UserManagement.import.styl"
|
||||||
@import "../imports/ui/MiscManagement.import.styl"
|
@import "../imports/ui/MiscManagement.import.styl"
|
||||||
@@ -184,5 +184,6 @@ body
|
|||||||
@import "../imports/ui/SalesSheetEditor.import.styl"
|
@import "../imports/ui/SalesSheetEditor.import.styl"
|
||||||
@import "../imports/ui/Pricing.import.styl"
|
@import "../imports/ui/Pricing.import.styl"
|
||||||
@import "../imports/ui/Production.import.styl"
|
@import "../imports/ui/Production.import.styl"
|
||||||
|
@import "../imports/ui/Workers.import.styl"
|
||||||
@import "../imports/ui/Graphs.import.styl"
|
@import "../imports/ui/Graphs.import.styl"
|
||||||
@import "../imports/ui/TestList.import.styl"
|
@import "../imports/ui/TestList.import.styl"
|
||||||
@@ -113,7 +113,7 @@ if(Meteor.isServer) {
|
|||||||
check(order, Number);
|
check(order, Number);
|
||||||
|
|
||||||
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
Products.update(id, {$set: {name, postfix, order, updatedAt: new Date()}});
|
Measures.update(id, {$set: {name, postfix, order, updatedAt: new Date()}});
|
||||||
}
|
}
|
||||||
else throw new Meteor.Error(403, "Not authorized.");
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,9 @@ import { Mongo } from 'meteor/mongo';
|
|||||||
import { check } from 'meteor/check';
|
import { check } from 'meteor/check';
|
||||||
import {SimpleSchema} from 'meteor/aldeed:simple-schema';
|
import {SimpleSchema} from 'meteor/aldeed:simple-schema';
|
||||||
|
|
||||||
|
const TYPES = ['Retail', "Farmer's Market", "Restaurant", "Mail"];
|
||||||
|
const FREQUENCIES = ['Daily', 'Weekly'];
|
||||||
|
|
||||||
Venues = new Mongo.Collection('Venues');
|
Venues = new Mongo.Collection('Venues');
|
||||||
let VenuesSchema = new SimpleSchema({
|
let VenuesSchema = new SimpleSchema({
|
||||||
name: {
|
name: {
|
||||||
@@ -17,7 +20,15 @@ let VenuesSchema = new SimpleSchema({
|
|||||||
type: String,
|
type: String,
|
||||||
label: "Type",
|
label: "Type",
|
||||||
optional: false,
|
optional: false,
|
||||||
trim: true
|
trim: true,
|
||||||
|
allowedValues: TYPES //If you change these values, also change Venues.js for the editor to include the new list when setting up the combo.
|
||||||
|
},
|
||||||
|
frequency: { // How often the market is run. The exact day or week is not important, just that it is daily, weekly, bi-weekly, monthly, etc... Currently only supporting Daily and Weekly since all markets fit into these categories.
|
||||||
|
type: String,
|
||||||
|
label: "Frequency",
|
||||||
|
optional: false,
|
||||||
|
defaultValue: 'Daily',
|
||||||
|
allowedValues: FREQUENCIES //If you change these values, also change Venues.js for the editor to include the new list when setting up the combo.
|
||||||
},
|
},
|
||||||
createdAt: {
|
createdAt: {
|
||||||
type: Date,
|
type: Date,
|
||||||
@@ -40,6 +51,7 @@ let VenuesSchema = new SimpleSchema({
|
|||||||
optional: true
|
optional: true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
VenuesSchema.constants = {types: TYPES, frequencies: FREQUENCIES};
|
||||||
Venues.attachSchema(VenuesSchema);
|
Venues.attachSchema(VenuesSchema);
|
||||||
|
|
||||||
if(Meteor.isServer) Meteor.publish('venues', function() {
|
if(Meteor.isServer) Meteor.publish('venues', function() {
|
||||||
@@ -58,12 +70,30 @@ if(Meteor.isServer) {
|
|||||||
//});
|
//});
|
||||||
|
|
||||||
Meteor.methods({
|
Meteor.methods({
|
||||||
createVenue: function(name, type) {
|
createVenue: function(name, type, frequency) {
|
||||||
check(name, String);
|
check(name, String);
|
||||||
check(type, String);
|
check(type, String);
|
||||||
|
check(frequency, String);
|
||||||
|
|
||||||
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
Venues.insert({name, type, createdAt: new Date()});
|
Venues.insert({name, type, frequency, createdAt: new Date()});
|
||||||
|
}
|
||||||
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
|
},
|
||||||
|
//deleteVenue: function(id) {
|
||||||
|
// if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
|
// Venues.remove(id); //TODO: If this is ever allowed, we should either remove or replace references to the deleted venue in the rest of the database.
|
||||||
|
// }
|
||||||
|
// else throw new Meteor.Error(403, "Not authorized.");
|
||||||
|
//},
|
||||||
|
updateVenue: function(id, name, type, frequency) {
|
||||||
|
check(id, String);
|
||||||
|
check(name, String);
|
||||||
|
check(type, String);
|
||||||
|
check(frequency, String);
|
||||||
|
|
||||||
|
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
|
Venues.update(id, {$set: {name, type, frequency, updatedAt: new Date()}});
|
||||||
}
|
}
|
||||||
else throw new Meteor.Error(403, "Not authorized.");
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
},
|
},
|
||||||
@@ -92,22 +122,6 @@ if(Meteor.isServer) {
|
|||||||
Venues.update(id, {$set: {hidden: false}}, {bypassCollection2: true});
|
Venues.update(id, {$set: {hidden: false}}, {bypassCollection2: true});
|
||||||
}
|
}
|
||||||
else throw new Meteor.Error(403, "Not authorized.");
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
},
|
|
||||||
//deleteVenue: function(id) {
|
|
||||||
// if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
|
||||||
// Venues.remove(id); //TODO: If this is ever allowed, we should either remove or replace references to the deleted venue in the rest of the database.
|
|
||||||
// }
|
|
||||||
// else throw new Meteor.Error(403, "Not authorized.");
|
|
||||||
//},
|
|
||||||
updateVenue: function(id, name, type) {
|
|
||||||
check(id, String);
|
|
||||||
check(name, String);
|
|
||||||
check(type, String);
|
|
||||||
|
|
||||||
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
|
||||||
Venues.update(id, {$set: {name, type, updatedAt: new Date()}});
|
|
||||||
}
|
|
||||||
else throw new Meteor.Error(403, "Not authorized.");
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
125
imports/api/Worker.js
Normal file
125
imports/api/Worker.js
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
import { Meteor } from 'meteor/meteor';
|
||||||
|
import { Mongo } from 'meteor/mongo';
|
||||||
|
import { check } from 'meteor/check';
|
||||||
|
import {SimpleSchema} from 'meteor/aldeed:simple-schema';
|
||||||
|
|
||||||
|
Workers = new Mongo.Collection('Workers');
|
||||||
|
let WORKER_ACTIVITIES = ['sales', 'prep', 'canning', 'farming'];
|
||||||
|
let workersSchema = new SimpleSchema({
|
||||||
|
name: {
|
||||||
|
type: String,
|
||||||
|
label: "Name",
|
||||||
|
optional: false,
|
||||||
|
trim: true,
|
||||||
|
index: 1,
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
activities: {
|
||||||
|
type: [String],
|
||||||
|
label: "Activities",
|
||||||
|
optional: false,
|
||||||
|
trim: true
|
||||||
|
},
|
||||||
|
hourlyRate: {
|
||||||
|
type: SimpleSchema.Integer,
|
||||||
|
label: "HourlyRate",
|
||||||
|
optional: false,
|
||||||
|
min: 0
|
||||||
|
},
|
||||||
|
createdAt: { //Force the value to the current date on the server.
|
||||||
|
type: Date,
|
||||||
|
label: "Created On",
|
||||||
|
// autoValue: function() { //The disadvantage of autoValue is that it sets the date after insertion, causing the UI to update twice - once where the item has no date, and then again where the date is set. Sorted lists will cause the item to bounce around.
|
||||||
|
// if(this.isInsert) return new Date();
|
||||||
|
// else if(this.isUpsert) return {$setOnInsert: new Date()};
|
||||||
|
// else this.unset();
|
||||||
|
// },
|
||||||
|
// denyUpdate: true,
|
||||||
|
optional: false
|
||||||
|
},
|
||||||
|
updatedAt: {
|
||||||
|
type: Date,
|
||||||
|
label: "Updated On",
|
||||||
|
// autoValue: function() {
|
||||||
|
// if(this.isUpdate) return new Date();
|
||||||
|
// },
|
||||||
|
// denyInsert: true,
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
deactivated: {
|
||||||
|
type: Boolean,
|
||||||
|
label: "Deactivated",
|
||||||
|
optional: true
|
||||||
|
},
|
||||||
|
hidden: {
|
||||||
|
type: Boolean,
|
||||||
|
label: "Hidden",
|
||||||
|
optional: true
|
||||||
|
}
|
||||||
|
});
|
||||||
|
workersSchema.constants = {activities: WORKER_ACTIVITIES};
|
||||||
|
Workers.attachSchema(workersSchema);
|
||||||
|
|
||||||
|
if(Meteor.isServer) Meteor.publish('Workers', function() {
|
||||||
|
return Workers.find({});
|
||||||
|
});
|
||||||
|
|
||||||
|
if(Meteor.isServer) {
|
||||||
|
Meteor.methods({
|
||||||
|
createWorker: function(name, activities, hourlyRate) {
|
||||||
|
check(name, String);
|
||||||
|
check(activities, [String]);
|
||||||
|
check(hourlyRate, Number);
|
||||||
|
|
||||||
|
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
|
Workers.insert({name, activities, hourlyRate, createdAt: new Date()});
|
||||||
|
}
|
||||||
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
|
},
|
||||||
|
//deleteWorker: function(id) {
|
||||||
|
// if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
|
// //TODO: Should troll the database looking for references to remove or replace. This is currently not used.
|
||||||
|
// Workers.remove(id);
|
||||||
|
// }
|
||||||
|
// else throw new Meteor.Error(403, "Not authorized.");
|
||||||
|
//},
|
||||||
|
updateWorker: function(id, name, activities, hourlyRate) {
|
||||||
|
check(id, String);
|
||||||
|
check(name, String);
|
||||||
|
check(activities, [String]);
|
||||||
|
check(hourlyRate, Number);
|
||||||
|
|
||||||
|
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
|
Workers.update(id, {$set: {name, activities, hourlyRate, updatedAt: new Date()}});
|
||||||
|
}
|
||||||
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
|
},
|
||||||
|
deactivateWorker: function(id) {
|
||||||
|
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
|
//Workers.remove(id);
|
||||||
|
Workers.update(id, {$set: {deactivated: true}}, {bypassCollection2: true});
|
||||||
|
}
|
||||||
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
|
},
|
||||||
|
reactivateWorker: function(id) {
|
||||||
|
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
|
Workers.update(id, {$set: {deactivated: false}}, {bypassCollection2: true});
|
||||||
|
}
|
||||||
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
|
},
|
||||||
|
hideWorker: function(id) { //One step past deactivated - will only show in the Workers list if hidden Workers are enabled.
|
||||||
|
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
|
Workers.update(id, {$set: {hidden: true}}, {bypassCollection2: true});
|
||||||
|
}
|
||||||
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
|
},
|
||||||
|
showWorker: function(id) { //Returns the measure to being simply deactivated. Will again show in lists.
|
||||||
|
if(Roles.userIsInRole(this.userId, [Meteor.UserRoles.ROLE_UPDATE])) {
|
||||||
|
Workers.update(id, {$set: {hidden: false}}, {bypassCollection2: true});
|
||||||
|
}
|
||||||
|
else throw new Meteor.Error(403, "Not authorized.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Workers;
|
||||||
@@ -7,9 +7,10 @@ import SalesSheets from "./SalesSheet.js";
|
|||||||
import Logs from "./Logs.js";
|
import Logs from "./Logs.js";
|
||||||
import Users from "./User.js";
|
import Users from "./User.js";
|
||||||
import UserRoles from "./Roles.js";
|
import UserRoles from "./Roles.js";
|
||||||
|
import Workers from "./Worker.js";
|
||||||
|
|
||||||
//Save the collections in the Meteor.collections property for easy access without name conflicts.
|
//Save the collections in the Meteor.collections property for easy access without name conflicts.
|
||||||
Meteor.collections = {Measures, Venues, Products, ProductTags, Sales, SalesSheets, Logs, Users, UserRoles};
|
Meteor.collections = {Measures, Venues, Products, ProductTags, Sales, SalesSheets, Logs, Users, UserRoles, Workers};
|
||||||
|
|
||||||
//If this is the server then setup the default admin user if none exist.
|
//If this is the server then setup the default admin user if none exist.
|
||||||
if(Meteor.isServer) {
|
if(Meteor.isServer) {
|
||||||
|
|||||||
@@ -1,16 +1,24 @@
|
|||||||
import { AccountsTemplates } from 'meteor/useraccounts:core';
|
import { AccountsTemplates } from 'meteor/useraccounts:core';
|
||||||
|
|
||||||
AccountsTemplates.configure({
|
AccountsTemplates.configure({
|
||||||
forbidClientAccountCreation: true,
|
forbidClientAccountCreation: true, //Turn off client side account creation. The app is expected to have a feature that will do this.
|
||||||
showForgotPasswordLink: true,
|
showForgotPasswordLink: true,
|
||||||
defaultTemplate: 'atForm',
|
defaultTemplate: 'OverrideAtForm',
|
||||||
defaultLayout: 'Full',
|
//defaultTemplate: 'AuthorizationPage', //The template for all the forms related to logging in or out.
|
||||||
defaultContentRegion: 'content',
|
defaultLayout: 'Login', //What page template to place the defaultTemplate in.
|
||||||
defaultLayoutRegions: {}
|
defaultContentRegion: 'content', //The content region of the page template to place the defaultTemplate in.
|
||||||
// defaultTemplate: 'Auth_page',
|
defaultLayoutRegions: {},
|
||||||
// defaultLayout: 'Body',
|
// defaultLayout: 'Body',
|
||||||
// defaultContentRegion: 'content',
|
// defaultContentRegion: 'content',
|
||||||
// defaultLayoutRegions: {}
|
// defaultLayoutRegions: {}
|
||||||
|
texts: {
|
||||||
|
title: {
|
||||||
|
signIn: ""
|
||||||
|
},
|
||||||
|
button: {
|
||||||
|
signIn: "Enter"
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// This removes the password field but returns it,
|
// This removes the password field but returns it,
|
||||||
@@ -29,6 +37,7 @@ AccountsTemplates.configure({
|
|||||||
// pwd
|
// pwd
|
||||||
// ]);
|
// ]);
|
||||||
let pwd = AccountsTemplates.removeField('password');
|
let pwd = AccountsTemplates.removeField('password');
|
||||||
|
|
||||||
AccountsTemplates.removeField('email');
|
AccountsTemplates.removeField('email');
|
||||||
AccountsTemplates.addFields([
|
AccountsTemplates.addFields([
|
||||||
{
|
{
|
||||||
@@ -46,6 +55,13 @@ AccountsTemplates.addFields([
|
|||||||
re: /.+@(.+){2,}\.(.+){2,}/,
|
re: /.+@(.+){2,}\.(.+){2,}/,
|
||||||
errStr: 'Invalid email',
|
errStr: 'Invalid email',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
_id: 'username_and_email',
|
||||||
|
type: 'text',
|
||||||
|
required: true,
|
||||||
|
displayName: "Login",
|
||||||
|
placeholder: "Login / Email"
|
||||||
|
},
|
||||||
pwd
|
pwd
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,13 @@ pri.route('/venues', {
|
|||||||
BlazeLayout.render('Body', {content: 'Venues'});
|
BlazeLayout.render('Body', {content: 'Venues'});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
pri.route('/workers', {
|
||||||
|
name: 'Workers',
|
||||||
|
action: function(params, queryParams) {
|
||||||
|
require("/imports/ui/Workers.js");
|
||||||
|
BlazeLayout.render('Body', {content: 'Workers'});
|
||||||
|
}
|
||||||
|
});
|
||||||
pri.route('/graphs', {
|
pri.route('/graphs', {
|
||||||
name: 'Graphs',
|
name: 'Graphs',
|
||||||
action: function(params, queryParams) {
|
action: function(params, queryParams) {
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
<div class="editorDiv"><label>Name:</label><input name="name" class="form-control" type="text" value="{{name}}" autocomplete="off" required></div>
|
<div class="editorDiv"><label>Name:</label><input name="name" class="form-control" type="text" value="{{name}}" autocomplete="off" required></div>
|
||||||
<div class="editorDiv"><label>Postfix:</label><input name="postfix" class="form-control" type="text" value="{{name}}" autocomplete="off" required></div>
|
<div class="editorDiv"><label>Postfix:</label><input name="postfix" class="form-control" type="text" value="{{name}}" autocomplete="off" required></div>
|
||||||
</td>
|
</td>
|
||||||
<td class="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>
|
<td class="center measureEditorTd actions"><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>
|
||||||
|
|
||||||
<template name="MeasureSearch">
|
<template name="MeasureSearch">
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th class="name">Name {{>VenueSearch columnName='name'}}</th>
|
<th class="name">Name {{>VenueSearch columnName='name'}}</th>
|
||||||
<th class="type">Type {{>VenueSearch columnName='type'}}</th>
|
<th class="type">Type {{>VenueSearch columnName='type'}}</th>
|
||||||
|
<th class="type">Frequency</th>
|
||||||
<th class="actions">Actions <span class="newVenueButton 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>
|
<th class="actions">Actions <span class="newVenueButton 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>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -31,7 +32,7 @@
|
|||||||
<table class="table table-striped table-hover">
|
<table class="table table-striped table-hover">
|
||||||
<tbody>
|
<tbody>
|
||||||
{{#if displayNewVenue}}
|
{{#if displayNewVenue}}
|
||||||
{{> VenueEditor isNew=true}}
|
<tr>{{> VenueEditor isNew=true}}</tr>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{#each venues}}
|
{{#each venues}}
|
||||||
{{> Venue}}
|
{{> Venue}}
|
||||||
@@ -53,6 +54,7 @@
|
|||||||
{{else}}
|
{{else}}
|
||||||
<td class="name noselect nonclickable left">{{name}}</td>
|
<td class="name noselect nonclickable left">{{name}}</td>
|
||||||
<td class="type noselect nonclickable left">{{type}}</td>
|
<td class="type noselect nonclickable left">{{type}}</td>
|
||||||
|
<td class="type noselect nonclickable left">{{frequency}}</td>
|
||||||
{{#if hidden}}
|
{{#if hidden}}
|
||||||
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionShow fa fa-eye fa-lg noselect clickable" title="Show" aria-hidden="true"></i></td>
|
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionShow fa fa-eye fa-lg noselect clickable" title="Show" aria-hidden="true"></i></td>
|
||||||
{{else}}
|
{{else}}
|
||||||
@@ -67,11 +69,12 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template name="VenueEditor">
|
<template name="VenueEditor">
|
||||||
<td colspan="2" class="venueEditorTd">
|
<td colspan="3" class="venueEditorTd left">
|
||||||
<div class="editorDiv"><label>Name:</label><input name="name" class="form-control" type="text" value="{{name}}" autocomplete="off" required></div>
|
<div class="editorDiv"><label>Name</label> <input name="name" class="form-control" type="text" value="{{name}}" autocomplete="off" required></div>
|
||||||
<div class="editorDiv"><label>Type:</label><input name="type" class="form-control" type="text" value="{{name}}" autocomplete="off" required></div>
|
<div class="editorDiv"><label>Type</label> <input name="type" class="form-control" type="text" autocomplete="off" required></div>
|
||||||
|
<div class="editorDiv"><label>Frequency</label> <input name="frequency" class="form-control" type="text" autocomplete="off" required></div>
|
||||||
</td>
|
</td>
|
||||||
<td class="center venueEditorTd"><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>
|
<td class="venueEditorTd actions center"><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>
|
||||||
|
|
||||||
<template name="VenueSearch">
|
<template name="VenueSearch">
|
||||||
|
|||||||
7
imports/ui/Venues.import.styl
vendored
7
imports/ui/Venues.import.styl
vendored
@@ -46,10 +46,13 @@
|
|||||||
thead, tbody
|
thead, tbody
|
||||||
> tr
|
> tr
|
||||||
> .name
|
> .name
|
||||||
width: 50%
|
width: 33%
|
||||||
min-width: 100px
|
min-width: 100px
|
||||||
> .type
|
> .type
|
||||||
width: 50%
|
width: 33%
|
||||||
|
min-width: 100px
|
||||||
|
> .frequency
|
||||||
|
width: 33%
|
||||||
min-width: 100px
|
min-width: 100px
|
||||||
> .actions
|
> .actions
|
||||||
width: 90px
|
width: 90px
|
||||||
|
|||||||
@@ -181,7 +181,16 @@ Template.Venue.events({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Template.VenueEditor.onCreated(function() {
|
||||||
|
this.selectedType = new ReactiveVar(this.data.type);
|
||||||
|
this.selectedFrequency = new ReactiveVar(this.data.frequency);
|
||||||
|
});
|
||||||
|
Template.VenueEditor.onRendered(function() {
|
||||||
|
let schema = Meteor.collections.Venues.simpleSchema();
|
||||||
|
|
||||||
|
this.$('[name="type"]').buildCombo({set: schema.constants.types, selection: this.selectedType, comparator: function(a, b) {return a === b;}, textAttr: undefined, listClass: 'comboList'});
|
||||||
|
this.$('[name="frequency"]').buildCombo({set: schema.constants.frequencies, selection: this.selectedFrequency, comparator: function(a, b) {return a === b;}, textAttr: undefined, listClass: 'comboList'});
|
||||||
|
});
|
||||||
Template.VenueEditor.helpers({
|
Template.VenueEditor.helpers({
|
||||||
});
|
});
|
||||||
Template.VenueEditor.events({
|
Template.VenueEditor.events({
|
||||||
@@ -193,10 +202,11 @@ Template.VenueEditor.events({
|
|||||||
"click .editorApply": function(event, template) {
|
"click .editorApply": function(event, template) {
|
||||||
let name = template.$("input[name='name']").val().trim();
|
let name = template.$("input[name='name']").val().trim();
|
||||||
let type = template.$("input[name='type']").val().trim();
|
let type = template.$("input[name='type']").val().trim();
|
||||||
|
let frequency = template.$("input[name='frequency']").val().trim();
|
||||||
let order = 0; //TODO:
|
let order = 0; //TODO:
|
||||||
|
|
||||||
if(Session.get(PREFIX + 'displayNewVenue')) {
|
if(Session.get(PREFIX + 'displayNewVenue')) {
|
||||||
Meteor.call("createVenue", name, type, order, function(error, result) {
|
Meteor.call("createVenue", name, type, frequency, order, function(error, result) {
|
||||||
if(error) sAlert.error(error);
|
if(error) sAlert.error(error);
|
||||||
else {
|
else {
|
||||||
sAlert.success("Venue created.");
|
sAlert.success("Venue created.");
|
||||||
@@ -206,7 +216,7 @@ Template.VenueEditor.events({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Meteor.call("updateVenue", this._id, name, type, order, function(error, result) {
|
Meteor.call("updateVenue", this._id, name, type, frequency, order, function(error, result) {
|
||||||
if(error) sAlert.error(error);
|
if(error) sAlert.error(error);
|
||||||
else {
|
else {
|
||||||
sAlert.success("Venue updated.");
|
sAlert.success("Venue updated.");
|
||||||
|
|||||||
90
imports/ui/Workers.html
Normal file
90
imports/ui/Workers.html
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<template name="Workers">
|
||||||
|
<div id="workers">
|
||||||
|
{{#if Template.subscriptionsReady}}
|
||||||
|
<div class="tableControls">
|
||||||
|
<div class="showHidden">
|
||||||
|
<span class="controlLabel">Show Hidden</span>
|
||||||
|
<div class="toggleShowHidden checkbox checkbox-slider--b-flat">
|
||||||
|
<label>
|
||||||
|
<input type="checkbox" name="showHidden"><span></span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<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="name">Name {{>WorkerSearch columnName='name'}}</th>
|
||||||
|
<th class="activities">Activities</th>
|
||||||
|
<th class="hourlyRate">Avg Hourly Rate</th>
|
||||||
|
<th class="actions">Actions <span class="newWorkerButton 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="listRow">
|
||||||
|
<div class="listCell">
|
||||||
|
<div class="tableContainer mCustomScrollbar" data-mcs-theme="dark">
|
||||||
|
<table class="table table-striped table-hover">
|
||||||
|
<tbody>
|
||||||
|
{{#if displayNewWorker}}
|
||||||
|
<tr>{{> WorkerEditor isNew=true}}</tr>
|
||||||
|
{{/if}}
|
||||||
|
{{#each workers}}
|
||||||
|
{{> Worker}}
|
||||||
|
{{/each}}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{else}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="Worker">
|
||||||
|
<tr class="{{getRowClass}}">
|
||||||
|
{{#if editing}}
|
||||||
|
{{> WorkerEditor}}
|
||||||
|
{{else}}
|
||||||
|
<td class="name noselect nonclickable left">{{name}}</td>
|
||||||
|
<td class="activities noselect nonclickable left">{{activities}}</td>
|
||||||
|
<td class="hourlyRate noselect nonclickable left">{{hourlyRate}}</td>
|
||||||
|
{{#if hidden}}
|
||||||
|
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionShow fa fa-eye fa-lg noselect clickable" title="Show" aria-hidden="true"></i></td>
|
||||||
|
{{else}}
|
||||||
|
{{#if deactivated}}
|
||||||
|
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionActivate fa fa-toggle-on fa-lg noselect clickable" title="Activate" aria-hidden="true"></i> / <i class="actionHide fa fa-eye-slash fa-lg noselect clickable" title="Hide" aria-hidden="true"></i></td>
|
||||||
|
{{else}}
|
||||||
|
<td class="actions center"><i class="actionEdit fa fa-pencil-square-o fa-lg noselect clickable" title="Edit" aria-hidden="true"></i> / <i class="actionRemove fa fa-times-circle fa-lg noselect clickable" title="Deactivate" aria-hidden="true"></i></td>
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</tr>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template name="WorkerEditor">
|
||||||
|
<td colspan="3" class="workerEditorTd">
|
||||||
|
<div class="editorDiv"><label>Name</label> <input name="name" class="form-control" type="text" value="{{name}}" autocomplete="off" required></div>
|
||||||
|
<div class="editorDiv"><label>Activities</label>
|
||||||
|
<select class="activitiesEditor" multiple="multiple">
|
||||||
|
{{#each activities}}
|
||||||
|
<option value="{{this}}" {{activitySelected}}>{{this}}</option>
|
||||||
|
{{/each}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="editorDiv"><label>Avg Hourly Rate</label> <input name="hourlyRate" class="form-control" type="number" min="0" step="0.01" data-schema-key='currency' value="{{name}}" autocomplete="off" required></div>
|
||||||
|
</td>
|
||||||
|
<td class="center workerEditorTd actions"><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="WorkerSearch">
|
||||||
|
<div class="workerSearch">
|
||||||
|
<input type="text" class="searchInput" placeholder="Filter..." value="{{searchValue}}"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
145
imports/ui/Workers.import.styl
vendored
Normal file
145
imports/ui/Workers.import.styl
vendored
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
#workers
|
||||||
|
display: table
|
||||||
|
content-box: border-box
|
||||||
|
padding: 10px 20px
|
||||||
|
height: 100%
|
||||||
|
width: 100%
|
||||||
|
text-align: left
|
||||||
|
|
||||||
|
.tableControls
|
||||||
|
display: table
|
||||||
|
width: 100%
|
||||||
|
text-align: right
|
||||||
|
margin-right: 20px
|
||||||
|
.showHidden
|
||||||
|
display: table-cell
|
||||||
|
width: 100%
|
||||||
|
.controlLabel
|
||||||
|
font-size: 9px
|
||||||
|
font-weight: 700
|
||||||
|
color: #5a5a5a
|
||||||
|
position: relative
|
||||||
|
top: -2px
|
||||||
|
.toggleShowHidden
|
||||||
|
margin: 0 40px 0 0
|
||||||
|
position: relative
|
||||||
|
top: -4px
|
||||||
|
display: inline-block
|
||||||
|
.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
|
||||||
|
.table
|
||||||
|
table-layout: fixed
|
||||||
|
min-width: 100%
|
||||||
|
thead, tbody
|
||||||
|
> tr
|
||||||
|
> .name
|
||||||
|
width: 30%
|
||||||
|
min-width: 100px
|
||||||
|
> .activities
|
||||||
|
width: 50%
|
||||||
|
min-width: 100px
|
||||||
|
> .hourlyRate
|
||||||
|
width: 20%
|
||||||
|
min-width: 100px
|
||||||
|
> .actions
|
||||||
|
width: 90px
|
||||||
|
min-width: 90px
|
||||||
|
.separatedTableHeader
|
||||||
|
table
|
||||||
|
thead
|
||||||
|
> tr
|
||||||
|
.actions
|
||||||
|
text-align: center
|
||||||
|
.newWorkerButton
|
||||||
|
margin-top: 4px
|
||||||
|
padding: 0 12px
|
||||||
|
.fa-plus-circle
|
||||||
|
display: inline-block
|
||||||
|
.fa-times-circle
|
||||||
|
display: none
|
||||||
|
.newWorkerButton.active
|
||||||
|
background-color: #fb557b
|
||||||
|
color: black
|
||||||
|
.fa-times-circle
|
||||||
|
display: inline-block
|
||||||
|
.fa-plus-circle
|
||||||
|
display: none
|
||||||
|
.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%
|
||||||
|
.workerSearch
|
||||||
|
margin: 3px 0 2px 1px
|
||||||
|
.workerEditorTd
|
||||||
|
background: #deeac0
|
||||||
|
input[name="name"], .activitiesEditor, input[name="hourlyRate"]
|
||||||
|
width: 100%
|
||||||
|
.editorDiv
|
||||||
|
margin: 4px 0
|
||||||
|
label
|
||||||
|
font-family: "Arial Black", "Arial Bold", Gadget, sans-serif
|
||||||
|
font-size: .9em
|
||||||
|
padding-bottom: 4px
|
||||||
|
select2
|
||||||
|
font-size: .4em
|
||||||
|
> thead
|
||||||
|
display: none
|
||||||
|
visibility: hidden
|
||||||
|
> tbody
|
||||||
|
> tr
|
||||||
|
.actionRemove
|
||||||
|
color: #F77
|
||||||
|
.actionEdit
|
||||||
|
color: #44F
|
||||||
|
.editorApply
|
||||||
|
color: green
|
||||||
|
.editorCancel
|
||||||
|
color: red
|
||||||
|
> tr.deactivated
|
||||||
|
background-color: #fac0d1
|
||||||
|
.actionActivate
|
||||||
|
color: #158b18
|
||||||
|
.actionHide
|
||||||
|
color: #6a0707
|
||||||
|
.actionEdit
|
||||||
|
color: #0101e4
|
||||||
|
> tr.deactivated:hover
|
||||||
|
background-color: #ffcadb
|
||||||
|
> tr.hidden
|
||||||
|
background-color: #e995ff
|
||||||
|
.actionEdit
|
||||||
|
color: #0101e4
|
||||||
|
.actionShow
|
||||||
|
color: #027905
|
||||||
|
> tr.hidden:hover
|
||||||
|
background-color: #ffb5ff
|
||||||
237
imports/ui/Workers.js
Normal file
237
imports/ui/Workers.js
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
|
||||||
|
import './Workers.html';
|
||||||
|
|
||||||
|
let QUERY_LIMIT = 100;
|
||||||
|
let QUERY_LIMIT_INCREMENT = 100;
|
||||||
|
let PREFIX = "Workers.";
|
||||||
|
|
||||||
|
Tracker.autorun(function() {
|
||||||
|
Meteor.subscribe("Workers");
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.Workers.onCreated(function() {
|
||||||
|
Session.set(PREFIX + "displayNewWorker", false);
|
||||||
|
Session.set(PREFIX + "showHidden", false);
|
||||||
|
Session.set(PREFIX + "queryLimit", QUERY_LIMIT);
|
||||||
|
});
|
||||||
|
Template.Workers.onRendered(function() {
|
||||||
|
$(".tableContainer").mCustomScrollbar({
|
||||||
|
scrollButtons: {enable:true},
|
||||||
|
theme: "light-thick",
|
||||||
|
scrollbarPosition: "outside",
|
||||||
|
scrollEasing: "linear"
|
||||||
|
});
|
||||||
|
});
|
||||||
|
Template.Workers.helpers({
|
||||||
|
displayNewWorker: function() {
|
||||||
|
return Session.get(PREFIX + "displayNewWorker");
|
||||||
|
},
|
||||||
|
workers: 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 + 'workerCount', Meteor.collections.Workers.find(dbQuery).count()); //Always get a full count.
|
||||||
|
return Meteor.collections.Workers.find(dbQuery, {limit: Session.get(PREFIX + "queryLimit"), skip: skipCount, sort: {order: 1}});
|
||||||
|
},
|
||||||
|
disableLoadMore: function() {
|
||||||
|
return Session.get(PREFIX + 'workerCount') - (Session.get(PREFIX + 'skipCount') || 0) - Session.get(PREFIX + "queryLimit") <= 0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Template.Workers.events({
|
||||||
|
'click .loadMoreLink': function(event, template) {
|
||||||
|
event.preventDefault();
|
||||||
|
Session.set(PREFIX + 'queryLimit', Session.get(PREFIX + "queryLimit") + QUERY_LIMIT_INCREMENT);
|
||||||
|
},
|
||||||
|
'click .newWorkerButton': function(event, template) {
|
||||||
|
if(template.$('.newWorkerButton').hasClass('active')) {
|
||||||
|
Session.set(PREFIX + 'displayNewWorker', false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Session.set(PREFIX + 'displayNewWorker', true);
|
||||||
|
Session.set(PREFIX + "editedWorker", undefined); //Clear the edited worker so that only one editor is open at a time.
|
||||||
|
}
|
||||||
|
template.$('.newWorkerButton').toggleClass('active');
|
||||||
|
},
|
||||||
|
'change input[name="showHidden"]': function(event, template) {
|
||||||
|
Session.set(PREFIX + "showHidden", $(event.target).prop('checked'));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.WorkerSearch.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 + 'searchFields', searchFields);
|
||||||
|
Session.set(PREFIX + 'skipCount', 0); //Reset the paging of the results.
|
||||||
|
}, 500)
|
||||||
|
});
|
||||||
|
Template.WorkerSearch.helpers({
|
||||||
|
searchValue: function() {
|
||||||
|
let searchFields = Session.get(PREFIX + 'searchFields');
|
||||||
|
|
||||||
|
return (searchFields && searchFields[this.columnName]) ? searchFields[this.columnName] : '';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Template.Worker.helpers({
|
||||||
|
workers: function() {
|
||||||
|
let result = "";
|
||||||
|
|
||||||
|
if(this.workers && this.workers.length > 0) {
|
||||||
|
let workerNames = [];
|
||||||
|
|
||||||
|
for(let i = 0; i < this.workers.length; i++) {
|
||||||
|
let workerObject = Meteor.collections.Workers.findOne(this.workers[i]);
|
||||||
|
|
||||||
|
if(workerObject && workerObject.name)
|
||||||
|
workerNames.push(workerObject.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
result = workerNames.join(", ");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
editing: function() {
|
||||||
|
let editedWorker = Session.get(PREFIX + "editedWorker");
|
||||||
|
|
||||||
|
return editedWorker == this._id;
|
||||||
|
},
|
||||||
|
getRowClass: function() {
|
||||||
|
return this.hidden ? "hidden" : this.deactivated ? "deactivated" : "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Template.Worker.events({
|
||||||
|
"click .actionEdit": function(event, template) {
|
||||||
|
Session.set(PREFIX + "editedWorker", this._id);
|
||||||
|
Session.set(PREFIX + 'displayNewWorker', false); //Ensure the new worker editor is closed.
|
||||||
|
template.parentTemplate().$('.newWorkerButton').removeClass('active');
|
||||||
|
},
|
||||||
|
"click .actionRemove": function(event, template) {
|
||||||
|
Meteor.call('deactivateWorker', this._id, function(error, result) {
|
||||||
|
if(error) sAlert.error(error);
|
||||||
|
else sAlert.success("Worker Deactivated");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'click .actionActivate': function(event, template) {
|
||||||
|
Meteor.call('reactivateWorker', this._id, function(error, result) {
|
||||||
|
if(error) sAlert.error(error);
|
||||||
|
else sAlert.success("Worker Reactivated");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
"click .actionShow": function(event, template) {
|
||||||
|
Meteor.call('showWorker', this._id, function(error, result) {
|
||||||
|
if(error) sAlert.error(error);
|
||||||
|
else sAlert.success("Worker Visibility Enabled");
|
||||||
|
});
|
||||||
|
},
|
||||||
|
'click .actionHide': function(event, template) {
|
||||||
|
Meteor.call('hideWorker', this._id, function(error, result) {
|
||||||
|
if(error) sAlert.error(error);
|
||||||
|
else sAlert.success("Worker Visibility Disabled");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
Template.WorkerEditor.onRendered(function() {
|
||||||
|
this.$(".activitiesEditor").select2();
|
||||||
|
});
|
||||||
|
Template.WorkerEditor.helpers({
|
||||||
|
activities: function() {
|
||||||
|
let schema = Meteor.collections.Workers.simpleSchema();
|
||||||
|
|
||||||
|
return schema.constants.activities;
|
||||||
|
},
|
||||||
|
activitySelected: function() {
|
||||||
|
let activity = this;
|
||||||
|
let worker = Template.parentData();
|
||||||
|
|
||||||
|
return worker.activities && worker.activities.includes(activity) ? "selected" : "";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Template.WorkerEditor.events({
|
||||||
|
"click .editorCancel": function(event, template) {
|
||||||
|
Session.set(PREFIX + "editedWorker", undefined);
|
||||||
|
Session.set(PREFIX + 'displayNewWorker', false);
|
||||||
|
template.parentTemplate().$('.newWorkerButton').removeClass('active');
|
||||||
|
},
|
||||||
|
"click .editorApply": function(event, template) {
|
||||||
|
let name = template.$("input[name='name']").val().trim();
|
||||||
|
let activities = template.$(".activitiesEditor").select2('data');
|
||||||
|
let hourlyRate = template.$("input[name='hourlyRate']").val().trim();
|
||||||
|
|
||||||
|
activities = activities.map((n)=>n.id);
|
||||||
|
hourlyRate = Number(hourlyRate);
|
||||||
|
|
||||||
|
if(Session.get(PREFIX + 'displayNewWorker')) {
|
||||||
|
Meteor.call("createWorker", name, activities, hourlyRate, function(error, result) {
|
||||||
|
if(error) sAlert.error(error);
|
||||||
|
else {
|
||||||
|
sAlert.success("Worker created.");
|
||||||
|
Session.set(PREFIX + 'displayNewWorker', false);
|
||||||
|
template.parentTemplate().$('.newWorkerButton').removeClass('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Meteor.call("updateWorker", this._id, name, activities, hourlyRate, function(error, result) {
|
||||||
|
if(error) sAlert.error(error);
|
||||||
|
else {
|
||||||
|
sAlert.success("Worker updated.");
|
||||||
|
Session.set(PREFIX + "editedWorker", undefined);
|
||||||
|
template.parentTemplate().$('.newWorkerButton').removeClass('active');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -1,65 +1,58 @@
|
|||||||
<template name="Auth_page">
|
<template name="OverrideAtForm">
|
||||||
<div class="page auth">
|
{{#unless hide}}
|
||||||
<nav>
|
<div class="at-form">
|
||||||
<div class="nav-group">
|
<!--{{#if showTitle}}-->
|
||||||
<a href="#" class="js-menu nav-item">
|
<!--{{> atTitle}}-->
|
||||||
<span class="icon-list-unordered"></span>
|
<!--{{/if}}-->
|
||||||
</a>
|
{{#if showOauthServices}}
|
||||||
</div>
|
{{> atOauth}}
|
||||||
</nav>
|
{{/if}}
|
||||||
|
{{#if showServicesSeparator}}
|
||||||
<div class="content-scrollable">
|
{{> atSep}}
|
||||||
<div class="wrapper-auth">
|
{{/if}}
|
||||||
{{> atForm}}
|
{{#if showError}}
|
||||||
</div>
|
{{> atError}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if showResult}}
|
||||||
|
{{> atResult}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if showMessage}}
|
||||||
|
{{> atMessage}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if showPwdForm}}
|
||||||
|
{{> OverrideAtPwdForm}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if showTermsLink}}
|
||||||
|
{{> atTermsLink}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if showSignInLink}}
|
||||||
|
{{> atSigninLink}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if showSignUpLink}}
|
||||||
|
{{> atSignupLink}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if showResendVerificationEmailLink}}
|
||||||
|
{{> atResendVerificationEmailLink}}
|
||||||
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{{/unless}}
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<template name="override-atPwdFormBtn">
|
<template name="OverrideAtPwdForm">
|
||||||
<button type="submit" class="btn-primary">
|
|
||||||
{{buttonText}}
|
|
||||||
</button>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template name="override-atTextInput">
|
|
||||||
<div class="input {{#if isValidating}}validating{{/if}} {{#if hasError}}error{{/if}} {{#if hasSuccess}}has-success{{/if}} {{#if feedback}}has-feedback{{/if}}">
|
|
||||||
<input type="{{type}}" id="at-field-{{_id}}" name="at-field-{{_id}}" placeholder="{{placeholder}}" autocapitalize="none" autocorrect="off">
|
|
||||||
{{#if hasIcon}}
|
|
||||||
<span class="{{iconClass}}"></span>
|
|
||||||
{{/if}}
|
|
||||||
{{#if hasError}}
|
|
||||||
<span>{{errorText}}</span>
|
|
||||||
{{/if}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template name="override-atTitle">
|
|
||||||
<h1 class="title-auth">{{title}}</h1>
|
|
||||||
<p class="subtitle-auth">Signing in allows you to have private lists</p>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template name="override-atError">
|
|
||||||
<div class="list-errors">
|
|
||||||
{{#each error}}
|
|
||||||
<div class="list-item">{{errorText}}</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<template name="override-atPwdForm">
|
|
||||||
<div class="at-pwd-form">
|
<div class="at-pwd-form">
|
||||||
<form role="form" id="at-pwd-form" class="{{disabled}}" novalidate action="#" method="POST">
|
<form role="form" id="at-pwd-form" novalidate action="#" method="POST">
|
||||||
{{#each fields}}
|
<fieldset {{disabled}}>
|
||||||
{{> atInput}}
|
{{#each fields}}
|
||||||
{{/each}}
|
{{> atInput}}
|
||||||
{{#if showReCaptcha}}
|
{{/each}}
|
||||||
{{> atReCaptcha}}
|
{{#if showReCaptcha}}
|
||||||
{{/if}}
|
{{> atReCaptcha}}
|
||||||
{{> atPwdFormBtn}}
|
{{/if}}
|
||||||
{{#if showForgotPasswordLink}}
|
{{> atPwdFormBtn}}
|
||||||
{{> atPwdLink}}
|
{{#if showForgotPasswordLink}}
|
||||||
{{/if}}
|
{{> atPwdLink}}
|
||||||
|
{{/if}}
|
||||||
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -2,6 +2,13 @@ import { Template } from 'meteor/templating';
|
|||||||
|
|
||||||
import './accounts.html';
|
import './accounts.html';
|
||||||
|
|
||||||
|
// Simply 'inherits' helpers from AccountsTemplates
|
||||||
|
Template.OverrideAtForm.helpers(AccountsTemplates.atFormHelpers);
|
||||||
|
|
||||||
|
// Simply 'inherits' helpers and events from AccountsTemplates
|
||||||
|
Template.OverrideAtPwdForm.helpers(AccountsTemplates.atPwdFormHelpers);
|
||||||
|
Template.OverrideAtPwdForm.events(AccountsTemplates.atPwdFormEvents);
|
||||||
|
|
||||||
// We identified the templates that need to be overridden by looking at the available templates
|
// We identified the templates that need to be overridden by looking at the available templates
|
||||||
// here: https://github.com/meteor-useraccounts/unstyled/tree/master/lib
|
// here: https://github.com/meteor-useraccounts/unstyled/tree/master/lib
|
||||||
// Template['override-atPwdFormBtn'].replaces('atPwdFormBtn');
|
// Template['override-atPwdFormBtn'].replaces('atPwdFormBtn');
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<template name="Body">
|
<template name="Body">
|
||||||
{{> sAlert}}
|
{{> sAlert}}
|
||||||
<div id="mainBody" class="mainBody">
|
<div id="mainBody" class="mainBody">
|
||||||
<nav class="leftSidebarContainer">
|
<nav class="leftSidebarContainer generalSidebar">
|
||||||
<a href="javascript:" class="fa fa-bars leftSidebarMenuButton" aria-hidden="true"></a>
|
<a href="javascript:" class="fa fa-balance-scale leftSidebarMenuButton generalMenuButton" aria-hidden="true"></a>
|
||||||
<div class="leftSidebar">
|
<div class="leftSidebar">
|
||||||
<div class="logoArea">
|
<div class="logoArea">
|
||||||
<i class="fa fa-sign-out fa-2x signOut" aria-hidden="true"></i>
|
<i class="fa fa-sign-out fa-2x signOut" aria-hidden="true"></i>
|
||||||
@@ -10,7 +10,63 @@
|
|||||||
<img src="/images/PetitTetonLogo_v2.png"/>
|
<img src="/images/PetitTetonLogo_v2.png"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="menuArea">
|
<div class="menuArea generalMenu">
|
||||||
|
<ul>
|
||||||
|
<li class="{{isActiveRoute 'Sales'}}">
|
||||||
|
<a href="{{pathFor 'Sales'}}">
|
||||||
|
Sales<!-- <a class="subMenu {{isActiveRoute 'SalesSheets'}}" href="{{pathFor 'SalesSheets'}}">Sales Sheets</a>-->
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="{{isActiveRoute 'SalesSheets'}}">
|
||||||
|
<a href="{{pathFor 'SalesSheets'}}">
|
||||||
|
Sales Sheets
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="{{isActiveRoute 'Production'}}">
|
||||||
|
<a href="{{pathFor 'Production'}}">
|
||||||
|
Production<!-- <span class="tag">sample</span>-->
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
© Petit Teton LLC 2017
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<nav class="leftSidebarContainer graphsSidebar">
|
||||||
|
<a href="javascript:" class="fa fa-line-chart leftSidebarMenuButton graphsMenuButton" aria-hidden="true"></a>
|
||||||
|
<div class="leftSidebar">
|
||||||
|
<div class="logoArea">
|
||||||
|
<i class="fa fa-sign-out fa-2x signOut" aria-hidden="true"></i>
|
||||||
|
<div class="logo">
|
||||||
|
<img src="/images/PetitTetonLogo_v2.png"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menuArea graphsMenu">
|
||||||
|
<ul>
|
||||||
|
<li class="{{isActiveRoute 'Graphs'}}">
|
||||||
|
<a href="{{pathFor 'Graphs'}}">
|
||||||
|
Graphs
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div class="footer">
|
||||||
|
© Petit Teton LLC 2017
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
<nav class="leftSidebarContainer settingsSidebar">
|
||||||
|
<a href="javascript:" class="fa fa-cogs leftSidebarMenuButton settingsMenuButton" aria-hidden="true"></a>
|
||||||
|
<div class="leftSidebar">
|
||||||
|
<div class="logoArea">
|
||||||
|
<i class="fa fa-sign-out fa-2x signOut" aria-hidden="true"></i>
|
||||||
|
<div class="logo">
|
||||||
|
<img src="/images/PetitTetonLogo_v2.png"/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="menuArea settingsMenu">
|
||||||
<ul>
|
<ul>
|
||||||
{{#if isInRole 'manage'}}
|
{{#if isInRole 'manage'}}
|
||||||
<li class="{{isActiveRoute 'UserManagement'}}">
|
<li class="{{isActiveRoute 'UserManagement'}}">
|
||||||
@@ -24,21 +80,6 @@
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<li class="{{isActiveRoute 'Sales'}}">
|
|
||||||
<a href="{{pathFor 'Sales'}}">
|
|
||||||
Sales <a class="subMenu {{isActiveRoute 'SalesSheets'}}" href="{{pathFor 'SalesSheets'}}">Sales Sheets</a>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<!--<li class="{{isActiveRoute 'SalesSheets'}}">-->
|
|
||||||
<!--<a href="{{pathFor 'SalesSheets'}}">-->
|
|
||||||
<!--Sales Sheets-->
|
|
||||||
<!--</a>-->
|
|
||||||
<!--</li>-->
|
|
||||||
<li class="{{isActiveRoute 'Production'}}">
|
|
||||||
<a href="{{pathFor 'Production'}}">
|
|
||||||
Production<!-- <span class="tag">sample</span>-->
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li class="{{isActiveRoute 'Products'}}">
|
<li class="{{isActiveRoute 'Products'}}">
|
||||||
<a href="{{pathFor 'Products'}}">
|
<a href="{{pathFor 'Products'}}">
|
||||||
Products
|
Products
|
||||||
@@ -64,9 +105,9 @@
|
|||||||
Venues
|
Venues
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="{{isActiveRoute 'Graphs'}}">
|
<li class="{{isActiveRoute 'Workers'}}">
|
||||||
<a href="{{pathFor 'Graphs'}}">
|
<a href="{{pathFor 'Workers'}}">
|
||||||
Graphs
|
Workers
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
18
imports/ui/layouts/Body.import.styl
vendored
18
imports/ui/layouts/Body.import.styl
vendored
@@ -44,7 +44,6 @@
|
|||||||
.leftSidebarMenuButton
|
.leftSidebarMenuButton
|
||||||
position: absolute
|
position: absolute
|
||||||
right: -30px
|
right: -30px
|
||||||
top: 10px
|
|
||||||
-webkit-transition: .5s ease-in
|
-webkit-transition: .5s ease-in
|
||||||
-moz-transition: .5s ease-in
|
-moz-transition: .5s ease-in
|
||||||
-o-transition: .5s ease-in
|
-o-transition: .5s ease-in
|
||||||
@@ -67,8 +66,22 @@
|
|||||||
padding: 5px 0
|
padding: 5px 0
|
||||||
background-color: #90b272
|
background-color: #90b272
|
||||||
display: block
|
display: block
|
||||||
|
border-top: 1px solid #494
|
||||||
|
border-right: 1px solid #494
|
||||||
|
border-bottom: 1px solid #494
|
||||||
.leftSidebarMenuButton:hover
|
.leftSidebarMenuButton:hover
|
||||||
color: rgba(150,0,0,.5)
|
color: rgba(150,0,0,.5)
|
||||||
|
nav.generalSidebar
|
||||||
|
.leftSidebarMenuButton
|
||||||
|
top: 10px
|
||||||
|
nav.graphsSidebar
|
||||||
|
.leftSidebarMenuButton
|
||||||
|
top: 50px
|
||||||
|
nav.settingsSidebar
|
||||||
|
.leftSidebarMenuButton
|
||||||
|
top: 90px
|
||||||
|
nav.menuHide .leftSidebarMenuButton
|
||||||
|
right: 60px
|
||||||
nav.menuShow
|
nav.menuShow
|
||||||
margin: 0
|
margin: 0
|
||||||
nav.menuShow .leftSidebarMenuButton
|
nav.menuShow .leftSidebarMenuButton
|
||||||
@@ -79,8 +92,9 @@
|
|||||||
-ms-transform: rotate(45deg) !important
|
-ms-transform: rotate(45deg) !important
|
||||||
transform: rotate(45deg) !important
|
transform: rotate(45deg) !important
|
||||||
-moz-border-radius-bottomright: 0
|
-moz-border-radius-bottomright: 0
|
||||||
border-top-right-radius: 0
|
//border-top-right-radius: 0
|
||||||
border-bottom-right-radius: 0
|
border-bottom-right-radius: 0
|
||||||
|
border-bottom: 0
|
||||||
.leftSidebar
|
.leftSidebar
|
||||||
flex: 0 0 auto
|
flex: 0 0 auto
|
||||||
display: flex
|
display: flex
|
||||||
|
|||||||
@@ -1,19 +1,54 @@
|
|||||||
import { Template } from 'meteor/templating';
|
import { Template } from 'meteor/templating';
|
||||||
import './Body.html';
|
import './Body.html';
|
||||||
|
|
||||||
|
Template.Body.toggleMenu = function($sidebar) {
|
||||||
|
let $sidebars = $('nav.leftSidebarContainer');
|
||||||
|
|
||||||
|
for(let i = 0; i < $sidebars.length; i++) {
|
||||||
|
if($sidebars[i] == $sidebar[0]) {
|
||||||
|
$sidebar.toggleClass('menuShow');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$($sidebars[i]).toggleClass('menuHide');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Template.Body.events({
|
Template.Body.events({
|
||||||
"click .signOut": function(event, template) {
|
"click .signOut": function(event, template) {
|
||||||
AccountsTemplates.logout();
|
AccountsTemplates.logout();
|
||||||
},
|
},
|
||||||
"click .leftSidebarMenuButton": function(event, template) {
|
// General Menu
|
||||||
|
"click .generalSidebar .leftSidebarMenuButton": function(event, template) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
$('nav.leftSidebarContainer').toggleClass('menuShow');
|
Template.Body.toggleMenu($('nav.generalSidebar'));
|
||||||
},
|
},
|
||||||
"click .menuArea a": function(event, template) {
|
"click .generalSidebar .leftSidebar a": function(event, template) {
|
||||||
$('nav.leftSidebarContainer').toggleClass('menuShow');
|
Template.Body.toggleMenu($('nav.generalSidebar'));
|
||||||
},
|
},
|
||||||
"click .menuArea a .subMenu": function(event, template) {
|
"click .generalSidebar .leftSidebar a .subMenu": function(event, template) {
|
||||||
$('nav.leftSidebarContainer').toggleClass('menuShow');
|
Template.Body.toggleMenu($('nav.generalSidebar'));
|
||||||
|
},
|
||||||
|
// Graphs Menu
|
||||||
|
"click .graphsSidebar .leftSidebarMenuButton": function(event, template) {
|
||||||
|
event.preventDefault();
|
||||||
|
Template.Body.toggleMenu($('nav.graphsSidebar'));
|
||||||
|
},
|
||||||
|
"click .graphsSidebar .leftSidebar a": function(event, template) {
|
||||||
|
Template.Body.toggleMenu($('nav.graphsSidebar'));
|
||||||
|
},
|
||||||
|
"click .graphsSidebar .leftSidebar a .subMenu": function(event, template) {
|
||||||
|
Template.Body.toggleMenu($('nav.graphsSidebar'));
|
||||||
|
},
|
||||||
|
// Settings Menu
|
||||||
|
"click .settingsSidebar .leftSidebarMenuButton": function(event, template) {
|
||||||
|
event.preventDefault();
|
||||||
|
Template.Body.toggleMenu($('nav.settingsSidebar'));
|
||||||
|
},
|
||||||
|
"click .settingsSidebar .leftSidebar a": function(event, template) {
|
||||||
|
Template.Body.toggleMenu($('nav.settingsSidebar'));
|
||||||
|
},
|
||||||
|
"click .settingsSidebar .leftSidebar a .subMenu": function(event, template) {
|
||||||
|
Template.Body.toggleMenu($('nav.settingsSidebar'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
<template name="Full">
|
|
||||||
<div id="full" class="content">
|
|
||||||
<div class="form">
|
|
||||||
{{> Template.dynamic template=content}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
11
imports/ui/layouts/Full.import.styl
vendored
11
imports/ui/layouts/Full.import.styl
vendored
@@ -1,11 +0,0 @@
|
|||||||
#full.content
|
|
||||||
//width: 100%
|
|
||||||
//height: 100%
|
|
||||||
//background-image: linear-gradient(to bottom, #315481, #918e82 100%)'
|
|
||||||
background: white
|
|
||||||
|
|
||||||
.form
|
|
||||||
//margin: 5% auto 0 auto
|
|
||||||
margin: 0 auto
|
|
||||||
width: 300px
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
import './Full.html';
|
|
||||||
8
imports/ui/layouts/Login.html
Normal file
8
imports/ui/layouts/Login.html
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<template name="Login">
|
||||||
|
<div id="login" class="content">
|
||||||
|
<div class="contentBox">
|
||||||
|
<img src="/images/PetitTetonLogo_v2.png"/>
|
||||||
|
<div class="form">{{> Template.dynamic template=content}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
64
imports/ui/layouts/Login.import.styl
vendored
Normal file
64
imports/ui/layouts/Login.import.styl
vendored
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
#login.content
|
||||||
|
//width: 100%
|
||||||
|
//height: 100%
|
||||||
|
//background-image: linear-gradient(to bottom, #315481, #918e82 100%)'
|
||||||
|
background: white
|
||||||
|
.contentBox
|
||||||
|
margin: 0 auto
|
||||||
|
max-width: 600px
|
||||||
|
background-color: #88d15a
|
||||||
|
-webkit-box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.5);
|
||||||
|
-moz-box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.5);
|
||||||
|
box-shadow: 10px 10px 5px 0px rgba(0,0,0,0.5);
|
||||||
|
margin-top: 5%
|
||||||
|
padding: 40px 10px
|
||||||
|
text-align: center
|
||||||
|
img
|
||||||
|
height: 120px
|
||||||
|
vertical-align: top
|
||||||
|
.form
|
||||||
|
display: inline-block
|
||||||
|
margin-left: 20px
|
||||||
|
input
|
||||||
|
padding: 8px
|
||||||
|
width: 300px
|
||||||
|
margin-bottom: 10px
|
||||||
|
label
|
||||||
|
display: none
|
||||||
|
fieldset
|
||||||
|
border: none
|
||||||
|
.at-btn
|
||||||
|
margin-bottom: 6px
|
||||||
|
text-align: center
|
||||||
|
width: 300px
|
||||||
|
background: #34d955;
|
||||||
|
background-image: -webkit-linear-gradient(top, #5d942b, #4b7d26)
|
||||||
|
background-image: -moz-linear-gradient(top, #5d942b, #4b7d26)
|
||||||
|
background-image: -ms-linear-gradient(top, #5d942b, #4b7d26)
|
||||||
|
background-image: -o-linear-gradient(top, #5d942b, #4b7d26)
|
||||||
|
background-image: linear-gradient(to bottom, #5d942b, #4b7d26)
|
||||||
|
font-family: "Arial Black", Arial
|
||||||
|
color: #ffffff
|
||||||
|
font-size: 14px
|
||||||
|
line-height: 16px
|
||||||
|
padding: 10px 20px 10px 20px
|
||||||
|
text-decoration: none
|
||||||
|
text-transform: uppercase
|
||||||
|
border: none
|
||||||
|
.at-btn:hover
|
||||||
|
background: #29b54f
|
||||||
|
background-image: -webkit-linear-gradient(top, #29b54f, #186b31)
|
||||||
|
background-image: -moz-linear-gradient(top, #29b54f, #186b31)
|
||||||
|
background-image: -ms-linear-gradient(top, #29b54f, #186b31)
|
||||||
|
background-image: -o-linear-gradient(top, #29b54f, #186b31)
|
||||||
|
background-image: linear-gradient(to bottom, #29b54f, #186b31)
|
||||||
|
text-decoration: none
|
||||||
|
cursor: pointer
|
||||||
|
.at-link
|
||||||
|
color: #1555b4
|
||||||
|
font: Arial
|
||||||
|
font-size: 12px
|
||||||
|
font-weight: 800
|
||||||
|
text-decoration: none
|
||||||
|
.at-link:hover
|
||||||
|
text-decoration: underline
|
||||||
1
imports/ui/layouts/Login.js
Normal file
1
imports/ui/layouts/Login.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
import './Login.html';
|
||||||
@@ -4,6 +4,9 @@
|
|||||||
// Takes a input form element and a hidden form element (to store the selected id in) along with an array of objects, to build a dropdown select control that allows the user to type part of the selection to filter the list.
|
// Takes a input form element and a hidden form element (to store the selected id in) along with an array of objects, to build a dropdown select control that allows the user to type part of the selection to filter the list.
|
||||||
// Modified for meteor.
|
// Modified for meteor.
|
||||||
//
|
//
|
||||||
|
// @param options: See Combo.DEFAULTS below.
|
||||||
|
//
|
||||||
|
//
|
||||||
(function($) {
|
(function($) {
|
||||||
let Combo = function($input, $hidden, options) {
|
let Combo = function($input, $hidden, options) {
|
||||||
let _this = this;
|
let _this = this;
|
||||||
@@ -37,7 +40,8 @@
|
|||||||
|
|
||||||
//this.$list.appendTo($input.parent());
|
//this.$list.appendTo($input.parent());
|
||||||
this.$list.appendTo(this.$listContainer);
|
this.$list.appendTo(this.$listContainer);
|
||||||
this.$listContainer.appendTo($input.parent());
|
//this.$listContainer.appendTo($input.parent());
|
||||||
|
this.$listContainer.prependTo(document.body); //Place the container at the top of the page with no height.
|
||||||
|
|
||||||
//Setup the list to highlight the item the user is hovering over, to select the item the user clicks, and to remove the hover styling when the list closes due to a selection being made.
|
//Setup the list to highlight the item the user is hovering over, to select the item the user clicks, and to remove the hover styling when the list closes due to a selection being made.
|
||||||
this.$list
|
this.$list
|
||||||
@@ -132,8 +136,8 @@
|
|||||||
let groupFunctions = _this.options.groupFunctions;
|
let groupFunctions = _this.options.groupFunctions;
|
||||||
let getClasses = _this.options.getClasses;
|
let getClasses = _this.options.getClasses;
|
||||||
|
|
||||||
let addOne = function(data, parent) { //role is optional.
|
let addOne = function(data, parent) {
|
||||||
let text = $.isFunction(_this.options.textAttr) ? _this.options.textAttr(data) : data[_this.options.textAttr];
|
let text = _this.options.textAttr ? ($.isFunction(_this.options.textAttr) ? _this.options.textAttr(data) : data[_this.options.textAttr]) : data;
|
||||||
let li = $("<li" + (parent ? " role='leaf'" : "") + (getClasses ? " class='" + getClasses(data) + "'" : "") + ">" + text + "</li>");
|
let li = $("<li" + (parent ? " role='leaf'" : "") + (getClasses ? " class='" + getClasses(data) + "'" : "") + ">" + text + "</li>");
|
||||||
|
|
||||||
li.appendTo(_this.$list);
|
li.appendTo(_this.$list);
|
||||||
@@ -191,8 +195,15 @@
|
|||||||
|
|
||||||
Tracker.autorun(function() {
|
Tracker.autorun(function() {
|
||||||
this.$list.empty();
|
this.$list.empty();
|
||||||
//Add the initial set of data.
|
if(options.cursor) {
|
||||||
add(options.cursor.fetch());
|
//Add the initial set of data.
|
||||||
|
add(options.cursor.fetch());
|
||||||
|
}
|
||||||
|
else if(options.set) {
|
||||||
|
for(let i = 0; i < options.set.length; i++) {
|
||||||
|
add(options.set[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
//Check the hidden input field for an ID, and setup the selection based in it if there is one.
|
//Check the hidden input field for an ID, and setup the selection based in it if there is one.
|
||||||
@@ -221,10 +232,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
Combo.DEFAULTS = {
|
Combo.DEFAULTS = {
|
||||||
cursor: undefined, //A meteor Cursor.
|
cursor: undefined, //A meteor Cursor used to populate the values displayed in the combo.
|
||||||
|
set: [], //An array of values displayed in the combo. This must be specified if cursor is not specified.
|
||||||
selection: undefined, //A meteor ReactiveVar whose value will be set to the current selection.
|
selection: undefined, //A meteor ReactiveVar whose value will be set to the current selection.
|
||||||
comparator: undefined, //A function that takes two collection objects and compares them for equality. If the combo shows users for example, this comparator would compare one user id to another. Required for the combo to set the selection if the view changes it externally relative to this combo.
|
comparator: function(a, b) {return a === b;}, //A function that takes two collection objects and compares them for equality. If the combo shows users for example, this comparator would compare one user id to another. Required for the combo to set the selection if the view changes it externally relative to this combo.
|
||||||
textAttr: 'text', //The attribute of the data elements to use for the name. This can also be a function that takes the data object and returns the text.
|
textAttr: undefined, //The attribute of the data elements to use for the name. This can also be a function that takes the data object and returns the text.
|
||||||
idAttr: 'id', //The attribute of the data elements to use for the ID. This can also be a function that takes the data obejct and returns the ID.
|
idAttr: 'id', //The attribute of the data elements to use for the ID. This can also be a function that takes the data obejct and returns the ID.
|
||||||
// groupFunctions: The object containing three functions: 'groupParent', 'parentText', 'children'.
|
// groupFunctions: The object containing three functions: 'groupParent', 'parentText', 'children'.
|
||||||
// groupParents(data) will take a data element and return the objects that best represents the parents of the children (for a multi layer tree, this would be the node just before the leaf nodes).
|
// groupParents(data) will take a data element and return the objects that best represents the parents of the children (for a multi layer tree, this would be the node just before the leaf nodes).
|
||||||
@@ -274,6 +286,15 @@
|
|||||||
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Removes all filtering. This is used to clear the filtering when first opening the combo when there is a value in the field. This is desirable because when we have an exact match, but are opening the combo, we most often want to select a new value.
|
||||||
|
Combo.prototype.clearFilter = function() {
|
||||||
|
console.log("CLearing Filter");
|
||||||
|
//Show all list elements.
|
||||||
|
this.$list.find('li').addClass('visible').show();
|
||||||
|
//Hide any node list elements.
|
||||||
|
this.$list.find('li[role="node"]').removeClass('visible').hide();
|
||||||
|
};
|
||||||
|
|
||||||
//Filters the list items by marking those that match the text in the text field as having the class 'visible'.
|
//Filters the list items by marking those that match the text in the text field as having the class 'visible'.
|
||||||
Combo.prototype.filter = function() {
|
Combo.prototype.filter = function() {
|
||||||
try {
|
try {
|
||||||
@@ -350,26 +371,36 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
Combo.prototype.show = function() {
|
Combo.prototype.show = function() {
|
||||||
//Position the list relative to the edit field.
|
// Make sure we don't repeatedly try to show the combo.
|
||||||
this.$list.css({position: 'absolute', top: 0, left: 0, width: this.$input.outerWidth()});
|
if(!this.isShowing) {
|
||||||
|
let position = this.$input.offset();
|
||||||
|
|
||||||
if(!this.$list.is(':visible') && this.$list.find('li.visible').length > 0) {
|
this.isShowing = true;
|
||||||
let fns = {default: 'show', fade: 'fadeIn', slide: 'slideDown'};
|
// Position the list relative to the field. Note that we place the combo at the top of the page (in the body tag) to avoid overflow not showing and to ensure the page scrolls if needed.
|
||||||
let fn = fns[this.options.effects];
|
this.$list.css({position: 'absolute', top: position.top + this.$input.outerHeight(), left: position.left, width: this.$input.outerWidth()});
|
||||||
|
this.clearFilter();
|
||||||
|
|
||||||
this.trigger('show');
|
if(!this.$list.is(':visible') && this.$list.find('li.visible').length > 0) {
|
||||||
this.$input.addClass('open');
|
let fns = {default: 'show', fade: 'fadeIn', slide: 'slideDown'};
|
||||||
this.$list[fn](this.options.duration, $.proxy(this.trigger, this, 'shown'));
|
let fn = fns[this.options.effects];
|
||||||
|
|
||||||
|
this.trigger('show');
|
||||||
|
this.$input.addClass('open');
|
||||||
|
this.$list[fn](this.options.duration, $.proxy(this.trigger, this, 'shown'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Combo.prototype.hide = function() {
|
Combo.prototype.hide = function() {
|
||||||
let fns = {default: 'hide', fade: 'fadeOut', slide: 'slideUp'};
|
if(this.isShowing) {
|
||||||
let fn = fns[this.options.effects];
|
let fns = {default: 'hide', fade: 'fadeOut', slide: 'slideUp'};
|
||||||
|
let fn = fns[this.options.effects];
|
||||||
|
|
||||||
this.trigger('hide');
|
this.isShowing = false;
|
||||||
this.$input.removeClass('open');
|
this.trigger('hide');
|
||||||
this.$list[fn](this.options.duration, $.proxy(this.trigger, this, 'hidden'));
|
this.$input.removeClass('open');
|
||||||
|
this.$list[fn](this.options.duration, $.proxy(this.trigger, this, 'hidden'));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// goDown: true/false - defaults to true - indicating whether the highlighting should go up or down if the requested item is a node. Nodes cannot be highlighted or selected.
|
// goDown: true/false - defaults to true - indicating whether the highlighting should go up or down if the requested item is a node. Nodes cannot be highlighted or selected.
|
||||||
|
|||||||
2036
package-lock.json
generated
Normal file
2036
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user