Commit 8d9db859 authored by Eliot Berriot's avatar Eliot Berriot

Merge branch 'release/0.2.2'

parents 8706f7df 14cfe3e0
Pipeline #184 passed with stages
in 43 seconds
......@@ -17,6 +17,7 @@ module.exports = {
],
// add your custom rules here
'rules': {
'import/no-webpack-loader-syntax': "off",
// allow paren-less arrow functions
'arrow-parens': 0,
// allow async-await
......
......@@ -28,6 +28,10 @@ module.exports = {
},
module: {
rules: [
{
test: /\.worker\.js$/,
use: { loader: 'worker-loader' }
},
{
test: /\.(js|vue)$/,
loader: 'eslint-loader',
......
......@@ -88,7 +88,6 @@
"version": "5.2.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.3.tgz",
"integrity": "sha1-wG9Zh3jETGsWGrr+NGa4GtGBTtI=",
"dev": true,
"requires": {
"co": "4.6.0",
"fast-deep-equal": "1.0.0",
......@@ -1203,8 +1202,7 @@
"big.js": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
"integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==",
"dev": true
"integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q=="
},
"binary-extensions": {
"version": "1.10.0",
......@@ -1729,8 +1727,7 @@
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
"dev": true
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"coa": {
"version": "1.0.4",
......@@ -2765,8 +2762,7 @@
"emojis-list": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
"dev": true
"integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
},
"encodeurl": {
"version": "1.0.1",
......@@ -3651,8 +3647,7 @@
"fast-deep-equal": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=",
"dev": true
"integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8="
},
"fast-levenshtein": {
"version": "2.0.6",
......@@ -3939,6 +3934,11 @@
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
"dev": true
},
"fuzzysearch": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/fuzzysearch/-/fuzzysearch-1.0.3.tgz",
"integrity": "sha1-3/yA9tawQiPyImqnndGUIxCW0Ag="
},
"generate-function": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
......@@ -5000,14 +5000,12 @@
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
"dev": true
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"json-stable-stringify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
"dev": true,
"requires": {
"jsonify": "0.0.0"
}
......@@ -5027,8 +5025,7 @@
"json5": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
},
"jsonfile": {
"version": "4.0.0",
......@@ -5042,8 +5039,7 @@
"jsonify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
"dev": true
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
},
"jsonpointer": {
"version": "4.0.1",
......@@ -5386,7 +5382,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
"integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
"dev": true,
"requires": {
"big.js": "3.2.0",
"emojis-list": "2.1.0",
......@@ -6620,11 +6615,6 @@
}
}
},
"pako": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
"integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg=="
},
"param-case": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
......@@ -9664,7 +9654,6 @@
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz",
"integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=",
"dev": true,
"requires": {
"ajv": "5.2.3"
}
......@@ -9788,6 +9777,11 @@
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
"dev": true
},
"simple-web-worker": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/simple-web-worker/-/simple-web-worker-1.2.0.tgz",
"integrity": "sha1-Le/9CZiXa4JLFBonzlBNMdDZkQg="
},
"sinon": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-4.0.1.tgz",
......@@ -10777,6 +10771,11 @@
"integrity": "sha512-Hn0jdFiNfNx4+Nxz1vokYUsP3mwpn9r/XomLrXA+KafYaiR7LNQG1fxtpVklD4KxD5GluXRiSoWNDf0H9BdsJw==",
"dev": true
},
"vue-lazyload": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/vue-lazyload/-/vue-lazyload-1.1.3.tgz",
"integrity": "sha1-UnoePmumUJ/icybTTwq5aHyaHpU="
},
"vue-loader": {
"version": "13.3.0",
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-13.3.0.tgz",
......@@ -10829,6 +10828,14 @@
"integrity": "sha512-x3LV3wdmmERhVCYy3quqA57NJW7F3i6faas++pJQWtknWT+n7k30F4TVdHvCLn48peTJFRvCpxs3UuFPqgeELg==",
"dev": true
},
"vue-worker": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/vue-worker/-/vue-worker-1.2.1.tgz",
"integrity": "sha1-3q4UuYqdidqrsg5/xhkGQoSbbZM=",
"requires": {
"simple-web-worker": "1.2.0"
}
},
"watchpack": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz",
......@@ -11175,6 +11182,15 @@
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
"worker-loader": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-1.0.0.tgz",
"integrity": "sha512-dUwgs4Rdi1qG3VciM1+EPgAoO8m9USpCXxE3xmpWrnHJSMKGkzpCUNeYLjBRgYcSkf2A5xnXpR450Wqtu+pq0w==",
"requires": {
"loader-utils": "1.1.0",
"schema-utils": "0.3.0"
}
},
"wrap-ansi": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
......
......@@ -14,11 +14,15 @@
"lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
},
"dependencies": {
"fuzzysearch": "^1.0.3",
"jquery": "^3.2.1",
"lz-string": "^1.4.4",
"semantic-ui-css": "^2.2.12",
"vue": "^2.4.2",
"vue-router": "^2.7.0"
"vue-lazyload": "^1.1.3",
"vue-router": "^2.7.0",
"vue-worker": "^1.2.1",
"worker-loader": "^1.0.0"
},
"devDependencies": {
"autoprefixer": "^7.1.2",
......
......@@ -8,36 +8,53 @@
</div>
</div>
<div v-else class="ui grid">
<div class="four wide column">
<div class="three wide column">
<h2>Filters</h2>
<div class="ui form filters">
<div class="ui field">
<h3 class="ui header">Ordering</h3>
<div>
<input
type="checkbox"
id="ordering-direction"
v-model="sortAscending">
<label for="ordering-direction">Sort in ascending order </label>
<div class="ui form">
<div class="ui segments">
<div class="ui segment">
<h3 class="ui header">Ordering</h3>
<div class="ui field">
<select v-model="sortField" class="ui fluid dropdown">
<option v-for="field in sortFields" :value="field.id">{{ field.label }}</option>
</select>
</div>
<select v-model="sortField">
<option v-for="field in sortFields" :value="field.id">{{ field.label }}</option>
</select>
</div>
<div class='ui field'>
<h3 class="ui header">Object class</h3>
<div class="all-toggle">
<input
type="checkbox"
@change="toggleAll('objectClass')"
id="objectclass-toggle-all"
:checked="filtersById.objectClass.choices.length === filtersById.objectClass.selected.length">
<label for="objectclass-toggle-all">Select all</label>
<div class="ui inline field">
<input
type="checkbox"
id="ordering-direction"
class="hidden"
v-model="sortAscending">
<label for="ordering-direction">Sort in ascending order </label>
</div>
</div>
<div class="ui segment">
<h3 class="ui header">Search</h3>
<div class="ui icon input">
<i class="search icon"></i>
<input
type="text"
id="search"
placeholder="666, Red ice, clown, shadow..."
v-model="filtersById.search.query">
</div>
</div>
<div class="choices">
<div class="choice" v-for="choice in filtersById.objectClass.choices">
<input type="checkbox" :id="'objectclass' + choice.id" :value="choice.id" v-model="filtersById.objectClass.selected">
<label :for="'objectclass' + choice.id">{{ choice.label }}</label>
<div class='ui segment'>
<h3 class="ui header">Object class</h3>
<div class="inline field">
<input
type="checkbox"
@change="toggleAll('objectClass')"
id="objectclass-toggle-all"
:checked="filtersById.objectClass.choices.length === filtersById.objectClass.selected.length">
<label for="objectclass-toggle-all">Select all</label>
</div>
<div class="choices">
<div class="inline field" v-for="choice in filtersById.objectClass.choices">
<input type="checkbox" :id="'objectclass' + choice.id" :value="choice.id" v-model="filtersById.objectClass.selected">
<span :class="['ui', getObjectClassColor(choice.id), 'empty', 'circular', 'label']"></span>
<label :for="'objectclass' + choice.id">{{ choice.label }}</label>
</div>
</div>
</div>
</div>
......@@ -47,7 +64,7 @@
<h1>{{ filteredScps.length }} SCPs matching your criteria</h1>
<div class="ui link stackable fluid cards">
<div v-for="scp in filteredScps.slice(0, 100)" class="card">
<div v-if="scp.images[0]" class="ui small image" :style="{'background-image': 'url(' + scp.images[0].src + ')'}"></div>
<div v-if="scp.images[0]" class="ui small image" v-lazy:background-image="scp.images[0].src"></div>
<div v-else class="ui small image no-image"></div>
<div class="content">
<div class="header ellipsis">
......@@ -56,7 +73,7 @@
<div class="meta">
<span>
<i :class="['ui', 'warning circle', getObjectClassColor(scp.object_class), 'icon']"></i>
{{ scp.object_class.label }}
{{ scpData.data.object_classes[scp.object_class].label }}
</span>
<span>
<i class="comments icon"></i> {{ scp.comments }}
......@@ -82,12 +99,15 @@
<script>
import scpData from '@/scp-data'
import fuzzysearch from 'fuzzysearch'
import $ from 'jquery'
export default {
data () {
// let self = this
let self = this
let d = {
scpData,
searchQuery: '',
sortAscending: true,
sortField: 'id',
sortFields: [
......@@ -118,18 +138,8 @@ export default {
choices: [],
selected: [],
init: function (scps) {
let choices = scps.map(e => {
return e.object_class
})
let seenIds = []
this.choices = choices.filter(e => {
// deduplicating chociecs
let seen = seenIds.indexOf(e.id) > -1
if (seen) {
return false
}
seenIds.push(e.id)
return true
this.choices = Object.keys(self.scpData.data.object_classes).map(e => {
return self.scpData.data.object_classes[e]
})
this.selected = this.choices.map(e => {
return e.id
......@@ -141,7 +151,29 @@ export default {
match: function (scp) {
for (var i = 0; i < this.selected.length; i++) {
let s = this.selected[i]
if (scp.object_class.id === s) {
if (scp.object_class === s) {
return true
}
}
}
},
{
id: 'search',
query: '',
searchFields: ['name', 'object_class'],
init: function (scps) {},
apply: function () {
return this.query.length > 0
},
match: function (scp) {
let id = parseInt(this.query, '10')
if (!isNaN(id) & scp.id === id) {
return true
}
let length = this.searchFields.length
for (var i = 0; i < length; i++) {
let f = this.searchFields[i]
if (fuzzysearch(this.query, scp[f].toLowerCase())) {
return true
}
}
......@@ -157,28 +189,35 @@ export default {
},
mounted: function () {
this.scpData.load()
$(this.$el).find('.ui.checkbox').checkbox()
$(this.$el).find('.ui.dropdown').dropdown()
},
methods: {
getObjectClassColor: function (objectClass) {
let colors = {
'null': 'grey',
'anomalous': 'black',
'null': 'black',
'safe': 'teal',
'euclid': 'orange',
'keter': 'red',
'thaumiel': 'purple',
'neutralized': 'green'
'pending': 'yellow',
'neutralized': 'green',
'hiemal': 'blue'
}
return colors[objectClass.id]
let color = colors[objectClass]
if (!color) {
color = 'grey'
}
return color
},
matchFilters: function (scp) {
for (var i = 0; i < this.filters.length; i++) {
let filter = this.filters[i]
if (filter.apply() && !filter.match(scp)) {
matchFilters: function (scp, filters) {
for (var i = 0; i < filters.length; i++) {
let filter = filters[i]
if (!filter.match(scp)) {
return false
}
return true
}
return true
},
toggleAll: function (filter) {
let f = this.filtersById[filter]
......@@ -192,8 +231,12 @@ export default {
computed: {
filteredScps: function () {
let self = this
let filtered = this.scpData.data.scps.filter(e => {
return self.matchFilters(e)
let candidates = this.scpData.data.scps
let filters = this.filters.filter(e => {
return e.apply()
})
let filtered = candidates.filter(e => {
return self.matchFilters(e, filters)
})
let sorted = filtered.sort((a, b) => {
return a[self.sortField] - b[self.sortField]
......
......@@ -3,11 +3,13 @@
import Vue from 'vue'
import App from './App'
import router from './router'
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)
Vue.config.productionTip = false
window.$ = window.jQuery = require('jquery')
require('semantic-ui-css/semantic.css')
require('semantic-ui-css/semantic.js')
require('./semantic-ui-css/semantic.css')
/* eslint-disable no-new */
new Vue({
......
import $ from 'jquery'
import Vue from 'vue'
import LZString from 'lz-string'
import Worker from 'worker-loader!./worker.js'
const cacheWorker = new Worker()
cacheWorker.onmessage = (event) => {
try {
localStorage.setItem('scpData', JSON.stringify({'data': event.data.data}))
console.log('Localstorage updated!')
} catch (e) {
console.error('Cannot store data in local storage', e)
}
}
var scpData = {
loading: false,
caching: false,
data: {
scps: [],
object_classes: {}
},
toCache: function () {
console.log('Putting data into cache...')
let uncompressedData = JSON.stringify(this.data)
let compressed = LZString.compress(uncompressedData)
localStorage.setItem('scpData', JSON.stringify({'data': compressed}))
console.log('cache updated!')
cacheWorker.postMessage({ action: 'cache', data: this.data })
},
restoreCache: function () {
let compressed = localStorage.getItem('scpData')
......@@ -33,7 +43,7 @@ var scpData = {
}
$.ajax({
url,
type: 'GET',
type: 'OPTIONS',
headers: {
'If-Range': 'nope' // disable partial resource (206)
},
......@@ -43,11 +53,7 @@ var scpData = {
let r = JSON.parse(response)
self.data = r
self.loading = false
try {
self.toCache()
} catch (e) {
console.log('Cannot put data into the cache, sorry', e)
}
self.toCache()
},
error: response => {
console.error('Error while fetching data!')
......
This diff is collapsed.
This source diff could not be displayed because it is too large. You can view the blob instead.
import LZString from 'lz-string'
function compress (data) {
var LZString = require('lz-string')
console.log('Compressing data before caching...')
let compressed = LZString.compress(JSON.stringify(data))
self.postMessage({data: compressed})
}
self.addEventListener('message', (event) => {
if (event.data.action === 'cache') {
compress(event.data.data)
}
})
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment