ADDED card sorting.

ADDED pantheon to each card (duplicate of culture).
ADDED demo cards.
ADDED wikipedia links to most entries.
ADDED Lovecraft Wikia links to all Cthulhu cards.
UPDATED to 0.1.6.
This commit is contained in:
Eric Woodward 2018-01-18 20:10:49 -05:00
parent 1979bd4f97
commit 0f605db8fa
9 changed files with 1663 additions and 545 deletions

2
app.js
View File

@ -36,7 +36,7 @@ app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs'); app.set('view engine', 'ejs');
app.use(favicon()); app.use(favicon());
app.use(logger('dev')); app.use(logger(':remote-addr - [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length]'));
app.use(bodyParser.json()); app.use(bodyParser.json());
app.use(bodyParser.urlencoded()); app.use(bodyParser.urlencoded());
app.use(cookieParser()); app.use(cookieParser());

File diff suppressed because it is too large Load Diff

323
lib/links.json Normal file
View File

@ -0,0 +1,323 @@
{
"Chalchiuhtlicue" : {
"wp": "https://en.wikipedia.org/wiki/Chalchiuhtlicue"
},
"Chicomecōātl" : {
"wp": "https://en.wikipedia.org/wiki/Chicomecoatl"
},
"Cihuacóatl" : {
"wp": "https://en.wikipedia.org/wiki/Cihuacoatl"
},
"Coatlicue" : {
"wp": "https://en.wikipedia.org/wiki/Coatlicue"
},
"Huehuetéotl" : {
"wp": "https://en.wikipedia.org/wiki/Huehueteotl"
},
"Huitzilopochtli" : {
"wp": "https://en.wikipedia.org/wiki/Huitzilopochtli"
},
"Mictecacihuatl" : {
"wp": "https://en.wikipedia.org/wiki/Mictecacihuatl"
},
"Mictlantecuhtli" : {
"wp": "https://en.wikipedia.org/wiki/Mictlantecuhtli"
},
"Quetzalcóatl" : {
"wp": "https://en.wikipedia.org/wiki/Quetzalcoatl"
},
"Tezcatlipōca" : {
"wp": "https://en.wikipedia.org/wiki/Tezcatlipoca"
},
"Tlālōc" : {
"wp": "https://en.wikipedia.org/wiki/Tlaloc"
},
"Xiuhtecuhtli" : {
"wp": "https://en.wikipedia.org/wiki/Xiuhtecuhtli"
},
"Amun" : {
"wp": "https://en.wikipedia.org/wiki/Amun"
},
"Anubis" : {
"wp": "https://en.wikipedia.org/wiki/Anubis"
},
"Hathor" : {
"wp": "https://en.wikipedia.org/wiki/Hathor"
},
"Horus" : {
"wp": "https://en.wikipedia.org/wiki/Horus"
},
"Isis" : {
"wp": "https://en.wikipedia.org/wiki/Isis"
},
"Osiris" : {
"wp": "https://en.wikipedia.org/wiki/Osiris"
},
"Ra" : {
"wp": "https://en.wikipedia.org/wiki/Ra"
},
"Seker" : {
"wp": "https://en.wikipedia.org/wiki/Seker"
},
"Sekhmet" : {
"wp": "https://en.wikipedia.org/wiki/Sekhmet"
},
"Set" : {
"wp": "https://en.wikipedia.org/wiki/Set_(deity)"
},
"Taweret" : {
"wp": "https://en.wikipedia.org/wiki/Taweret"
},
"Wadjet" : {
"wp": "https://en.wikipedia.org/wiki/Wadjet"
},
"Aphrodite" : {
"wp": "https://en.wikipedia.org/wiki/Aphrodite"
},
"Apollo" : {
"wp": "https://en.wikipedia.org/wiki/Apollo"
},
"Ares" : {
"wp": "https://en.wikipedia.org/wiki/Ares"
},
"Artemis" : {
"wp": "https://en.wikipedia.org/wiki/Artemis"
},
"Athena" : {
"wp": "https://en.wikipedia.org/wiki/Athena"
},
"Demeter" : {
"wp": "https://en.wikipedia.org/wiki/Demeter"
},
"Hephaestus" : {
"wp": "https://en.wikipedia.org/wiki/Hephaestus"
},
"Hera" : {
"wp": "https://en.wikipedia.org/wiki/Hera"
},
"Hermes" : {
"wp": "https://en.wikipedia.org/wiki/Hermes"
},
"Hestia" : {
"wp": "https://en.wikipedia.org/wiki/Hestia"
},
"Poseidon" : {
"wp": "https://en.wikipedia.org/wiki/Poseidon"
},
"Zeus" : {
"wp": "https://en.wikipedia.org/wiki/Zeus"
},
"Amaterasu" : {
"wp": "https://en.wikipedia.org/wiki/Amaterasu"
},
"Benzaiten" : {
"wp": "https://en.wikipedia.org/wiki/Benzaiten"
},
"Bishamonten" : {
"wp": "Bishamonten"
},
"Fūjin" : {
"wp": "https://en.wikipedia.org/wiki/F%C5%ABjin"
},
"Izanagi" : {
"wp": "https://en.wikipedia.org/wiki/Izanagi"
},
"Izanami" : {
"wp": "https://en.wikipedia.org/wiki/Izanami"
},
"Jurōjin" : {
"wp": "https://en.wikipedia.org/wiki/Jur%C5%8Djin"
},
"Oinari" : {
"wp": "https://en.wikipedia.org/wiki/Inari_%C5%8Ckami"
},
"Raijin" : {
"wp": "https://en.wikipedia.org/wiki/Raijin"
},
"Ryūjin" : {
"wp": "https://en.wikipedia.org/wiki/Raijin"
},
"Shōki" : {
"wp": "https://en.wikipedia.org/wiki/Zhong_Kui"
},
"Susanoo" : {
"wp": "https://en.wikipedia.org/wiki/Susanoo-no-Mikoto"
},
"Baldr" : {
"wp": "https://en.wikipedia.org/wiki/Baldr"
},
"Freyja" : {
"wp": "https://en.wikipedia.org/wiki/Freyja"
},
"Frigg" : {
"wp": "https://en.wikipedia.org/wiki/Frigg"
},
"Freyr" : {
"wp": "https://en.wikipedia.org/wiki/Freyr"
},
"Heimdallr" : {
"wp": "https://en.wikipedia.org/wiki/Heimdallr"
},
"Hel" : {
"wp": "https://en.wikipedia.org/wiki/Hel_(being)"
},
"Iðunn" : {
"wp": "https://en.wikipedia.org/wiki/I%C3%B0unn"
},
"Loki" : {
"wp": "https://en.wikipedia.org/wiki/Loki"
},
"Óðin" : {
"wp": "https://en.wikipedia.org/wiki/Odin"
},
"Skaði" : {
"wp": "https://en.wikipedia.org/wiki/Ska%C3%B0i"
},
"Sól" : {
"wp": "https://en.wikipedia.org/wiki/S%C3%B3l_(sun)"
},
"Thor" : {
"wp": "https://en.wikipedia.org/wiki/Thor"
},
"Bau" : {
"wp": "https://en.wikipedia.org/wiki/Nintinugga"
},
"Enki" : {
"wp": "https://en.wikipedia.org/wiki/Enki"
},
"Enlil" : {
"wp": "https://en.wikipedia.org/wiki/Enlil"
},
"Ereškigal" : {
"wp": "https://en.wikipedia.org/wiki/Ereshkigal"
},
"Inanna" : {
"wp": "https://en.wikipedia.org/wiki/Inanna"
},
"Iškur" : {
"wp": "https://en.wikipedia.org/wiki/Hadad"
},
"Nanãya" : {
"wp": "https://en.wikipedia.org/wiki/Nanaya"
},
"Narundi" : {
},
"Ningal" : {
"wp": "https://en.wikipedia.org/wiki/Ningal"
},
"Ninsumun" : {
"wp": "https://en.wikipedia.org/wiki/Ninsun"
},
"Ninurta" : {
"wp": "https://en.wikipedia.org/wiki/Ninurta"
},
"Utu" : {
"wp": "https://en.wikipedia.org/wiki/Utu"
},
"Cihuātēotl" : {
"wp": "https://en.wikipedia.org/wiki/Cihuateteo"
},
"Sphinx" : {
"wp": "https://en.wikipedia.org/wiki/Sphinx"
},
"Hydra" : {
"wp": "https://en.wikipedia.org/wiki/Lernaean_Hydra"
},
"Raiju" : {
"wp": "https://en.wikipedia.org/wiki/Raij%C5%AB"
},
"Valkyrie" : {
"wp": "https://en.wikipedia.org/wiki/Valkyrie"
},
"Anzû" : {
"wp": "https://en.wikipedia.org/wiki/Anz%C3%BB_(mythology)"
},
"Azathoth" : {
"wp": "https://en.wikipedia.org/wiki/Azathoth",
"lc": "http://lovecraft.wikia.com/wiki/Azathoth"
},
"Cthulhu" : {
"wp": "https://en.wikipedia.org/wiki/Cthulhu",
"lc": "http://lovecraft.wikia.com/wiki/Cthulhu"
},
"Father Dagon" : {
"wp": "https://en.wikipedia.org/wiki/Dagon_(Cthulhu_Mythos)",
"lc": "http://lovecraft.wikia.com/wiki/Dagon"
},
"Hastur" : {
"wp": "https://en.wikipedia.org/wiki/Hastur",
"lc": "http://lovecraft.wikia.com/wiki/Hastur"
},
"Hypnos" : {
"wp": "https://en.wikipedia.org/wiki/Hypnos",
"lc": "http://lovecraft.wikia.com/wiki/Hypnos"
},
"Mother Hydra" : {
"lc": "http://lovecraft.wikia.com/wiki/Hydra"
},
"Nyarlathotep" : {
"wp": "https://en.wikipedia.org/wiki/Nyarlathotep",
"lc": "http://lovecraft.wikia.com/wiki/Nyarlathotep"
},
"Yog-Sothoth" : {
"wp": "https://en.wikipedia.org/wiki/Yog-Sothoth",
"lc": "http://lovecraft.wikia.com/wiki/Yog-Sothoth"
},
"Deep One" : {
"wp": "https://en.wikipedia.org/wiki/Deep_One",
"lc": "http://lovecraft.wikia.com/wiki/Deep_One"
},
"Shoggoth" : {
"wp": "https://en.wikipedia.org/wiki/Shoggoth",
"lc": "http://lovecraft.wikia.com/wiki/Shoggoth"
},
"Arena of Eternity" : {
},
"Bifröst" : {
"wp": "https://en.wikipedia.org/wiki/Bifr%C3%B6st"
},
"Duat" : {
"wp": "https://en.wikipedia.org/wiki/Duat"
},
"Mount Olympus" : {
"wp": "https://en.wikipedia.org/wiki/Mount_Olympus"
},
"R'lyeh" : {
"wp": "https://en.wikipedia.org/wiki/R%27lyeh"
},
"Asteroid Impact" : {
"wp": "https://en.wikipedia.org/wiki/Asteroid_Impact"
},
"Avalanche" : {
"wp": "https://en.wikipedia.org/wiki/Avalanche"
},
"Blizzard" : {
"wp": "https://en.wikipedia.org/wiki/Blizzard"
},
"Drought" : {
"wp": "https://en.wikipedia.org/wiki/Drought"
},
"Firestorm" : {
"wp": "https://en.wikipedia.org/wiki/Firestorm"
},
"Ice Storm" : {
"wp": "https://en.wikipedia.org/wiki/Ice_storm"
},
"Maelstrom" : {
"wp": "https://en.wikipedia.org/wiki/Maelstrom"
},
"Sunblast" : {
},
"Tsunami" : {
"wp": "https://en.wikipedia.org/wiki/Tsunami"
},
"Volcanic Blast" : {
"wp": "https://en.wikipedia.org/wiki/Eruption"
},
"Wildfire" : {
"wp": "https://en.wikipedia.org/wiki/Wildfire"
},
"Prometheus" : {
"wp": "https://en.wikipedia.org/wiki/Prometheus"
}
}

View File

@ -1,6 +1,6 @@
{ {
"name": "@mysticbits/codex-mythica", "name": "@mysticbits/codex-mythica",
"version": "0.1.5", "version": "0.1.6",
"private": true, "private": true,
"scripts": { "scripts": {
"start": "nodejs ./bin/www" "start": "nodejs ./bin/www"

View File

@ -1,7 +1,24 @@
'use strict'; 'use strict';
var express = require('express'); const
var router = express.Router(); express = require('express'),
sortByName = function(list) {
let
coll_opts = {
sensitivity: 'accent',
numeric: true,
caseFirst: "upper"
},
coll = new Intl.Collator({}, coll_opts);
list.sort((a,b) => {
if (a[field] && b[field]) {
return coll.compare(a[field], b[field]);
}
return 1;
});
return list;
};
let router = express.Router();
/* GET home page. */ /* GET home page. */
router.get('/', function(req, res) { router.get('/', function(req, res) {
@ -12,11 +29,18 @@ router.get('/cards/:card_num', (req, res) => {
req.params.card_num = (req.params.card_num || 'all'); req.params.card_num = (req.params.card_num || 'all');
let let
cards = require('../lib/cards.json'), cards = require('../lib/cards.json'),
filtered = cards.filter(card => card.num.toLowerCase().indexOf(req.params.card_num.toLowerCase()) > -1 || req.params.card_num.toLowerCase() === 'all'); links = require('../lib/links.json'),
filtered = cards.filter(card =>
card.num.toLowerCase().indexOf(req.params.card_num.toLowerCase()) > -1 || req.params.card_num.toLowerCase() === 'all'
);
if (filtered.length === 1) { if (filtered.length === 1) {
res.render('single', { title: filtered[0].name + ' (' + filtered[0].num + ')', card: filtered[0] }); let card = filtered[0];
if (links && card.hasOwnProperty('name') && links.hasOwnProperty(card.name)) {
Object.assign(card, links[card.name]);
}
res.render('single', { title: card.name + ' (' + card.num + ')', card: card });
} else { } else {
filtered = sortByName(filtered);
res.render('all', { title: 'All Cards', cards: filtered }); res.render('all', { title: 'All Cards', cards: filtered });
} }
}); });
@ -25,5 +49,4 @@ router.get('/cards', function(req, res) {
res.redirect('/cards/all'); res.redirect('/cards/all');
}); });
module.exports = router; module.exports = router;

View File

@ -1,7 +1,32 @@
'use strict'; 'use strict';
var express = require('express');
var router = express.Router(); const
express = require('express'),
sortByField = function(field, order, list) {
field = (field || 'num');
order = (order || 'asc');
let
coll_opts = {
sensitivity: 'accent',
numeric: true,
caseFirst: "upper"
},
coll = new Intl.Collator({}, coll_opts);
list.sort((a,b) => {
if (a[field] && b[field]) {
let res = coll.compare(a[field], b[field]) * (order !== 'asc' ? -1 : 1);
if (res === 0 && field !== 'name') {
return coll.compare(a['name'], b['name']) * (order !== 'asc' ? -1 : 1);
}
return res;
}
return 1;
});
return list;
};
let router = express.Router();
/* GET search results page. */ /* GET search results page. */
router.get('/', function(req, res) { router.get('/', function(req, res) {
@ -23,89 +48,96 @@ router.get('/', function(req, res) {
q.races = Array.isArray(q.races) ? q.races : [q.races]; q.races = Array.isArray(q.races) ? q.races : [q.races];
q.releases = (q.releases || []); q.releases = (q.releases || []);
q.releases = Array.isArray(q.releases) ? q.releases : [q.releases]; q.releases = Array.isArray(q.releases) ? q.releases : [q.releases];
q.sort_by = (q.sort_by || 'num').trim().toLowerCase();
q.sort_order = (q.sort_order || 'asc').trim().toLowerCase();
console.log(`sort_by: ${q.sort_by}`);
filtered = cards.filter(card => { filtered = cards.filter(card => {
if (q.search_in.length > 0 && q.search_for.trim() !== '') { if (q.search_in.length > 0 && q.search_for.trim() !== '') {
if (!( if (!(
(q.search_in.indexOf('name') > -1 && (card.name.toLowerCase().indexOf(q.search_for) > -1 || card.name_ang.indexOf(q.search_for) > -1)) || (q.search_in.indexOf('name') > -1 && (card.name.toLowerCase().indexOf(q.search_for) > -1 || card.name_ang.indexOf(q.search_for) > -1)) ||
(q.search_in.indexOf('ability') > -1 && (card.ability_name.toLowerCase().indexOf(q.search_for) > -1 || card.ability_text.toLowerCase().indexOf(q.search_for) > -1)))) { (q.search_in.indexOf('ability') > -1 && (card.ability_name.toLowerCase().indexOf(q.search_for) > -1 || card.ability_text.toLowerCase().indexOf(q.search_for) > -1)))) {
return false;
}
}
if (q.pantheons.length > 0 && card.pantheon) {
let
has_pantheon = false;
for (let i=0; i < q.pantheons.length; i++) {
if (card.pantheon_idx.indexOf(q.pantheons[i]) > -1) {
has_pantheon = true;
}
}
if (!has_pantheon) {
return false; return false;
} }
}
} if (q.elements.length > 0) {
let
if (q.pantheons.length > 0 && card.culture !== '') { has_element = false;
let for (let i=0; i < q.elements.length; i++) {
has_pantheon = false; if (card.element_idx.indexOf(q.elements[i]) > -1) {
for (let i=0; i < q.pantheons.length; i++) { has_element = true;
if (card.culture_idx.indexOf(q.pantheons[i]) > -1) { }
has_pantheon = true; }
if (!has_element) {
return false;
} }
} }
if (!has_pantheon) {
return false;
}
}
if (q.elements.length > 0) { if (q.races.length > 0 && card.race) {
let let
has_element = false; has_race = false;
for (let i=0; i < q.elements.length; i++) { for (let i=0; i < q.races.length; i++) {
if (card.element_idx.indexOf(q.elements[i]) > -1) { if (card.race_idx.indexOf(q.races[i]) > -1) {
has_element = true; has_race = true;
}
}
if (!has_race) {
return false;
} }
} }
if (!has_element) {
return false;
}
}
if (q.races.length > 0 && card.race !== '') { if (q.types.length > 0) {
let let
has_race = false; has_type = false;
for (let i=0; i < q.races.length; i++) { for (let i=0; i < q.types.length; i++) {
if (card.race_idx.indexOf(q.races[i]) > -1) { if (card.type_idx.indexOf(q.types[i]) > -1) {
has_race = true; has_type = true;
}
}
if (!has_type) {
return false;
} }
} }
if (!has_race) {
return false;
}
}
if (q.types.length > 0) { if (q.releases.length > 0) {
let let
has_type = false; has_release = false;
for (let i=0; i < q.types.length; i++) { for (let i=0; i < q.releases.length; i++) {
if (card.type_idx.indexOf(q.types[i]) > -1) { if (card.num.toLowerCase().indexOf(q.releases[i]) > -1) {
has_type = true; has_release = true;
}
}
if (!has_release) {
return false;
} }
} }
if (!has_type) {
return false;
}
}
if (q.releases.length > 0) {
let
has_release = false;
for (let i=0; i < q.releases.length; i++) {
if (card.num.toLowerCase().indexOf(q.releases[i]) > -1) {
has_release = true;
}
}
if (!has_release) {
return false;
}
}
return true;
});
return true;
});
if (q.sort_by !== 'name') {
filtered = sortByField('name', q.sort_order, filtered);
}
filtered = sortByField(q.sort_by, q.sort_order, filtered);
} }
res.render('search', { title: 'Search Results', query: req.query, cards: filtered }); res.render('search', { title:`Search Results (${filtered.length})`, query: req.query, cards: filtered });
}); });
module.exports = router; module.exports = router;

View File

@ -23,10 +23,10 @@
<dt>Release</dt> <dt>Release</dt>
<dd><%- release_map[card.num.toLowerCase().substr(0,4)] %></dd> <dd><%- release_map[card.num.toLowerCase().substr(0,4)] %></dd>
<% if (card.culture !== '') { %> <% if (card.pantheon !== '') { %>
<dt>Pantheon</dt> <dt>Pantheon</dt>
<dd><img class="card-pantheon" src="/images/pantheons/<%= card.culture.toLowerCase().replace(' ','-') %>.png" <dd><img class="card-pantheon" src="/images/pantheons/<%= card.pantheon.toLowerCase().replace(' ','-') %>.png"
alt="<%= card.culture %>" /></dd> alt="<%= card.pantheon %>" /></dd>
<% } %> <% } %>
@ -108,6 +108,18 @@
<dt>Flavor</dt> <dt>Flavor</dt>
<dd><em><%- card.flavor %></em></dd> <dd><em><%- card.flavor %></em></dd>
<% } %> <% } %>
<% if ((card.wp && card.wp !== '') || (card.lc && card.lc !== '')) { %>
<dt>Learn More</dt>
<dd>
<% if (card.wp && card.wp !== '') { %>
<a href='<%-card.wp%>' title="Wikipedia link for <%=card.name%>">Wikipedia</a>
<% } %>
<% if (card.lc && card.lc !== '') { %>
<a href='<%-card.lc%>' title="Lovecraft Wiki link for <%=card.name%>">Lovecraft Wiki</a>
<% } %>
</dd>
<% } %>
<dt>Copyright</dt> <dt>Copyright</dt>
<dd>&copy; <%= card.copyright_year %> <%= card.copyright_owner %></dd> <dd>&copy; <%= card.copyright_year %> <%= card.copyright_owner %></dd>
</dl> </dl>

View File

@ -8,9 +8,9 @@
<div> <div>
<a href="/cards/<%= card.num.toLowerCase() %>"><%= card.name %> <a href="/cards/<%= card.num.toLowerCase() %>"><%= card.name %>
<% if (card.culture !== '') { %> <% if (card.pantheon !== '') { %>
<img class="preview-pantheon" src="/images/pantheons/<%= card.culture.toLowerCase().replace(' ','-') %>.png" <img class="preview-pantheon" src="/images/pantheons/<%= card.pantheon.toLowerCase().replace(' ','-') %>.png"
alt="<%= card.culture %>" /> alt="<%= card.pantheon %>" />
<% } %> <% } %>
<%= card.num.toUpperCase() %></a><br /> <%= card.num.toUpperCase() %></a><br />
<% if (card.race != '') { %> <% if (card.race != '') { %>

View File

@ -251,9 +251,49 @@
</li> </li>
</ul> </ul>
</li> </li>
<li>
<label for='sort_by'>Sort By</label>
<ul>
<li>
<label>
<select name='sort_by'>
<option value='name'
<%- query && ((query.sort_by && query.sort_by === 'name') || !query.sort_by) ? "selected='selected'" : '' %>>Name</option>
<option value='num'
<%- query && (query.sort_by && query.sort_by === 'num') ? "selected='selected'" : '' %>>Card Number</option>
<option value='attack'
<%- query && (query.sort_by && query.sort_by === 'attack') ? "selected='selected'" : '' %>>Attack</option>
<option value='defense'
<%- query && (query.sort_by && query.sort_by === 'defense') ? "selected='selected'" : '' %>>Defense</option>
<option value='power'
<%- query && (query.sort_by && query.sort_by === 'power') ? "selected='selected'" : '' %>>Power</option>
<option value='pantheon'
<%- query && (query.sort_by && query.sort_by === 'pantheon') ? "selected='selected'" : '' %>>Pantheon</option>
<option value='race'
<%- query && (query.sort_by && query.sort_by === 'race') ? "selected='selected'" : '' %>>Race</option>
<option value='type'
<%- query && (query.sort_by && query.sort_by === 'type') ? "selected='selected'" : '' %>>Type</option>
</select>
</label>
</li>
<li>
<label>
<input type='radio' name='sort_order' value='asc'
<%- query && ((query.sort_order && query.sort_order === 'asc') || !query.sort_order) ? "checked='checked'" : '' %>
/>&nbsp;Ascending
</label>
</li>
<li>
<label>
<input type='radio' name='sort_order' value='asc'
<%- query && (query.sort_order && query.sort_order === 'desc') ? "checked='checked'" : '' %>
/>&nbsp;Descending
</label>
</li>
</ul>
</li>
</ul> </ul>
</fieldset> </fieldset>
<fieldset class='searchForm-controlSet'> <fieldset class='searchForm-controlSet'>
<legend>Controls</legend> <legend>Controls</legend>