sortable tables, apprentice/location filters
This commit is contained in:
		
							parent
							
								
									ff9452ec3d
								
							
						
					
					
						commit
						0ac6178228
					
				@ -25,7 +25,7 @@ app.get([ '/', '/enemies' ], (req, res) => {
 | 
				
			|||||||
app.get('/spells', (req, res) => {
 | 
					app.get('/spells', (req, res) => {
 | 
				
			||||||
	res.render('spells', {
 | 
						res.render('spells', {
 | 
				
			||||||
		context: 'spells',
 | 
							context: 'spells',
 | 
				
			||||||
		spells: spells.spells,
 | 
							spells: spells.spells.sort((a, b) => a.name.localeCompare(b.name)),
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -39,14 +39,24 @@ app.get('/exp', (req, res) => {
 | 
				
			|||||||
app.get('/weapons', (req, res) => {
 | 
					app.get('/weapons', (req, res) => {
 | 
				
			||||||
	res.render('weapons', {
 | 
						res.render('weapons', {
 | 
				
			||||||
		context: 'weapons',
 | 
							context: 'weapons',
 | 
				
			||||||
		weapons: items.weapons,
 | 
							weapons: items.weapons.sort((a, b) => {
 | 
				
			||||||
 | 
								if (a.attack === b.attack) {
 | 
				
			||||||
 | 
									return a.name.localeCompare(b.name);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return a.attack === b.attack ? 0 : (a.attack < b.attack ? -1 : 1 );
 | 
				
			||||||
 | 
							})
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app.get('/armor', (req, res) => {
 | 
					app.get('/armor', (req, res) => {
 | 
				
			||||||
	res.render('armor', {
 | 
						res.render('armor', {
 | 
				
			||||||
		context: 'armor',
 | 
							context: 'armor',
 | 
				
			||||||
		armor: items.armor,
 | 
							armor: items.armor.sort((a, b) => {
 | 
				
			||||||
 | 
								if (a.defense === b.defense) {
 | 
				
			||||||
 | 
									return a.name.localeCompare(b.name);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
								return a.defense === b.defense ? 0 : (a.defense < b.defense ? -1 : 1)
 | 
				
			||||||
 | 
							},),
 | 
				
			||||||
	});
 | 
						});
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -42,3 +42,19 @@
 | 
				
			|||||||
	content: ",";
 | 
						content: ",";
 | 
				
			||||||
	margin-right: 4px;
 | 
						margin-right: 4px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					table.sticky-header {
 | 
				
			||||||
 | 
						position: relative;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					table.sticky-header tr.header th {
 | 
				
			||||||
 | 
						position: sticky;
 | 
				
			||||||
 | 
						top: 37px;
 | 
				
			||||||
 | 
						background-color: #fcfac8;
 | 
				
			||||||
 | 
						z-index: 2;
 | 
				
			||||||
 | 
						box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.25);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					th.sorted, td.sorted {
 | 
				
			||||||
 | 
						background-color: #dae5f6 !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										164
									
								
								web/static/saga.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								web/static/saga.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,164 @@
 | 
				
			|||||||
 | 
					(function(window) {
 | 
				
			||||||
 | 
						const $apprenticeFilterForm = $('.apprentice-filter-form');
 | 
				
			||||||
 | 
						const $locationFilterForm = $('.location-filter-form');
 | 
				
			||||||
 | 
						const $table = $('#main-table');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						window.saga = {
 | 
				
			||||||
 | 
							sortData: () => {
 | 
				
			||||||
 | 
								const qs = new URLSearchParams(window.location.search);
 | 
				
			||||||
 | 
								const col = qs.get('col');
 | 
				
			||||||
 | 
								let dir = qs.get('dir');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!col) {
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!$table.length) {
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (dir !== 'asc' && dir !== 'desc') {
 | 
				
			||||||
 | 
									dir = 'asc';
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const rows = $table.find('tbody.data tr').toArray();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const firstRow = rows[0];
 | 
				
			||||||
 | 
								if (!firstRow) {
 | 
				
			||||||
 | 
									return;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								const coefficient = dir === 'desc' ? -1 : 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								rows.sort((a, b) => {
 | 
				
			||||||
 | 
									let aVal = a.getAttribute('data-' + col);
 | 
				
			||||||
 | 
									let bVal = b.getAttribute('data-' + col);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									const isNumber = !isNaN(Number(aVal));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (isNumber && aVal) {
 | 
				
			||||||
 | 
										aVal = Number(aVal);
 | 
				
			||||||
 | 
										bVal = Number(bVal);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (aVal === bVal) {
 | 
				
			||||||
 | 
										if (col === 'name') {
 | 
				
			||||||
 | 
											return 0;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										const aName = a.getAttribute('data-name');
 | 
				
			||||||
 | 
										const bName = b.getAttribute('data-name');
 | 
				
			||||||
 | 
										if (typeof(aName) === 'string' && typeof(bName) === 'string') {
 | 
				
			||||||
 | 
											return aName.localeCompare(bName) * coefficient;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										return 0;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (typeof(aVal) === 'number' && typeof(bVal) === 'number') {
 | 
				
			||||||
 | 
										return (aVal < bVal ? -1 : 1) * coefficient;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									if (typeof(aVal) === 'string' && typeof(bVal) === 'string') {
 | 
				
			||||||
 | 
										return aVal.localeCompare(bVal) * coefficient;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								let nextChild = null;
 | 
				
			||||||
 | 
								const headers = $table.find('tr.header th').removeClass('sorted').toArray();
 | 
				
			||||||
 | 
								const highlightedIndex = headers.findIndex(cell => cell.getAttribute('data-col') === col);
 | 
				
			||||||
 | 
								if (highlightedIndex === -1) {
 | 
				
			||||||
 | 
									throw new Error('could not find header column');
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								headers[highlightedIndex].classList.add('sorted');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								for (let i = rows.length - 1; i >= 0; i--) {
 | 
				
			||||||
 | 
									const row = rows[i];
 | 
				
			||||||
 | 
									if (row === nextChild) {
 | 
				
			||||||
 | 
										continue;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									$(row).find('td.sorted').removeClass('sorted');
 | 
				
			||||||
 | 
									$(row).find('td').eq(highlightedIndex).addClass('sorted');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									row.parentNode.insertBefore(row, nextChild);
 | 
				
			||||||
 | 
									nextChild = row;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							filterApprentices: () => {
 | 
				
			||||||
 | 
								const apprentices = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$apprenticeFilterForm.find('input[type="checkbox"]').toArray().map((input) => {
 | 
				
			||||||
 | 
									if (input.checked) {
 | 
				
			||||||
 | 
										apprentices.push(input.name);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$table
 | 
				
			||||||
 | 
									.find('tbody.data tr')
 | 
				
			||||||
 | 
									.hide()
 | 
				
			||||||
 | 
									.filter((i, row) => {
 | 
				
			||||||
 | 
										if (!apprentices.length) {
 | 
				
			||||||
 | 
											return true;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										const users = ($(row).attr('data-users') || '').split(',');
 | 
				
			||||||
 | 
										if (!users.length) {
 | 
				
			||||||
 | 
											return true;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return apprentices.some((name) => users.includes(name));
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
									.show();
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							filterLocations: () => {
 | 
				
			||||||
 | 
								const checked = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								console.log('filter locations');
 | 
				
			||||||
 | 
								$locationFilterForm.find('input[type="checkbox"]').toArray().map((input) => {
 | 
				
			||||||
 | 
									if (input.checked) {
 | 
				
			||||||
 | 
										console.log('input checked');
 | 
				
			||||||
 | 
										checked.push(input.name);
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								$table
 | 
				
			||||||
 | 
									.find('tbody.data tr')
 | 
				
			||||||
 | 
									.hide()
 | 
				
			||||||
 | 
									.filter((i, row) => {
 | 
				
			||||||
 | 
										if (!checked.length) {
 | 
				
			||||||
 | 
											return true;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
										const data = $(row).attr('data-locations').split(',');
 | 
				
			||||||
 | 
										if (!data.length) {
 | 
				
			||||||
 | 
											return true;
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
										return data.some((name) => checked.includes(name));
 | 
				
			||||||
 | 
									})
 | 
				
			||||||
 | 
									.show();
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						window.saga.sortData();
 | 
				
			||||||
 | 
						window.saga.filterApprentices();
 | 
				
			||||||
 | 
						window.saga.filterLocations();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						window.addEventListener('popstate', () => {
 | 
				
			||||||
 | 
							window.saga.sortData();
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$('.sortable-links a').click(function(e) {
 | 
				
			||||||
 | 
							e.preventDefault();
 | 
				
			||||||
 | 
							window.history.replaceState(null, '', $(this).attr('href'));
 | 
				
			||||||
 | 
							window.saga.sortData();
 | 
				
			||||||
 | 
						});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						$apprenticeFilterForm.find('input[type="checkbox"]').on('change', window.saga.filterApprentices);
 | 
				
			||||||
 | 
						$locationFilterForm.find('input[type="checkbox"]').on('change', window.saga.filterLocations);
 | 
				
			||||||
 | 
					}(window));
 | 
				
			||||||
@ -3,42 +3,42 @@ extends master.pug
 | 
				
			|||||||
block tab-content
 | 
					block tab-content
 | 
				
			||||||
	+apprenticeFilterForm()
 | 
						+apprenticeFilterForm()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	div.table-responsive
 | 
						table#main-table.table.table-sm.table-borderless.table-hover.table-striped.sticky-header
 | 
				
			||||||
		table.table.table-sm.table-borderless.table-hover.table-striped
 | 
							thead: tr.header
 | 
				
			||||||
			thead: tr
 | 
								+sortHeader('Name', 'name')
 | 
				
			||||||
				+sortHeader('Name')
 | 
								+sortHeader('Defense', 'defense')
 | 
				
			||||||
				+sortHeader('Defense')
 | 
								+sortHeader('Cost', 'cost')
 | 
				
			||||||
				+sortHeader('Cost')
 | 
								+sortHeader('Fire', 'res-fire')
 | 
				
			||||||
				+sortHeader('Fire')
 | 
								+sortHeader('Ice', 'res-ice')
 | 
				
			||||||
				+sortHeader('Ice')
 | 
								+sortHeader('Thunder', 'res-thunder')
 | 
				
			||||||
				+sortHeader('Thunder')
 | 
								+sortHeader('Vacuum', 'res-vacuum')
 | 
				
			||||||
				+sortHeader('Vacuum')
 | 
								+sortHeader('Debuff', 'res-debuff')
 | 
				
			||||||
				+sortHeader('Debuff')
 | 
								th.align-middle Users
 | 
				
			||||||
				th.align-middle Users
 | 
								th.align-middle Locations
 | 
				
			||||||
				th.align-middle Locations
 | 
							tbody.data: each item in accessories
 | 
				
			||||||
			tbody: each item in accessories
 | 
								tr(
 | 
				
			||||||
				tr(
 | 
									data-name=item.name
 | 
				
			||||||
					data-name=item.name
 | 
									data-defense=item.defense
 | 
				
			||||||
					data-defense=item.defense
 | 
									data-cost=item.cost
 | 
				
			||||||
					data-cost=item.cost
 | 
									data-res-fire=item.resistance.fire
 | 
				
			||||||
					data-res-fire=item.resistance.fire
 | 
									data-res-ice=item.resistance.ice
 | 
				
			||||||
					data-res-ice=item.resistance.ice
 | 
									data-res-thunder=item.resistance.thunder
 | 
				
			||||||
					data-res-thunder=item.resistance.thunder
 | 
									data-res-vacuum=item.resistance.vacuum
 | 
				
			||||||
					data-res-vacuum=item.resistance.vacuum
 | 
									data-res-debuff=item.resistance.debuff
 | 
				
			||||||
					data-res-debuff=item.resistance.debuff
 | 
									data-users=item.users.join(',')
 | 
				
			||||||
				)
 | 
								)
 | 
				
			||||||
					td: strong= item.name
 | 
									td: strong= item.name
 | 
				
			||||||
					td.text-right: code= item.defense
 | 
									td.text-right: code= item.defense
 | 
				
			||||||
					td.text-right: code= item.cost.toLocaleString()
 | 
									td.text-right: code= item.cost.toLocaleString()
 | 
				
			||||||
					td.text-right: code= item.resistance.fire
 | 
									td.text-right: code= item.resistance.fire
 | 
				
			||||||
					td.text-right: code= item.resistance.ice
 | 
									td.text-right: code= item.resistance.ice
 | 
				
			||||||
					td.text-right: code= item.resistance.thunder
 | 
									td.text-right: code= item.resistance.thunder
 | 
				
			||||||
					td.text-right: code= item.resistance.vacuum
 | 
									td.text-right: code= item.resistance.vacuum
 | 
				
			||||||
					td.text-right: code= item.resistance.debuff
 | 
									td.text-right: code= item.resistance.debuff
 | 
				
			||||||
					td: ul.list-horizontal
 | 
									td: ul.list-horizontal
 | 
				
			||||||
						each char in item.users
 | 
										each char in item.users
 | 
				
			||||||
							li= char
 | 
											li= char
 | 
				
			||||||
					td: ul.list-horizontal
 | 
									td: ul.list-horizontal
 | 
				
			||||||
						each location in item.locations
 | 
										each location in item.locations
 | 
				
			||||||
							li= location
 | 
											li= location
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,42 +1,44 @@
 | 
				
			|||||||
extends master.pug
 | 
					extends master.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
block tab-content
 | 
					block tab-content
 | 
				
			||||||
	div.table-responsive
 | 
						+apprenticeFilterForm()
 | 
				
			||||||
		table.table.table-sm.table-borderless.table-hover.table-striped
 | 
					
 | 
				
			||||||
			thead: tr
 | 
						table#main-table.table.table-sm.table-borderless.table-hover.table-striped.sticky-header
 | 
				
			||||||
				+sortHeader('Name')
 | 
							thead: tr.header
 | 
				
			||||||
				+sortHeader('Defense')
 | 
								+sortHeader('Name', 'name')
 | 
				
			||||||
				+sortHeader('Cost')
 | 
								+sortHeader('Defense', 'defense')
 | 
				
			||||||
				+sortHeader('Fire')
 | 
								+sortHeader('Cost', 'cost')
 | 
				
			||||||
				+sortHeader('Ice')
 | 
								+sortHeader('Fire', 'res-fire')
 | 
				
			||||||
				+sortHeader('Thunder')
 | 
								+sortHeader('Ice', 'res-ice')
 | 
				
			||||||
				+sortHeader('Vacuum')
 | 
								+sortHeader('Thunder', 'res-thunder')
 | 
				
			||||||
				+sortHeader('Debuff')
 | 
								+sortHeader('Vacuum', 'res-vacuum')
 | 
				
			||||||
				th.align-middle Users
 | 
								+sortHeader('Debuff', 'res-debuff')
 | 
				
			||||||
				th.align-middle Locations
 | 
								th.align-middle Users
 | 
				
			||||||
			tbody: each item in armor
 | 
								th.align-middle Locations
 | 
				
			||||||
				tr(
 | 
							tbody.data: each item in armor
 | 
				
			||||||
					data-name=item.name
 | 
								tr(
 | 
				
			||||||
					data-defense=item.defense
 | 
									data-name=item.name
 | 
				
			||||||
					data-cost=item.cost
 | 
									data-defense=item.defense
 | 
				
			||||||
					data-res-fire=item.resistance.fire
 | 
									data-cost=item.cost
 | 
				
			||||||
					data-res-ice=item.resistance.ice
 | 
									data-res-fire=item.resistance.fire
 | 
				
			||||||
					data-res-thunder=item.resistance.thunder
 | 
									data-res-ice=item.resistance.ice
 | 
				
			||||||
					data-res-vacuum=item.resistance.vacuum
 | 
									data-res-thunder=item.resistance.thunder
 | 
				
			||||||
					data-res-debuff=item.resistance.debuff
 | 
									data-res-vacuum=item.resistance.vacuum
 | 
				
			||||||
				)
 | 
									data-res-debuff=item.resistance.debuff
 | 
				
			||||||
					td: strong= item.name
 | 
									data-users=item.users.join(',')
 | 
				
			||||||
					td.text-right: code= item.defense
 | 
								)
 | 
				
			||||||
					td.text-right: code= item.cost.toLocaleString()
 | 
									td: strong= item.name
 | 
				
			||||||
					td.text-right: code= item.resistance.fire
 | 
									td.text-right: code= item.defense
 | 
				
			||||||
					td.text-right: code= item.resistance.ice
 | 
									td.text-right: code= item.cost.toLocaleString()
 | 
				
			||||||
					td.text-right: code= item.resistance.thunder
 | 
									td.text-right: code= item.resistance.fire
 | 
				
			||||||
					td.text-right: code= item.resistance.vacuum
 | 
									td.text-right: code= item.resistance.ice
 | 
				
			||||||
					td.text-right: code= item.resistance.debuff
 | 
									td.text-right: code= item.resistance.thunder
 | 
				
			||||||
					td: ul.list-horizontal
 | 
									td.text-right: code= item.resistance.vacuum
 | 
				
			||||||
						each char in item.users
 | 
									td.text-right: code= item.resistance.debuff
 | 
				
			||||||
							li= char
 | 
									td: ul.list-horizontal
 | 
				
			||||||
					td: ul.list-horizontal
 | 
										each char in item.users
 | 
				
			||||||
						each location in item.locations
 | 
											li= char
 | 
				
			||||||
							li= location
 | 
									td: ul.list-horizontal
 | 
				
			||||||
 | 
										each location in item.locations
 | 
				
			||||||
 | 
											li= location
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
extends master.pug
 | 
					extends master.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
block tab-content
 | 
					block tab-content
 | 
				
			||||||
    div.table-responsive: table.table.table-sm.table-borderless.table-striped.table-hover
 | 
					    table#main-table.table.table-sm.table-borderless.table-striped.table-hover.sticky-header
 | 
				
			||||||
        tr.header-above
 | 
					        tr.header-above
 | 
				
			||||||
            th(colspan="2")
 | 
					            th(colspan="2")
 | 
				
			||||||
            th(colspan="3").text-center.bg-info.text-light Reward
 | 
					            th(colspan="3").text-center.bg-info.text-light Reward
 | 
				
			||||||
@ -9,23 +9,23 @@ block tab-content
 | 
				
			|||||||
            th(colspan="5").text-center.bg-dark.text-light Resistance
 | 
					            th(colspan="5").text-center.bg-dark.text-light Resistance
 | 
				
			||||||
        tr.header
 | 
					        tr.header
 | 
				
			||||||
            th.align-middle Img
 | 
					            th.align-middle Img
 | 
				
			||||||
            +sortHeader('Name')
 | 
					            +sortHeader('Name', 'name')
 | 
				
			||||||
            +sortHeader('Gold')
 | 
					            +sortHeader('Gold', 'gold')
 | 
				
			||||||
            +sortHeader('Exp')
 | 
					            +sortHeader('Exp', 'exp')
 | 
				
			||||||
            th.align-middle Drops
 | 
					            th.align-middle Drops
 | 
				
			||||||
            +sortHeader('HP')
 | 
					            +sortHeader('HP', 'hp')
 | 
				
			||||||
            +sortHeader('MP')
 | 
					            +sortHeader('MP', 'mp')
 | 
				
			||||||
            +sortHeader('Power')
 | 
					            +sortHeader('Power', 'power')
 | 
				
			||||||
            +sortHeader('Guard')
 | 
					            +sortHeader('Guard', 'guard')
 | 
				
			||||||
            +sortHeader('Magic')
 | 
					            +sortHeader('Magic', 'magic')
 | 
				
			||||||
            +sortHeader('Speed')
 | 
					            +sortHeader('Speed', 'speed')
 | 
				
			||||||
            th.align-middle Spells
 | 
					            th.align-middle Spells
 | 
				
			||||||
            +sortHeader('Fire')
 | 
					            +sortHeader('Fire', 'res-fire')
 | 
				
			||||||
            +sortHeader('Ice')
 | 
					            +sortHeader('Ice', 'res-ice')
 | 
				
			||||||
            +sortHeader('Thunder')
 | 
					            +sortHeader('Thunder', 'res-thunder')
 | 
				
			||||||
            +sortHeader('Vacuum')
 | 
					            +sortHeader('Vacuum', 'res-vacuum')
 | 
				
			||||||
            +sortHeader('Debuff')
 | 
					            +sortHeader('Debuff', 'res-debuff')
 | 
				
			||||||
        tbody: each enemy in enemies
 | 
					        tbody.data: each enemy in enemies
 | 
				
			||||||
            tr(
 | 
					            tr(
 | 
				
			||||||
                data-name=enemy.name
 | 
					                data-name=enemy.name
 | 
				
			||||||
                data-gold=enemy.gold
 | 
					                data-gold=enemy.gold
 | 
				
			||||||
 | 
				
			|||||||
@ -1,25 +1,27 @@
 | 
				
			|||||||
extends master.pug
 | 
					extends master.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
block tab-content
 | 
					block tab-content
 | 
				
			||||||
	div.row: div.col-12.col-md-6: div.table-responsive
 | 
						div.row: div.col-12.col-md-6
 | 
				
			||||||
		table.table.table-sm.table-borderless.table-hover
 | 
							table#main-table.table.table-sm.table-borderless.table-hover.sticky-header
 | 
				
			||||||
			thead: tr
 | 
								thead: tr.header
 | 
				
			||||||
				+sortHeader('Level')
 | 
									+sortHeader('Level', 'level')
 | 
				
			||||||
				th Experience
 | 
									th Experience
 | 
				
			||||||
				+sortHeader('+ increase')
 | 
									+sortHeader('+ increase', 'increase')
 | 
				
			||||||
				+sortHeader('% increase')
 | 
									+sortHeader('% increase', 'increase-per')
 | 
				
			||||||
			tbody: each value, i in exp
 | 
								tbody.data: each value, i in exp
 | 
				
			||||||
				- const prev = exp[i - 1];
 | 
									- const prev = exp[i - 1];
 | 
				
			||||||
				tr
 | 
									- const increaseAmount = i > 0 ? value - prev : 0;
 | 
				
			||||||
 | 
									- const increasePercent = i > 0 && prev > 0 ? increaseAmount / prev : 0;
 | 
				
			||||||
 | 
									tr(
 | 
				
			||||||
 | 
										data-level=(i + 1)
 | 
				
			||||||
 | 
										data-increase=increaseAmount
 | 
				
			||||||
 | 
										data-increase-per=increasePercent
 | 
				
			||||||
 | 
									)
 | 
				
			||||||
					td: strong= i + 1
 | 
										td: strong= i + 1
 | 
				
			||||||
					td: code= value
 | 
										td: code= value
 | 
				
			||||||
					td
 | 
										td
 | 
				
			||||||
						+na(i > 0)
 | 
											+na(i > 0)
 | 
				
			||||||
							- const increaseAmount = value - prev;
 | 
					 | 
				
			||||||
							code= increaseAmount
 | 
												code= increaseAmount
 | 
				
			||||||
					td
 | 
										td
 | 
				
			||||||
						+na(i > 0 && prev > 0)
 | 
											+na(i > 0 && prev > 0)
 | 
				
			||||||
							-
 | 
					 | 
				
			||||||
								const increaseAmount = value - prev;
 | 
					 | 
				
			||||||
								const increasePercent = increaseAmount / prev;
 | 
					 | 
				
			||||||
							code= (increasePercent * 100).toFixed(2) + '%'
 | 
												code= (increasePercent * 100).toFixed(2) + '%'
 | 
				
			||||||
 | 
				
			|||||||
@ -1,22 +1,23 @@
 | 
				
			|||||||
extends master.pug
 | 
					extends master.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
block tab-content
 | 
					block tab-content
 | 
				
			||||||
	div.row: div.col-12: div.table-responsive
 | 
						+locationFilterForm()
 | 
				
			||||||
		table.table.table-sm.table-borderless.table-hover.table-striped
 | 
						table#main-table.table.table-sm.table-borderless.table-hover.table-striped.sticky-header
 | 
				
			||||||
			thead: tr
 | 
							thead: tr.header
 | 
				
			||||||
				+sortHeader('Name')
 | 
								+sortHeader('Name', 'name')
 | 
				
			||||||
				+sortHeader('Cost')
 | 
								+sortHeader('Cost', 'cost')
 | 
				
			||||||
				th.align-middle Effect
 | 
								th.align-middle Effect
 | 
				
			||||||
				th.align-middle Locations
 | 
								th.align-middle Locations
 | 
				
			||||||
			tbody: each item in items
 | 
							tbody.data: each item in items
 | 
				
			||||||
				tr(
 | 
								tr(
 | 
				
			||||||
					data-name=item.name
 | 
									data-name=item.name
 | 
				
			||||||
					data-cost=item.cost
 | 
									data-cost=item.cost
 | 
				
			||||||
				)
 | 
									data-locations=item.locations.join(',')
 | 
				
			||||||
					td: strong= item.name
 | 
								)
 | 
				
			||||||
					td.text-right: code= item.cost.toLocaleString()
 | 
									td: strong.text-nowrap= item.name
 | 
				
			||||||
					td: em= item.effect
 | 
									td.text-right: code= item.cost.toLocaleString()
 | 
				
			||||||
					td: ul.list-horizontal
 | 
									td: em= item.effect
 | 
				
			||||||
						each location in item.locations
 | 
									td: ul.list-horizontal
 | 
				
			||||||
							li= location
 | 
										each location in item.locations
 | 
				
			||||||
 | 
											li= location
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -7,11 +7,11 @@ html
 | 
				
			|||||||
		link(rel="stylesheet" href="/static/bootstrap-icons.css")
 | 
							link(rel="stylesheet" href="/static/bootstrap-icons.css")
 | 
				
			||||||
		link(rel="stylesheet" href="/static/7th-saga.css")
 | 
							link(rel="stylesheet" href="/static/7th-saga.css")
 | 
				
			||||||
	body
 | 
						body
 | 
				
			||||||
		mixin sortHeader(label)
 | 
							mixin sortHeader(label, col)
 | 
				
			||||||
			th: div.sortable
 | 
								th(data-col=col): div.sortable
 | 
				
			||||||
				div.sortable-links
 | 
									div.sortable-links
 | 
				
			||||||
					a(href="#") ▲
 | 
										a(href="?col=" + col + "&dir=asc") ▲
 | 
				
			||||||
					a(href="#") ▼
 | 
										a(href="?col=" + col + "&dir=desc") ▼
 | 
				
			||||||
				div.col-label.ml-1= label
 | 
									div.col-label.ml-1= label
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mixin na(bool, text)
 | 
							mixin na(bool, text)
 | 
				
			||||||
@ -21,15 +21,23 @@ html
 | 
				
			|||||||
				small: em.text-muted= text || 'n/a'
 | 
									small: em.text-muted= text || 'n/a'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		mixin apprenticeFilterForm()
 | 
							mixin apprenticeFilterForm()
 | 
				
			||||||
			form.apprentice-filter-form: div.d-flex.justify-content-center
 | 
								div.d-flex.justify-content-center.apprentice-filter-form.my-2
 | 
				
			||||||
				each apprentice in [ 'Esuna', 'Kamil', 'Olvan', 'Lejes', 'Lux', 'Valsu', 'Wilme' ]
 | 
									each apprentice in [ 'Esuna', 'Kamil', 'Olvan', 'Lejes', 'Lux', 'Valsu', 'Wilme' ]
 | 
				
			||||||
					div.form-check-inline
 | 
										div.form-check-inline
 | 
				
			||||||
						- const id = 'apprentice-' + apprentice;
 | 
											- const id = 'apprentice-' + apprentice;
 | 
				
			||||||
						input.form-check-input(type="checkbox" name=apprentice id=id)
 | 
											input.form-check-input(type="checkbox" name=apprentice id=id)
 | 
				
			||||||
						label.form-check-label(for=id)= apprentice
 | 
											label.form-check-label(for=id)= apprentice
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							mixin locationFilterForm()
 | 
				
			||||||
 | 
								div.d-flex.justify-content-center.location-filter-form.my-2.flex-wrap
 | 
				
			||||||
 | 
									each location in [ 'Lemele', 'Rablesk', 'Bonro', 'Zellis', 'Pell', 'Patrof', 'Bone', 'Dowaine', 'Belaine', 'Telaine', 'Pang', 'Padal', 'Polasu', 'Tiffana', 'Bilthem', 'Brush', 'Valenca', 'Bugask', 'Guanta', 'Pharano', 'Pasanda', 'Ligena', 'Palsu', 'Melenam', 'Airship' ]
 | 
				
			||||||
 | 
										div.form-check-inline
 | 
				
			||||||
 | 
											- const id = 'location-' + location;
 | 
				
			||||||
 | 
											input.form-check-input(type="checkbox" name=location id=id)
 | 
				
			||||||
 | 
											label.form-check-label(for=id)= location
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		div.container-fluid
 | 
							div.container-fluid
 | 
				
			||||||
			ul.nav.nav-tabs.mt-4.px-4.position-sticky(style="top: 0; background-color: white;")
 | 
								ul.nav.nav-tabs.mt-4.px-4.position-sticky(style="top: 0; background-color: white; z-index: 1")
 | 
				
			||||||
				li.nav-item: a.nav-link(href="/enemies" class=(context === 'enemies' ? 'active' : '')) Enemies
 | 
									li.nav-item: a.nav-link(href="/enemies" class=(context === 'enemies' ? 'active' : '')) Enemies
 | 
				
			||||||
				li.nav-item: a.nav-link(href="/spells" class=(context === 'spells' ? 'active' : '')) Spells
 | 
									li.nav-item: a.nav-link(href="/spells" class=(context === 'spells' ? 'active' : '')) Spells
 | 
				
			||||||
				li.nav-item: a.nav-link(href="/items" class=(context === 'items' ? 'active' : '')) Items
 | 
									li.nav-item: a.nav-link(href="/items" class=(context === 'items' ? 'active' : '')) Items
 | 
				
			||||||
@ -45,3 +53,4 @@ html
 | 
				
			|||||||
		script(src="/static/jquery.js")
 | 
							script(src="/static/jquery.js")
 | 
				
			||||||
		script(src="/static/popper.js")
 | 
							script(src="/static/popper.js")
 | 
				
			||||||
		script(src="/static/bootstrap.js")
 | 
							script(src="/static/bootstrap.js")
 | 
				
			||||||
 | 
							script(src="/static/saga.js")
 | 
				
			||||||
 | 
				
			|||||||
@ -1,18 +1,26 @@
 | 
				
			|||||||
extends master.pug
 | 
					extends master.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
block tab-content
 | 
					block tab-content
 | 
				
			||||||
	div.table-responsive: table.table.table-sm.table-borderless.table-striped.table-hover
 | 
						table#main-table.table.table-sm.table-borderless.table-striped.table-hover.sticky-header
 | 
				
			||||||
		thead: tr
 | 
							thead: tr.header
 | 
				
			||||||
			+sortHeader('Name')
 | 
								+sortHeader('Name', 'name')
 | 
				
			||||||
			+sortHeader('Type')
 | 
								+sortHeader('Type', 'type')
 | 
				
			||||||
			+sortHeader('MP')
 | 
								+sortHeader('MP', 'mp')
 | 
				
			||||||
			+sortHeader('Power')
 | 
								+sortHeader('Power', 'power')
 | 
				
			||||||
			+sortHeader('Heals')
 | 
								+sortHeader('Heals', 'heals')
 | 
				
			||||||
			+sortHeader('Element')
 | 
								+sortHeader('Element', 'element')
 | 
				
			||||||
			+sortHeader('Targets')
 | 
								+sortHeader('Targets', 'targets')
 | 
				
			||||||
			th Effect
 | 
								th.align-middle Effect
 | 
				
			||||||
		tbody: each spell in spells
 | 
							tbody.data: each spell in spells
 | 
				
			||||||
			tr
 | 
								tr(
 | 
				
			||||||
 | 
									data-name=spell.name
 | 
				
			||||||
 | 
									data-type=spell.type
 | 
				
			||||||
 | 
									data-mp=spell.mp
 | 
				
			||||||
 | 
									data-power=(spell.power || 0)
 | 
				
			||||||
 | 
									data-heals=(spell.healingPower === 'max' ? 999 : spell.healingPower || 0)
 | 
				
			||||||
 | 
									data-element=(spell.element || '')
 | 
				
			||||||
 | 
									data-targets=spell.targets
 | 
				
			||||||
 | 
								)
 | 
				
			||||||
				td: strong= spell.name
 | 
									td: strong= spell.name
 | 
				
			||||||
				td= spell.type
 | 
									td= spell.type
 | 
				
			||||||
				td= spell.mp
 | 
									td= spell.mp
 | 
				
			||||||
 | 
				
			|||||||
@ -1,19 +1,22 @@
 | 
				
			|||||||
extends master.pug
 | 
					extends master.pug
 | 
				
			||||||
 | 
					
 | 
				
			||||||
block tab-content
 | 
					block tab-content
 | 
				
			||||||
	div.row: div.col-12.col-md-6: div.table-responsive
 | 
					
 | 
				
			||||||
		table.table.table-sm.table-borderless.table-hover.table-striped
 | 
						div.row.d-flex.justify-content-center: div.col-12.col-md-8
 | 
				
			||||||
			thead: tr
 | 
							+apprenticeFilterForm()
 | 
				
			||||||
				+sortHeader('Name')
 | 
							table#main-table.table.table-sm.table-borderless.table-hover.table-striped.sticky-header
 | 
				
			||||||
				+sortHeader('Power')
 | 
								thead: tr.header
 | 
				
			||||||
				+sortHeader('Cost')
 | 
									+sortHeader('Name', 'name')
 | 
				
			||||||
 | 
									+sortHeader('Power', 'power')
 | 
				
			||||||
 | 
									+sortHeader('Cost', 'cost')
 | 
				
			||||||
				th.align-middle Users
 | 
									th.align-middle Users
 | 
				
			||||||
				th.align-middle Locations
 | 
									th.align-middle Locations
 | 
				
			||||||
			tbody: each weapon in weapons
 | 
								tbody.data: each weapon in weapons
 | 
				
			||||||
				tr(
 | 
									tr(
 | 
				
			||||||
					data-name=weapon.name
 | 
										data-name=weapon.name
 | 
				
			||||||
					data-power=weapon.attack
 | 
										data-power=weapon.attack
 | 
				
			||||||
					data-cost=weapon.cost
 | 
										data-cost=weapon.cost
 | 
				
			||||||
 | 
										data-users=weapon.users.join(',')
 | 
				
			||||||
				)
 | 
									)
 | 
				
			||||||
					td: strong= weapon.name
 | 
										td: strong= weapon.name
 | 
				
			||||||
					td.text-right: code= weapon.attack
 | 
										td.text-right: code= weapon.attack
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user