🔨 Add manager
This commit is contained in:
parent
85630ec233
commit
39a02da5f4
12
.idea/dataSources.xml
Normal file
12
.idea/dataSources.xml
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="DataSourceManagerImpl" format="xml" multifile-model="true">
|
||||||
|
<data-source source="LOCAL" name="db.sqlite" uuid="d3100bad-6ce1-4918-8a79-868dad8b16a7">
|
||||||
|
<driver-ref>sqlite.xerial</driver-ref>
|
||||||
|
<synchronize>true</synchronize>
|
||||||
|
<jdbc-driver>org.sqlite.JDBC</jdbc-driver>
|
||||||
|
<jdbc-url>jdbc:sqlite:$PROJECT_DIR$/db.sqlite</jdbc-url>
|
||||||
|
<working-dir>$ProjectFileDir$</working-dir>
|
||||||
|
</data-source>
|
||||||
|
</component>
|
||||||
|
</project>
|
11
app.js
11
app.js
@ -6,10 +6,13 @@ const bodyParser = require('body-parser')
|
|||||||
const logger = require('./config/winston');
|
const logger = require('./config/winston');
|
||||||
const sassMiddleware = require('node-sass-middleware');
|
const sassMiddleware = require('node-sass-middleware');
|
||||||
const expressWinston = require('express-winston');
|
const expressWinston = require('express-winston');
|
||||||
|
const flash = require('connect-flash');
|
||||||
const i18n = require('i18n');
|
const i18n = require('i18n');
|
||||||
|
const session = require('express-session');
|
||||||
|
|
||||||
const indexRouter = require('./routes/index');
|
const indexRouter = require('./routes/index');
|
||||||
const loginRouter = require('./routes/login');
|
const loginRouter = require('./routes/login');
|
||||||
|
const presetManagerRouter = require('./routes/preset-manager');
|
||||||
|
|
||||||
const passport = require('./config/passport');
|
const passport = require('./config/passport');
|
||||||
|
|
||||||
@ -43,7 +46,7 @@ app.use(expressWinston.logger({
|
|||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({ extended: false }));
|
app.use(express.urlencoded({ extended: false }));
|
||||||
app.use(require('express-session')({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
|
app.use(session({ secret: 'keyboard cat', resave: false, saveUninitialized: false }));
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
// app.use(sassMiddleware({
|
// app.use(sassMiddleware({
|
||||||
@ -61,14 +64,20 @@ app.use(i18n.init)
|
|||||||
|
|
||||||
app.use(passport.initialize());
|
app.use(passport.initialize());
|
||||||
app.use(passport.session());
|
app.use(passport.session());
|
||||||
|
app.use(flash());
|
||||||
|
|
||||||
|
|
||||||
app.use('/', indexRouter);
|
app.use('/', indexRouter);
|
||||||
app.use('/', loginRouter);
|
app.use('/', loginRouter);
|
||||||
|
app.use('/', presetManagerRouter);
|
||||||
|
|
||||||
// Boootstrap JS Files
|
// Boootstrap JS Files
|
||||||
app.use('/js/bootstrap.min.js', express.static(path.join(__dirname, '/node_modules/bootstrap/dist/js/bootstrap.min.js')))
|
app.use('/js/bootstrap.min.js', express.static(path.join(__dirname, '/node_modules/bootstrap/dist/js/bootstrap.min.js')))
|
||||||
|
|
||||||
|
// Fontawesome Files
|
||||||
|
app.use('/css/fa-all.min.css', express.static(path.join(__dirname, '/node_modules/@fortawesome/fontawesome-free/css/all.min.css')))
|
||||||
|
app.use('/webfonts/', express.static(path.join(__dirname, '/node_modules/@fortawesome/fontawesome-free/webfonts')))
|
||||||
|
|
||||||
// catch 404 and forward to error handler
|
// catch 404 and forward to error handler
|
||||||
app.use(function (req, res, next) {
|
app.use(function (req, res, next) {
|
||||||
next(createError(404));
|
next(createError(404));
|
||||||
|
2
bin/www
2
bin/www
@ -86,7 +86,7 @@ function onListening() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
console.log(`Checking database connection...`);
|
logger.info(`Checking database connection...`);
|
||||||
try {
|
try {
|
||||||
await sequelize.authenticate();
|
await sequelize.authenticate();
|
||||||
logger.info('Database connection OK!');
|
logger.info('Database connection OK!');
|
||||||
|
@ -15,5 +15,34 @@
|
|||||||
"Cutting Speed": "Cutting Speed",
|
"Cutting Speed": "Cutting Speed",
|
||||||
"Feed By Tooth": "Feed By Tooth",
|
"Feed By Tooth": "Feed By Tooth",
|
||||||
"Step Down factor": "Step Down factor",
|
"Step Down factor": "Step Down factor",
|
||||||
"Spindle Max Speed": "Spindle Max Speed"
|
"Spindle Max Speed": "Spindle Max Speed",
|
||||||
|
"Username": "Username",
|
||||||
|
"Password": "Password",
|
||||||
|
"Log In": "Log In",
|
||||||
|
"Login": "Login",
|
||||||
|
"Logout": "Logout",
|
||||||
|
"Manage Presets": "Manage Presets",
|
||||||
|
"Preset Manager": "Preset Manager",
|
||||||
|
"Name": "Name",
|
||||||
|
"Cut Speed": "Cut Speed",
|
||||||
|
"∅ > 1mm": "∅ > 1mm",
|
||||||
|
"∅ > 2mm": "∅ > 2mm",
|
||||||
|
"∅ > 3mm": "∅ > 3mm",
|
||||||
|
"∅ > 4mm": "∅ > 4mm",
|
||||||
|
"∅ > 5mm": "∅ > 5mm",
|
||||||
|
"∅ > 6mm": "∅ > 6mm",
|
||||||
|
"∅ > 8mm": "∅ > 8mm",
|
||||||
|
"Feed By Tooth (By tool diameter)": "Feed By Tooth (By tool diameter)",
|
||||||
|
"∅ ≥ 1mm": "∅ ≥ 1mm",
|
||||||
|
"∅ ≥ 2mm": "∅ ≥ 2mm",
|
||||||
|
"∅ ≥ 3mm": "∅ ≥ 3mm",
|
||||||
|
"∅ ≥ 4mm": "∅ ≥ 4mm",
|
||||||
|
"∅ ≥ 5mm": "∅ ≥ 5mm",
|
||||||
|
"∅ ≥ 6mm": "∅ ≥ 6mm",
|
||||||
|
"∅ ≥ 8mm": "∅ ≥ 8mm",
|
||||||
|
"K factor (By tool diameter)": "K factor (By tool diameter)",
|
||||||
|
"∅ < 2mm": "∅ < 2mm",
|
||||||
|
"Material Preset Editor": "Material Preset Editor",
|
||||||
|
"name": "name",
|
||||||
|
"Save": "Save"
|
||||||
}
|
}
|
10
middleware/is-admin.js
Normal file
10
middleware/is-admin.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
|
||||||
|
module.exports = function (req, res, next){
|
||||||
|
if(req.user !== null && req.user.is_admin){
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
res.redirect('/')
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
26
package-lock.json
generated
26
package-lock.json
generated
@ -14,6 +14,11 @@
|
|||||||
"kuler": "^2.0.0"
|
"kuler": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"@fortawesome/fontawesome-free": {
|
||||||
|
"version": "5.15.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.2.tgz",
|
||||||
|
"integrity": "sha512-7l/AX41m609L/EXI9EKH3Vs3v0iA8tKlIOGtw+kgcoanI7p+e4I4GYLqW3UXWiTnjSFymKSmTTPKYrivzbxxqA=="
|
||||||
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "14.14.22",
|
"version": "14.14.22",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.22.tgz",
|
||||||
@ -428,6 +433,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/connect-ensure-login/-/connect-ensure-login-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/connect-ensure-login/-/connect-ensure-login-0.1.1.tgz",
|
||||||
"integrity": "sha1-F03MUSQ7nqwj+NmCFa62aU4uihI="
|
"integrity": "sha1-F03MUSQ7nqwj+NmCFa62aU4uihI="
|
||||||
},
|
},
|
||||||
|
"connect-flash": {
|
||||||
|
"version": "0.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
|
||||||
|
"integrity": "sha1-2GMPJtlaf4UfmVax6MxnMvO2qjA="
|
||||||
|
},
|
||||||
"console-control-strings": {
|
"console-control-strings": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||||
@ -701,6 +711,22 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"express-validator": {
|
||||||
|
"version": "6.9.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/express-validator/-/express-validator-6.9.2.tgz",
|
||||||
|
"integrity": "sha512-Yqlsw2/uBobtBVkP+gnds8OMmVAEb3uTI4uXC93l0Ym5JGHgr8Vd4ws7oSo7GGYpWn5YCq4UePMEppKchURXrw==",
|
||||||
|
"requires": {
|
||||||
|
"lodash": "^4.17.20",
|
||||||
|
"validator": "^13.5.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"validator": {
|
||||||
|
"version": "13.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/validator/-/validator-13.5.2.tgz",
|
||||||
|
"integrity": "sha512-mD45p0rvHVBlY2Zuy3F3ESIe1h5X58GPfAtslBjY7EtTqGquZTj+VX/J4RnHWN8FKq0C9WRVt1oWAcytWRuYLQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"express-winston": {
|
"express-winston": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/express-winston/-/express-winston-4.0.5.tgz",
|
||||||
|
@ -6,15 +6,18 @@
|
|||||||
"start": "node ./bin/www"
|
"start": "node ./bin/www"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@fortawesome/fontawesome-free": "^5.15.2",
|
||||||
"bcrypt": "^5.0.0",
|
"bcrypt": "^5.0.0",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"bootstrap": "^5.0.0-beta1",
|
"bootstrap": "^5.0.0-beta1",
|
||||||
"connect-ensure-login": "^0.1.1",
|
"connect-ensure-login": "^0.1.1",
|
||||||
|
"connect-flash": "^0.1.1",
|
||||||
"cookie-parser": "~1.4.4",
|
"cookie-parser": "~1.4.4",
|
||||||
"debug": "~2.6.9",
|
"debug": "~2.6.9",
|
||||||
"ejs": "~2.6.1",
|
"ejs": "~2.6.1",
|
||||||
"express": "~4.16.1",
|
"express": "~4.16.1",
|
||||||
"express-session": "^1.17.1",
|
"express-session": "^1.17.1",
|
||||||
|
"express-validator": "^6.9.2",
|
||||||
"express-winston": "^4.0.5",
|
"express-winston": "^4.0.5",
|
||||||
"http-errors": "~1.6.3",
|
"http-errors": "~1.6.3",
|
||||||
"i18n": "^0.13.2",
|
"i18n": "^0.13.2",
|
||||||
|
4
public/css/bootstrap_imports.scss
vendored
4
public/css/bootstrap_imports.scss
vendored
@ -5,13 +5,13 @@
|
|||||||
@import "../../node_modules/bootstrap/scss/images";
|
@import "../../node_modules/bootstrap/scss/images";
|
||||||
@import "../../node_modules/bootstrap/scss/containers";
|
@import "../../node_modules/bootstrap/scss/containers";
|
||||||
@import "../../node_modules/bootstrap/scss/grid";
|
@import "../../node_modules/bootstrap/scss/grid";
|
||||||
//@import "tables";
|
@import "../../node_modules/bootstrap/scss/tables";
|
||||||
@import "../../node_modules/bootstrap/scss/forms";
|
@import "../../node_modules/bootstrap/scss/forms";
|
||||||
@import "../../node_modules/bootstrap/scss/buttons";
|
@import "../../node_modules/bootstrap/scss/buttons";
|
||||||
@import "../../node_modules/bootstrap/scss/transitions";
|
@import "../../node_modules/bootstrap/scss/transitions";
|
||||||
@import "../../node_modules/bootstrap/scss/dropdown";
|
@import "../../node_modules/bootstrap/scss/dropdown";
|
||||||
//@import "button-group";
|
//@import "button-group";
|
||||||
//@import "nav";
|
@import "../../node_modules/bootstrap/scss/nav";
|
||||||
@import "../../node_modules/bootstrap/scss/navbar";
|
@import "../../node_modules/bootstrap/scss/navbar";
|
||||||
@import "../../node_modules/bootstrap/scss/card";
|
@import "../../node_modules/bootstrap/scss/card";
|
||||||
//@import "accordion";
|
//@import "accordion";
|
||||||
|
@ -1916,6 +1916,201 @@ progress {
|
|||||||
--bs-gutter-y: 3rem;
|
--bs-gutter-y: 3rem;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.table {
|
||||||
|
--bs-table-bg: transparent;
|
||||||
|
--bs-table-striped-color: #212529;
|
||||||
|
--bs-table-striped-bg: rgba(0, 0, 0, 0.05);
|
||||||
|
--bs-table-active-color: #212529;
|
||||||
|
--bs-table-active-bg: rgba(0, 0, 0, 0.1);
|
||||||
|
--bs-table-hover-color: #212529;
|
||||||
|
--bs-table-hover-bg: rgba(0, 0, 0, 0.075);
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
color: #212529;
|
||||||
|
vertical-align: top;
|
||||||
|
border-color: #dee2e6;
|
||||||
|
}
|
||||||
|
.table > :not(caption) > * > * {
|
||||||
|
padding: 0.5rem 0.5rem;
|
||||||
|
background-color: var(--bs-table-bg);
|
||||||
|
background-image: linear-gradient(var(--bs-table-accent-bg), var(--bs-table-accent-bg));
|
||||||
|
border-bottom-width: 1px;
|
||||||
|
}
|
||||||
|
.table > tbody {
|
||||||
|
vertical-align: inherit;
|
||||||
|
}
|
||||||
|
.table > thead {
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
.table > :not(:last-child) > :last-child > * {
|
||||||
|
border-bottom-color: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.caption-top {
|
||||||
|
caption-side: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-sm > :not(caption) > * > * {
|
||||||
|
padding: 0.25rem 0.25rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-bordered > :not(caption) > * {
|
||||||
|
border-width: 1px 0;
|
||||||
|
}
|
||||||
|
.table-bordered > :not(caption) > * > * {
|
||||||
|
border-width: 0 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-borderless > :not(caption) > * > * {
|
||||||
|
border-bottom-width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-striped > tbody > tr:nth-of-type(odd) {
|
||||||
|
--bs-table-accent-bg: var(--bs-table-striped-bg);
|
||||||
|
color: var(--bs-table-striped-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-active {
|
||||||
|
--bs-table-accent-bg: var(--bs-table-active-bg);
|
||||||
|
color: var(--bs-table-active-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-hover > tbody > tr:hover {
|
||||||
|
--bs-table-accent-bg: var(--bs-table-hover-bg);
|
||||||
|
color: var(--bs-table-hover-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-primary {
|
||||||
|
--bs-table-bg: #cfe2ff;
|
||||||
|
--bs-table-striped-bg: #c5d7f2;
|
||||||
|
--bs-table-striped-color: #000;
|
||||||
|
--bs-table-active-bg: #bacbe6;
|
||||||
|
--bs-table-active-color: #000;
|
||||||
|
--bs-table-hover-bg: #bfd1ec;
|
||||||
|
--bs-table-hover-color: #000;
|
||||||
|
color: #000;
|
||||||
|
border-color: #bacbe6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-secondary {
|
||||||
|
--bs-table-bg: #d6d8d9;
|
||||||
|
--bs-table-striped-bg: #cbcdce;
|
||||||
|
--bs-table-striped-color: #000;
|
||||||
|
--bs-table-active-bg: #c1c2c3;
|
||||||
|
--bs-table-active-color: #000;
|
||||||
|
--bs-table-hover-bg: #c6c8c9;
|
||||||
|
--bs-table-hover-color: #000;
|
||||||
|
color: #000;
|
||||||
|
border-color: #c1c2c3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-success {
|
||||||
|
--bs-table-bg: #d1e7dd;
|
||||||
|
--bs-table-striped-bg: #c7dbd2;
|
||||||
|
--bs-table-striped-color: #000;
|
||||||
|
--bs-table-active-bg: #bcd0c7;
|
||||||
|
--bs-table-active-color: #000;
|
||||||
|
--bs-table-hover-bg: #c1d6cc;
|
||||||
|
--bs-table-hover-color: #000;
|
||||||
|
color: #000;
|
||||||
|
border-color: #bcd0c7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-info {
|
||||||
|
--bs-table-bg: #cff4fc;
|
||||||
|
--bs-table-striped-bg: #c5e8ef;
|
||||||
|
--bs-table-striped-color: #000;
|
||||||
|
--bs-table-active-bg: #badce3;
|
||||||
|
--bs-table-active-color: #000;
|
||||||
|
--bs-table-hover-bg: #bfe2e9;
|
||||||
|
--bs-table-hover-color: #000;
|
||||||
|
color: #000;
|
||||||
|
border-color: #badce3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-warning {
|
||||||
|
--bs-table-bg: #fff3cd;
|
||||||
|
--bs-table-striped-bg: #f2e7c3;
|
||||||
|
--bs-table-striped-color: #000;
|
||||||
|
--bs-table-active-bg: #e6dbb9;
|
||||||
|
--bs-table-active-color: #000;
|
||||||
|
--bs-table-hover-bg: #ece1be;
|
||||||
|
--bs-table-hover-color: #000;
|
||||||
|
color: #000;
|
||||||
|
border-color: #e6dbb9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-danger {
|
||||||
|
--bs-table-bg: #f8d7da;
|
||||||
|
--bs-table-striped-bg: #eccccf;
|
||||||
|
--bs-table-striped-color: #000;
|
||||||
|
--bs-table-active-bg: #dfc2c4;
|
||||||
|
--bs-table-active-color: #000;
|
||||||
|
--bs-table-hover-bg: #e5c7ca;
|
||||||
|
--bs-table-hover-color: #000;
|
||||||
|
color: #000;
|
||||||
|
border-color: #dfc2c4;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-light {
|
||||||
|
--bs-table-bg: #f8f9fa;
|
||||||
|
--bs-table-striped-bg: #ecedee;
|
||||||
|
--bs-table-striped-color: #000;
|
||||||
|
--bs-table-active-bg: #dfe0e1;
|
||||||
|
--bs-table-active-color: #000;
|
||||||
|
--bs-table-hover-bg: #e5e6e7;
|
||||||
|
--bs-table-hover-color: #000;
|
||||||
|
color: #000;
|
||||||
|
border-color: #dfe0e1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-dark {
|
||||||
|
--bs-table-bg: #292929;
|
||||||
|
--bs-table-striped-bg: #343434;
|
||||||
|
--bs-table-striped-color: #fff;
|
||||||
|
--bs-table-active-bg: #3e3e3e;
|
||||||
|
--bs-table-active-color: #fff;
|
||||||
|
--bs-table-hover-bg: #393939;
|
||||||
|
--bs-table-hover-color: #fff;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #3e3e3e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-responsive {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 575.98px) {
|
||||||
|
.table-responsive-sm {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 767.98px) {
|
||||||
|
.table-responsive-md {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.table-responsive-lg {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 1199.98px) {
|
||||||
|
.table-responsive-xl {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media (max-width: 1399.98px) {
|
||||||
|
.table-responsive-xxl {
|
||||||
|
overflow-x: auto;
|
||||||
|
-webkit-overflow-scrolling: touch;
|
||||||
|
}
|
||||||
|
}
|
||||||
.form-label {
|
.form-label {
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
@ -3513,6 +3708,93 @@ textarea.form-control-lg {
|
|||||||
color: #adb5bd;
|
color: #adb5bd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.nav {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding-left: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
display: block;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
color: white;
|
||||||
|
text-decoration: none;
|
||||||
|
transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out;
|
||||||
|
}
|
||||||
|
@media (prefers-reduced-motion: reduce) {
|
||||||
|
.nav-link {
|
||||||
|
transition: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nav-link:hover, .nav-link:focus {
|
||||||
|
color: #b58e51;
|
||||||
|
}
|
||||||
|
.nav-link.disabled {
|
||||||
|
color: #6c757d;
|
||||||
|
pointer-events: none;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-tabs {
|
||||||
|
border-bottom: 1px solid #b58e51;
|
||||||
|
}
|
||||||
|
.nav-tabs .nav-link {
|
||||||
|
margin-bottom: -1px;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-top-left-radius: 0.25rem;
|
||||||
|
border-top-right-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
.nav-tabs .nav-link:hover, .nav-tabs .nav-link:focus {
|
||||||
|
border-color: #343a40 #343a40 #b58e51;
|
||||||
|
}
|
||||||
|
.nav-tabs .nav-link.disabled {
|
||||||
|
color: #6c757d;
|
||||||
|
background-color: transparent;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
.nav-tabs .nav-link.active,
|
||||||
|
.nav-tabs .nav-item.show .nav-link {
|
||||||
|
color: #b58e51;
|
||||||
|
background-color: #222222;
|
||||||
|
border-color: #b58e51 #b58e51 #222222;
|
||||||
|
}
|
||||||
|
.nav-tabs .dropdown-menu {
|
||||||
|
margin-top: -1px;
|
||||||
|
border-top-left-radius: 0;
|
||||||
|
border-top-right-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-pills .nav-link {
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
}
|
||||||
|
.nav-pills .nav-link.active,
|
||||||
|
.nav-pills .show > .nav-link {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #b58e51;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-fill > .nav-link,
|
||||||
|
.nav-fill .nav-item {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-justified > .nav-link,
|
||||||
|
.nav-justified .nav-item {
|
||||||
|
flex-basis: 0;
|
||||||
|
flex-grow: 1;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-content > .tab-pane {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.tab-content > .active {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.navbar {
|
.navbar {
|
||||||
position: relative;
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
File diff suppressed because one or more lines are too long
@ -10,7 +10,6 @@ $custom-colors:(
|
|||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$enable-shadows: true;
|
$enable-shadows: true;
|
||||||
$btn-box-shadow: none;
|
$btn-box-shadow: none;
|
||||||
|
|
||||||
@ -39,6 +38,16 @@ $alert-bg-scale: 0%;
|
|||||||
$alert-border-scale: -10%;
|
$alert-border-scale: -10%;
|
||||||
$alert-color-scale: -100%;
|
$alert-color-scale: -100%;
|
||||||
|
|
||||||
|
$nav-tabs-border-color: $accent;
|
||||||
|
$nav-tabs-link-active-border-color: $accent $accent $body-bg;
|
||||||
|
$nav-tabs-link-active-color: $accent;
|
||||||
|
$nav-tabs-link-hover-border-color: $secondary $secondary $nav-tabs-border-color;
|
||||||
|
$nav-link-color: white;
|
||||||
|
$nav-link-hover-color: $accent;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Configuration
|
// Configuration
|
||||||
@import "../../node_modules/bootstrap/scss/functions";
|
@import "../../node_modules/bootstrap/scss/functions";
|
||||||
@import "../../node_modules/bootstrap/scss/variables";
|
@import "../../node_modules/bootstrap/scss/variables";
|
||||||
|
118
public/js/index.js
Normal file
118
public/js/index.js
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
preset_cut = JSON.parse(preset_cut);
|
||||||
|
preset_step_down_factor = JSON.parse(preset_step_down_factor);
|
||||||
|
|
||||||
|
let preset_cut_elem = document.querySelector('#preset_cut');
|
||||||
|
let preset_step_down_factor_elem = document.querySelector('#preset_step_down_factor');
|
||||||
|
let tooth_nbr_elem = document.querySelector('#tooth_nbr');
|
||||||
|
let tool_diameter_elem = document.querySelector('#tool_diameter');
|
||||||
|
let max_rpm_elem = document.querySelector('#max_rpm')
|
||||||
|
|
||||||
|
let rpm_elem = document.querySelector('#rpm');
|
||||||
|
let feed_rate_elem = document.querySelector('#feed_rate');
|
||||||
|
let feed_rate_sec_elem = document.querySelector('#feed_rate_sec');
|
||||||
|
let step_down_elem = document.querySelector('#step_down');
|
||||||
|
|
||||||
|
let cutting_speed_elem = document.querySelector('#cutting_speed');
|
||||||
|
let feed_tooth_elem = document.querySelector('#feed_tooth');
|
||||||
|
let step_down_factor_elem = document.querySelector('#step_down_factor');
|
||||||
|
|
||||||
|
document.addEventListener("DOMContentLoaded", function (event) {
|
||||||
|
load();
|
||||||
|
onChange();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
function onChange() {
|
||||||
|
if (preset_cut_elem.value === "" || preset_step_down_factor_elem.value === "" || tool_diameter_elem.value === "0" || tooth_nbr_elem.value === "0" || max_rpm_elem.value === "0") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
save();
|
||||||
|
let new_preset_cut = getPresetValue(preset_cut, parseInt(preset_cut_elem.value, 10));
|
||||||
|
let new_preset_steep_down = getPresetValue(preset_step_down_factor, parseInt(preset_step_down_factor_elem.value, 10))
|
||||||
|
let new_tool_diameter = parseFloat(tool_diameter_elem.value);
|
||||||
|
let new_tooth_nbr = parseInt(tooth_nbr_elem.value);
|
||||||
|
let max_rpm = parseInt(max_rpm_elem.value);
|
||||||
|
|
||||||
|
let rpm = (1000 * new_preset_cut.cut_speed) / (3.14 * new_tool_diameter);
|
||||||
|
if (rpm > max_rpm)
|
||||||
|
rpm = max_rpm;
|
||||||
|
let feed_rate = rpm * getFeedByTooth(new_tool_diameter, new_preset_cut) * new_tooth_nbr;
|
||||||
|
let feed_rate_sec = feed_rate / 60;
|
||||||
|
let step_down = new_tool_diameter * getStepDownFactor(new_tool_diameter, new_preset_steep_down);
|
||||||
|
|
||||||
|
rpm = Math.round(rpm);
|
||||||
|
feed_rate = Math.round(feed_rate);
|
||||||
|
feed_rate_sec = feed_rate_sec.toFixed(2)
|
||||||
|
step_down = step_down.toFixed(2);
|
||||||
|
|
||||||
|
rpm_elem.value = rpm;
|
||||||
|
feed_rate_elem.value = feed_rate;
|
||||||
|
feed_rate_sec_elem.value = feed_rate_sec;
|
||||||
|
step_down_elem.value = step_down;
|
||||||
|
|
||||||
|
cutting_speed_elem.value = new_preset_cut.cut_speed;
|
||||||
|
feed_tooth_elem.value = getFeedByTooth(new_tool_diameter, new_preset_cut);
|
||||||
|
step_down_factor_elem.value = getStepDownFactor(new_tool_diameter, new_preset_steep_down);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getPresetValue(list, id) {
|
||||||
|
for (let elem of list) {
|
||||||
|
if (elem.id === id) {
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
function getFeedByTooth(tool_diam, preset) {
|
||||||
|
if (tool_diam >= 8)
|
||||||
|
return preset.feed_by_tooth_more_8;
|
||||||
|
if (tool_diam >= 6)
|
||||||
|
return preset.feed_by_tooth_more_6;
|
||||||
|
if (tool_diam >= 5)
|
||||||
|
return preset.feed_by_tooth_more_5;
|
||||||
|
if (tool_diam >= 4)
|
||||||
|
return preset.feed_by_tooth_more_4;
|
||||||
|
if (tool_diam >= 3)
|
||||||
|
return preset.feed_by_tooth_more_3;
|
||||||
|
if (tool_diam >= 2)
|
||||||
|
return preset.feed_by_tooth_more_2;
|
||||||
|
return preset.feed_by_tooth_more_1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getStepDownFactor(tool_diam, preset) {
|
||||||
|
if (tool_diam >= 6)
|
||||||
|
return preset.k_more_6;
|
||||||
|
if (tool_diam >= 5)
|
||||||
|
return preset.k_more_5;
|
||||||
|
if (tool_diam >= 4)
|
||||||
|
return preset.k_more_4;
|
||||||
|
if (tool_diam >= 3)
|
||||||
|
return preset.k_more_3;
|
||||||
|
if (tool_diam >= 2)
|
||||||
|
return preset.k_more_2;
|
||||||
|
return preset.k_less_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
function save(){
|
||||||
|
let values = {
|
||||||
|
preset_cut: preset_cut_elem.value,
|
||||||
|
preset_step_down_factor: preset_step_down_factor_elem.value,
|
||||||
|
tool_diameter: tool_diameter_elem.value,
|
||||||
|
tooth_nbr: tooth_nbr_elem.value,
|
||||||
|
max_rpm: max_rpm_elem.value
|
||||||
|
}
|
||||||
|
localStorage.setItem('previous_data', JSON.stringify(values));
|
||||||
|
}
|
||||||
|
|
||||||
|
function load(){
|
||||||
|
let previous_data = localStorage.getItem('previous_data')
|
||||||
|
if(previous_data === null)
|
||||||
|
return;
|
||||||
|
previous_data = JSON.parse(previous_data);
|
||||||
|
preset_cut_elem.value = previous_data.preset_cut;
|
||||||
|
preset_step_down_factor_elem.value = previous_data.preset_step_down_factor;
|
||||||
|
tool_diameter_elem.value = previous_data.tool_diameter;
|
||||||
|
tooth_nbr_elem.value = previous_data.tooth_nbr;
|
||||||
|
max_rpm_elem.value = previous_data.max_rpm;
|
||||||
|
}
|
@ -6,10 +6,9 @@ const sequelize = require('../sequelize')
|
|||||||
router.get('/', function (req, res, next) {
|
router.get('/', function (req, res, next) {
|
||||||
sequelize.models.preset_cut.findAll({ order: ['name'] }).then((preset_cut) => {
|
sequelize.models.preset_cut.findAll({ order: ['name'] }).then((preset_cut) => {
|
||||||
sequelize.models.preset_step_down_factor.findAll({ order: ['name'] }).then((step_down_factor) => {
|
sequelize.models.preset_step_down_factor.findAll({ order: ['name'] }).then((step_down_factor) => {
|
||||||
res.render('index', { preset_cut: preset_cut, step_down_factor: step_down_factor });
|
res.render('index', { preset_cut: preset_cut, step_down_factor: step_down_factor, user: req.user });
|
||||||
})
|
});
|
||||||
})
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
@ -1,13 +1,20 @@
|
|||||||
var express = require('express');
|
const express = require('express');
|
||||||
var router = express.Router();
|
const router = express.Router();
|
||||||
const passport = require('../config/passport')
|
const passport = require('../config/passport')
|
||||||
|
|
||||||
/* GET home page. */
|
/* GET home page. */
|
||||||
router.get('/login', function (req, res, next) {
|
router.get('/login', function (req, res, next) {
|
||||||
res.render('login');
|
res.render('login', {user: req.user});
|
||||||
});
|
});
|
||||||
router.post('/login', passport.authenticate('local', { failureRedirect: '/login' }),
|
router.post('/login', passport.authenticate('local', { failureRedirect: '/login' }),
|
||||||
function (req, res) {
|
function (req, res) {
|
||||||
|
if (req.session.returnTo !== undefined && req.session.returnTo !== null){
|
||||||
|
let url = req.session.returnTo;
|
||||||
|
delete req.session.returnTo;
|
||||||
|
res.redirect(url);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
res.redirect('/');
|
res.redirect('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
79
routes/preset-manager.js
Normal file
79
routes/preset-manager.js
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const sequelize = require('../sequelize');
|
||||||
|
const { Op } = require("sequelize");
|
||||||
|
const ensureLoggedIn = require('connect-ensure-login').ensureLoggedIn;
|
||||||
|
const isAdmin = require('../middleware/is-admin');
|
||||||
|
const logger = require('../config/winston');
|
||||||
|
|
||||||
|
const preset_cut_tools = require('../tools/preset_cut_tools')
|
||||||
|
|
||||||
|
const { body, validationResult, matchedData } = require('express-validator');
|
||||||
|
|
||||||
|
/* GET home page. */
|
||||||
|
router.get('/preset-manager', ensureLoggedIn(), isAdmin, function (req, res, next) {
|
||||||
|
sequelize.models.preset_cut.findAll({ order: ['name'] }).then((preset_cut) => {
|
||||||
|
sequelize.models.preset_step_down_factor.findAll({ order: ['name'] }).then((step_down_factor) => {
|
||||||
|
res.render('preset-manager', {
|
||||||
|
preset_cut: preset_cut,
|
||||||
|
step_down_factor: step_down_factor,
|
||||||
|
user: req.user
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/preset-manager/preset-cut/:id',
|
||||||
|
ensureLoggedIn(),
|
||||||
|
isAdmin,
|
||||||
|
function (req, res, next) {
|
||||||
|
sequelize.models.preset_cut.findOne({ where: { id: req.params.id } }).then((preset) => {
|
||||||
|
if (preset == null) {
|
||||||
|
res.status(404);
|
||||||
|
} else {
|
||||||
|
res.render('preset-cut-editor', { preset: preset, user: req.user });
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
res.status(500);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/preset-manager/preset-cut/:id',
|
||||||
|
ensureLoggedIn(),
|
||||||
|
isAdmin,
|
||||||
|
body('name').isString(),
|
||||||
|
body('feed_by_tooth_more_1').isFloat({ min: 0 }).toFloat(),
|
||||||
|
body('feed_by_tooth_more_2').isFloat({ min: 0 }).toFloat(),
|
||||||
|
body('feed_by_tooth_more_3').isFloat({ min: 0 }).toFloat(),
|
||||||
|
body('feed_by_tooth_more_4').isFloat({ min: 0 }).toFloat(),
|
||||||
|
body('feed_by_tooth_more_5').isFloat({ min: 0 }).toFloat(),
|
||||||
|
body('feed_by_tooth_more_6').isFloat({ min: 0 }).toFloat(),
|
||||||
|
body('feed_by_tooth_more_8').isFloat({ min: 0 }).toFloat(),
|
||||||
|
body('cutting_speed').isInt({ min: 0 }).toInt(),
|
||||||
|
function (req, res, next) {
|
||||||
|
|
||||||
|
const errors = validationResult(req);
|
||||||
|
const data = matchedData(req);
|
||||||
|
if (!errors.isEmpty()) {
|
||||||
|
// TODO Handle error
|
||||||
|
req.flash('error', 'Error');
|
||||||
|
res.redirect(`/preset-manager/preset-cut/${req.params.id}`);
|
||||||
|
} else {
|
||||||
|
preset_cut_tools.edit(req.params.id, data).then(() => {
|
||||||
|
res.redirect('/preset-manager');
|
||||||
|
}).catch((reason => {
|
||||||
|
if (reason === "NOT_FOUND") {
|
||||||
|
res.status(404);
|
||||||
|
} else {
|
||||||
|
logger.error(`Fail to save: Code ${reason}`);
|
||||||
|
res.status(500);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
@ -104,14 +104,14 @@ async function reset() {
|
|||||||
k_more_6: 0.35
|
k_more_6: 0.35
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
await sequelize.models.user.create({username: "admin" , password: bcrypt.hashSync("love_cnc", 10)})
|
await sequelize.models.user.create({username: "admin", password: bcrypt.hashSync("love_cnc", 10), is_admin: true} )
|
||||||
await sequelize.models.need_init.create({name: 'init'})
|
await sequelize.models.need_init.create({name: 'init'})
|
||||||
|
|
||||||
logger.info('...Done')
|
logger.info('...Done')
|
||||||
}
|
}
|
||||||
|
|
||||||
async function check_database() {
|
async function check_database() {
|
||||||
await sequelize.sync();
|
await sequelize.sync({alter: true});
|
||||||
let val = await sequelize.models.need_init.findAll({where: {name: 'init'}});
|
let val = await sequelize.models.need_init.findAll({where: {name: 'init'}});
|
||||||
if(val.length === 0){
|
if(val.length === 0){
|
||||||
logger.info('Need init !');
|
logger.info('Need init !');
|
||||||
|
@ -16,6 +16,11 @@ module.exports = (sequelize) => {
|
|||||||
password: {
|
password: {
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
type: DataTypes.STRING,
|
type: DataTypes.STRING,
|
||||||
|
},
|
||||||
|
is_admin: {
|
||||||
|
allowNull: false,
|
||||||
|
defaultValue: false,
|
||||||
|
type: DataTypes.BOOLEAN
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
31
tools/preset_cut_tools.js
Normal file
31
tools/preset_cut_tools.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
const sequelize = require('../sequelize');
|
||||||
|
|
||||||
|
let edit = function (id, form_data){
|
||||||
|
return new Promise(((resolve, reject) => {
|
||||||
|
// TODO Add debug logs
|
||||||
|
sequelize.models.preset_cut.findOne({ where: { id: id } }).then((preset) => {
|
||||||
|
if (preset == null) {
|
||||||
|
reject('NOT_FOUND');
|
||||||
|
} else {
|
||||||
|
preset.name = form_data.name;
|
||||||
|
preset.cut_speed = form_data.cutting_speed;
|
||||||
|
preset.feed_by_tooth_more_1 = form_data.feed_by_tooth_more_1;
|
||||||
|
preset.feed_by_tooth_more_2 = form_data.feed_by_tooth_more_2;
|
||||||
|
preset.feed_by_tooth_more_3 = form_data.feed_by_tooth_more_3;
|
||||||
|
preset.feed_by_tooth_more_4 = form_data.feed_by_tooth_more_4;
|
||||||
|
preset.feed_by_tooth_more_5 = form_data.feed_by_tooth_more_5;
|
||||||
|
preset.feed_by_tooth_more_6 = form_data.feed_by_tooth_more_6;
|
||||||
|
preset.feed_by_tooth_more_8 = form_data.feed_by_tooth_more_8;
|
||||||
|
preset.save().then(() => {
|
||||||
|
resolve();
|
||||||
|
}).catch((err) => {
|
||||||
|
reject('SAVE_FAIL')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}).catch((err) => {
|
||||||
|
reject('DB_ERROR');
|
||||||
|
});
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.edit = edit;
|
28
views/includes/base/navbar.ejs
Normal file
28
views/includes/base/navbar.ejs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<nav class="navbar navbar-expand-md navbar-dark">
|
||||||
|
<div class="container">
|
||||||
|
<a href="/" class="navbar-brand">
|
||||||
|
CNC Speed Calculator
|
||||||
|
</a>
|
||||||
|
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
<span class="navbar-toggler-icon"></span>
|
||||||
|
</button>
|
||||||
|
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||||
|
<ul class="navbar-nav me-auto mb-2 mb-md-0">
|
||||||
|
<% if(user && user.is_admin){ %>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/preset-manager"><%= __('Manage Presets') %></a>
|
||||||
|
</li>
|
||||||
|
<% } %>
|
||||||
|
</ul>
|
||||||
|
<div class="">
|
||||||
|
<% if(user){ %>
|
||||||
|
<span class="navbar-text"><%= user.username %></span>
|
||||||
|
<a class="ms-2 btn btn-sm btn-secondary" href="/logout">Logout</a>
|
||||||
|
<% } else { %>
|
||||||
|
<a class="ml-2 btn btn-sm btn-secondary" href="/login">Login</a>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</nav>
|
4
views/includes/base/styles.ejs
Normal file
4
views/includes/base/styles.ejs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<link rel='stylesheet' href='/css/style.css'/>
|
||||||
|
<link rel="stylesheet" href="/css/custom_bootstrap.css">
|
||||||
|
<link rel="stylesheet" href="/css/fa-all.min.css">
|
38
views/includes/preset-manager/material-table.ejs
Normal file
38
views/includes/preset-manager/material-table.ejs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
<table class="table table-bordered table-dark table-striped table-hover text-center align-middle mt-3 mb-0">
|
||||||
|
<thead class="">
|
||||||
|
<tr>
|
||||||
|
<th colspan="2"></th>
|
||||||
|
<th colspan="7"><%= __('Feed By Tooth (By tool diameter)') %></th>
|
||||||
|
<th rowspan="2"></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="col"><%= __('Name') %></th>
|
||||||
|
<th scope="col"><%= __('Cut Speed') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 1mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 2mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 3mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 4mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 5mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 6mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 8mm') %></th>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% preset_cut.forEach(function (preset){ %>
|
||||||
|
<tr>
|
||||||
|
<td><%= preset.name %></td>
|
||||||
|
<td><%= preset.cut_speed %></td>
|
||||||
|
<td><%= preset.feed_by_tooth_more_1 %></td>
|
||||||
|
<td><%= preset.feed_by_tooth_more_2 %></td>
|
||||||
|
<td><%= preset.feed_by_tooth_more_3 %></td>
|
||||||
|
<td><%= preset.feed_by_tooth_more_4 %></td>
|
||||||
|
<td><%= preset.feed_by_tooth_more_5 %></td>
|
||||||
|
<td><%= preset.feed_by_tooth_more_6 %></td>
|
||||||
|
<td><%= preset.feed_by_tooth_more_8 %></td>
|
||||||
|
<td><a href="/preset-manager/preset-cut/<%= preset.id %>" class="btn btn-sm btn-success"><i class="fas fa-edit"></i></a></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<% }) %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
33
views/includes/preset-manager/step-down-factor-table.ejs
Normal file
33
views/includes/preset-manager/step-down-factor-table.ejs
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
<table class="table table-bordered table-dark table-striped table-hover text-center align-middle mt-2 mb-0">
|
||||||
|
<thead class="">
|
||||||
|
<tr>
|
||||||
|
<th rowspan="2"><%= __('Name') %></th>
|
||||||
|
<th colspan="6"><%= __('K factor (By tool diameter)') %></th>
|
||||||
|
<th rowspan="2"></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="col"><%= __('∅ < 2mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 2mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 3mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 4mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 5mm') %></th>
|
||||||
|
<th scope="col"><%= __('∅ ≥ 6mm') %></th>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<% step_down_factor.forEach(function (preset){ %>
|
||||||
|
<tr>
|
||||||
|
<td><%= preset.name %></td>
|
||||||
|
<td><%= preset.k_less_2 %></td>
|
||||||
|
<td><%= preset.k_more_2 %></td>
|
||||||
|
<td><%= preset.k_more_3 %></td>
|
||||||
|
<td><%= preset.k_more_4 %></td>
|
||||||
|
<td><%= preset.k_more_5 %></td>
|
||||||
|
<td><%= preset.k_more_6 %></td>
|
||||||
|
<td><a href="/preset-manager/step-down/<%= preset.id %>" class="btn btn-sm btn-success"><i class="fas fa-edit"></i></a></td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<% }) %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
138
views/index.ejs
138
views/index.ejs
@ -2,30 +2,22 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>CNC Speed Calculator</title>
|
<title>CNC Speed Calculator</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<%- include('includes/base/styles') %>
|
||||||
<link rel='stylesheet' href='/css/style.css'/>
|
|
||||||
<link rel="stylesheet" href="/css/custom_bootstrap.css">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-dark navbar-expand">
|
<%- include('includes/base/navbar')%>
|
||||||
<div class="container">
|
|
||||||
<a href="#" class="navbar-brand">
|
|
||||||
CNC Speed Calculator
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class="container mt-4 text-white">
|
<div class="container mt-4 text-white">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-lg-8 offset-lg-2">
|
<div class="col-12 col-lg-8 offset-lg-2">
|
||||||
<%- include('settings'); -%>
|
<%- include('includes/index/settings'); -%>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row mb-4 mt-lg-2">
|
<div class="row mb-4 mt-lg-2">
|
||||||
<div class="col-12 col-lg-6 mt-3">
|
<div class="col-12 col-lg-6 mt-3">
|
||||||
<%- include('calculated'); -%>
|
<%- include('includes/index/calculated'); -%>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-lg-6 mt-3">
|
<div class="col-12 col-lg-6 mt-3">
|
||||||
<%- include('constants'); -%>
|
<%- include('includes/index/constants'); -%>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -36,124 +28,6 @@
|
|||||||
<script>
|
<script>
|
||||||
let preset_cut = '<%- JSON.stringify(preset_cut) %>';
|
let preset_cut = '<%- JSON.stringify(preset_cut) %>';
|
||||||
let preset_step_down_factor = '<%- JSON.stringify(step_down_factor) %>';
|
let preset_step_down_factor = '<%- JSON.stringify(step_down_factor) %>';
|
||||||
preset_cut = JSON.parse(preset_cut);
|
|
||||||
preset_step_down_factor = JSON.parse(preset_step_down_factor);
|
|
||||||
|
|
||||||
let preset_cut_elem = document.querySelector('#preset_cut');
|
|
||||||
let preset_step_down_factor_elem = document.querySelector('#preset_step_down_factor');
|
|
||||||
let tooth_nbr_elem = document.querySelector('#tooth_nbr');
|
|
||||||
let tool_diameter_elem = document.querySelector('#tool_diameter');
|
|
||||||
let max_rpm_elem = document.querySelector('#max_rpm')
|
|
||||||
|
|
||||||
let rpm_elem = document.querySelector('#rpm');
|
|
||||||
let feed_rate_elem = document.querySelector('#feed_rate');
|
|
||||||
let feed_rate_sec_elem = document.querySelector('#feed_rate_sec');
|
|
||||||
let step_down_elem = document.querySelector('#step_down');
|
|
||||||
|
|
||||||
let cutting_speed_elem = document.querySelector('#cutting_speed');
|
|
||||||
let feed_tooth_elem = document.querySelector('#feed_tooth');
|
|
||||||
let step_down_factor_elem = document.querySelector('#step_down_factor');
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function (event) {
|
|
||||||
load();
|
|
||||||
onChange();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
function onChange() {
|
|
||||||
if (preset_cut_elem.value === "" || preset_step_down_factor_elem.value === "" || tool_diameter_elem.value === "0" || tooth_nbr_elem.value === "0" || max_rpm_elem.value === "0") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
save();
|
|
||||||
let new_preset_cut = getPresetValue(preset_cut, parseInt(preset_cut_elem.value, 10));
|
|
||||||
let new_preset_steep_down = getPresetValue(preset_step_down_factor, parseInt(preset_step_down_factor_elem.value, 10))
|
|
||||||
let new_tool_diameter = parseFloat(tool_diameter_elem.value);
|
|
||||||
let new_tooth_nbr = parseInt(tooth_nbr_elem.value);
|
|
||||||
let max_rpm = parseInt(max_rpm_elem.value);
|
|
||||||
|
|
||||||
let rpm = (1000 * new_preset_cut.cut_speed) / (3.14 * new_tool_diameter);
|
|
||||||
if (rpm > max_rpm)
|
|
||||||
rpm = max_rpm;
|
|
||||||
let feed_rate = rpm * getFeedByTooth(new_tool_diameter, new_preset_cut) * new_tooth_nbr;
|
|
||||||
let feed_rate_sec = feed_rate / 60;
|
|
||||||
let step_down = new_tool_diameter * getStepDownFactor(new_tool_diameter, new_preset_steep_down);
|
|
||||||
|
|
||||||
rpm = Math.round(rpm);
|
|
||||||
feed_rate = Math.round(feed_rate);
|
|
||||||
feed_rate_sec = feed_rate_sec.toFixed(2)
|
|
||||||
step_down = step_down.toFixed(2);
|
|
||||||
|
|
||||||
rpm_elem.value = rpm;
|
|
||||||
feed_rate_elem.value = feed_rate;
|
|
||||||
feed_rate_sec_elem.value = feed_rate_sec;
|
|
||||||
step_down_elem.value = step_down;
|
|
||||||
|
|
||||||
cutting_speed_elem.value = new_preset_cut.cut_speed;
|
|
||||||
feed_tooth_elem.value = getFeedByTooth(new_tool_diameter, new_preset_cut);
|
|
||||||
step_down_factor_elem.value = getStepDownFactor(new_tool_diameter, new_preset_steep_down);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPresetValue(list, id) {
|
|
||||||
for (let elem of list) {
|
|
||||||
if (elem.id === id) {
|
|
||||||
return elem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
function getFeedByTooth(tool_diam, preset) {
|
|
||||||
if (tool_diam >= 8)
|
|
||||||
return preset.feed_by_tooth_more_8;
|
|
||||||
if (tool_diam >= 6)
|
|
||||||
return preset.feed_by_tooth_more_6;
|
|
||||||
if (tool_diam >= 5)
|
|
||||||
return preset.feed_by_tooth_more_5;
|
|
||||||
if (tool_diam >= 4)
|
|
||||||
return preset.feed_by_tooth_more_4;
|
|
||||||
if (tool_diam >= 3)
|
|
||||||
return preset.feed_by_tooth_more_3;
|
|
||||||
if (tool_diam >= 2)
|
|
||||||
return preset.feed_by_tooth_more_2;
|
|
||||||
return preset.feed_by_tooth_more_1;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getStepDownFactor(tool_diam, preset) {
|
|
||||||
if (tool_diam >= 6)
|
|
||||||
return preset.k_more_6;
|
|
||||||
if (tool_diam >= 5)
|
|
||||||
return preset.k_more_5;
|
|
||||||
if (tool_diam >= 4)
|
|
||||||
return preset.k_more_4;
|
|
||||||
if (tool_diam >= 3)
|
|
||||||
return preset.k_more_3;
|
|
||||||
if (tool_diam >= 2)
|
|
||||||
return preset.k_more_2;
|
|
||||||
return preset.k_less_2;
|
|
||||||
}
|
|
||||||
|
|
||||||
function save(){
|
|
||||||
let values = {
|
|
||||||
preset_cut: preset_cut_elem.value,
|
|
||||||
preset_step_down_factor: preset_step_down_factor_elem.value,
|
|
||||||
tool_diameter: tool_diameter_elem.value,
|
|
||||||
tooth_nbr: tooth_nbr_elem.value,
|
|
||||||
max_rpm: max_rpm_elem.value
|
|
||||||
}
|
|
||||||
localStorage.setItem('previous_data', JSON.stringify(values));
|
|
||||||
}
|
|
||||||
|
|
||||||
function load(){
|
|
||||||
let previous_data = localStorage.getItem('previous_data')
|
|
||||||
if(previous_data === null)
|
|
||||||
return;
|
|
||||||
previous_data = JSON.parse(previous_data);
|
|
||||||
preset_cut_elem.value = previous_data.preset_cut;
|
|
||||||
preset_step_down_factor_elem.value = previous_data.preset_step_down_factor;
|
|
||||||
tool_diameter_elem.value = previous_data.tool_diameter;
|
|
||||||
tooth_nbr_elem.value = previous_data.tooth_nbr;
|
|
||||||
max_rpm_elem.value = previous_data.max_rpm;
|
|
||||||
}
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
<script src="/js/index.js"></script>
|
||||||
</html>
|
</html>
|
||||||
|
@ -2,36 +2,43 @@
|
|||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>CNC Speed Calculator</title>
|
<title>CNC Speed Calculator</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<%- include('includes/base/styles') %>
|
||||||
<link rel='stylesheet' href='/css/style.css'/>
|
|
||||||
<link rel="stylesheet" href="/css/custom_bootstrap.css">
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-dark navbar-expand">
|
<%- include('includes/base/navbar') %>
|
||||||
<div class="container">
|
|
||||||
<a href="#" class="navbar-brand">
|
|
||||||
CNC Speed Calculator
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</nav>
|
|
||||||
<div class="container mt-4 text-white">
|
<div class="container mt-4 text-white">
|
||||||
<form action="/login" method="post">
|
<div class="row justify-content-center">
|
||||||
<div>
|
<div class="col-12 col-md-6 col-lg-4">
|
||||||
<label>Username:</label>
|
<div class="card bg-dark border-secondary">
|
||||||
<input type="text" name="username"/>
|
<div class="card-header text-center h4 border-secondary">
|
||||||
|
<%= __('Login') %>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="card-body">
|
||||||
<label>Password:</label>
|
<form action="/login" method="post" autocomplete="on">
|
||||||
<input type="password" name="password"/>
|
<div class="mb-3 text-center">
|
||||||
|
<label class="form-label" for="username"><%= __('Username') %></label>
|
||||||
|
<input class="form-control text-center border-accent" type="text" name="username" id="username"/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="mb-3 text-center">
|
||||||
<input type="submit" value="Log In"/>
|
<label class="form-label" for="password"><%= __('Password') %></label>
|
||||||
|
<input class="form-control text-center border-accent" type="password" name="password" id="password"/>
|
||||||
|
</div>
|
||||||
|
<div class="d-flex justify-content-center">
|
||||||
|
<button type="submit" class="btn btn-success"><%= __('Log In') %></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
<script src="/js/bootstrap.min.js"></script>
|
<script src="/js/bootstrap.min.js"></script>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
|
||||||
|
|
||||||
|
114
views/preset-cut-editor.ejs
Normal file
114
views/preset-cut-editor.ejs
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>CNC Speed Calculator</title>
|
||||||
|
<%- include('includes/base/styles') %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%- include('includes/base/navbar') %>
|
||||||
|
<div class="container mt-4 text-white">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-12 col-md-12">
|
||||||
|
<div class="card bg-dark border-secondary mb-4">
|
||||||
|
<div class="card-header text-center h4 border-secondary">
|
||||||
|
<%= __('Material Preset Editor') %>
|
||||||
|
</div>
|
||||||
|
<div class="card-body">
|
||||||
|
<form method="post">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-12 col-md-4">
|
||||||
|
<label for="name" class="form-label"><%= __('Name') %></label>
|
||||||
|
<input type="text" class="form-control border-accent" id="name" name="name" value="<%= preset.name %>">
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-4 mt-3 mt-md-0">
|
||||||
|
<label for="cutting_speed" class="form-label"><%= __('Cutting Speed') %></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control border-accent border-end-0" id="cutting_speed" min=0
|
||||||
|
step="1" value="<%= preset.cut_speed %>" name="cutting_speed">
|
||||||
|
<span class="input-group-text border-accent">m/min</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mt-4">
|
||||||
|
<div class="col-12 text-center border-bottom border-secondary">
|
||||||
|
<h5><b><%= __('Feed By Tooth (By tool diameter)') %></b></h5>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row row-cols-md-4 row-cols-lg-5 row-cols-xl-6 row-cols-1 justify-content-center">
|
||||||
|
<div class="col mt-3 text-center">
|
||||||
|
<label for="feed_by_tooth_more_1" class="form-label fw-bold"><%= __('∅ ≥ 1mm') %></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control border-accent border-end-0" id="feed_by_tooth_more_1" min=0
|
||||||
|
step="0.001" value="<%= preset.feed_by_tooth_more_1 %>" name="feed_by_tooth_more_1">
|
||||||
|
<span class="input-group-text border-accent">mm</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col mt-3 text-center">
|
||||||
|
<label for="feed_by_tooth_more_2" class="form-label fw-bold"><%= __('∅ ≥ 2mm') %></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control border-accent border-end-0" id="feed_by_tooth_more_2" min=0
|
||||||
|
step="0.001" value="<%= preset.feed_by_tooth_more_2 %>" name="feed_by_tooth_more_2">
|
||||||
|
<span class="input-group-text border-accent">mm</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col mt-3 text-center">
|
||||||
|
<label for="feed_by_tooth_more_3" class="form-label fw-bold"><%= __('∅ ≥ 3mm') %></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control border-accent border-end-0" id="feed_by_tooth_more_3" min=0
|
||||||
|
step="0.001" value="<%= preset.feed_by_tooth_more_3 %>" name="feed_by_tooth_more_3">
|
||||||
|
<span class="input-group-text border-accent">mm</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col mt-3 text-center">
|
||||||
|
<label for="feed_by_tooth_more_4" class="form-label fw-bold"><%= __('∅ ≥ 4mm') %></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control border-accent border-end-0" id="feed_by_tooth_more_4" min=0
|
||||||
|
step="0.001" value="<%= preset.feed_by_tooth_more_4 %>" name="feed_by_tooth_more_4">
|
||||||
|
<span class="input-group-text border-accent">mm</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col mt-3 text-center">
|
||||||
|
<label for="feed_by_tooth_more_5" class="form-label fw-bold"><%= __('∅ ≥ 5mm') %></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control border-accent border-end-0" id="feed_by_tooth_more_5" min=0
|
||||||
|
step="0.001" value="<%= preset.feed_by_tooth_more_5 %>" name="feed_by_tooth_more_5">
|
||||||
|
<span class="input-group-text border-accent">mm</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col mt-3 text-center">
|
||||||
|
<label for="feed_by_tooth_more_6" class="form-label fw-bold"><%= __('∅ ≥ 6mm') %></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control border-accent border-end-0" id="feed_by_tooth_more_6" min=0
|
||||||
|
step="0.001" value="<%= preset.feed_by_tooth_more_6 %>" name="feed_by_tooth_more_6">
|
||||||
|
<span class="input-group-text border-accent">mm</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col mt-3 text-center">
|
||||||
|
<label for="feed_by_tooth_more_8" class="form-label fw-bold"><%= __('∅ ≥ 8mm') %></label>
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="number" class="form-control border-accent border-end-0" id="feed_by_tooth_more_8" min=0
|
||||||
|
step="0.001" value="<%= preset.feed_by_tooth_more_8 %>" name="feed_by_tooth_more_8">
|
||||||
|
<span class="input-group-text border-accent">mm</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center mt-4">
|
||||||
|
<div class="col-12 d-flex justify-content-center">
|
||||||
|
<button class="btn btn-success"><i class="fas fa-save"></i> <%= __('Save') %></button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script src="/js/bootstrap.min.js"></script>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
63
views/preset-manager.ejs
Normal file
63
views/preset-manager.ejs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>CNC Speed Calculator</title>
|
||||||
|
<%- include('includes/base/styles') %>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<%- include('includes/base/navbar') %>
|
||||||
|
<div class="container mt-4 text-white">
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-12">
|
||||||
|
<div class="card bg-dark border-secondary">
|
||||||
|
<div class="card-header h4 text-center"><%= __('Preset Manager') %></div>
|
||||||
|
<div class="card-body px-0 pb-0">
|
||||||
|
<ul class="nav nav-tabs nav-fill" role="tablist">
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<a class="nav-link active" id="material-tab-btn" data-bs-toggle="tab"
|
||||||
|
href="#material_content"
|
||||||
|
role="tab"><%= __("Material") %></a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<a class="nav-link" id="step-down-tab-btn" data-bs-toggle="tab" href="#step_down_content"
|
||||||
|
role="tab"><%= __('Step down factor') %></a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane fade show active table-responsive" id="material_content" role="tabpanel">
|
||||||
|
<%- include('includes/preset-manager/material-table') %>
|
||||||
|
</div>
|
||||||
|
<div class="tab-pane fade table-responsive" id="step_down_content" role="tabpanel">
|
||||||
|
<%- include('includes/preset-manager/step-down-factor-table') %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
<script src="/js/bootstrap.min.js"></script>
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function (event) {
|
||||||
|
document.getElementById("material-tab-btn").addEventListener('click', onClick);
|
||||||
|
document.getElementById("step-down-tab-btn").addEventListener('click', onClick);
|
||||||
|
if (document.location.hash === "#step_down")
|
||||||
|
(new bootstrap.Tab(document.getElementById('step-down-tab-btn'))).show();
|
||||||
|
});
|
||||||
|
|
||||||
|
function onClick(ev) {
|
||||||
|
if (ev.target.id === "material-tab-btn") {
|
||||||
|
window.location.hash = "";
|
||||||
|
} else {
|
||||||
|
window.location.hash = "step_down";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user