Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bileşik Önerileri #19

Closed
wants to merge 10 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,5 @@ ecosystem.config.js

# SQL files
db.sql

.vscode/
141 changes: 141 additions & 0 deletions components/RightSideBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@
</swiper>
</div>
</div>
<div v-if="suggestedCompounds.length > 0" class="suggestion-area">
<div v-for="compound in suggestedCompounds" :key="compound.formula" v-fcf class="compound-suggestion" @click="setElementsByFormula(compound.formula)">
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Buradaki click eventi icin test yazabilir misin?

{{ compound.formula }}
</div>
</div>
<div v-if="foundCompound && foundCompound.formula" class="wrapper" style="color: white">
<canvas id="smiley" width="200" height="80"></canvas>
<div class="row">
Expand Down Expand Up @@ -157,6 +162,7 @@ export default {
foundCompound: {
dtp_names: [],
},
suggestedCompounds: [],
loadingInstance: null,
timeoutCheck: null,
}
Expand Down Expand Up @@ -203,6 +209,38 @@ export default {
this.$store.commit('SET_PROBABLE_ELEMENTS', [])
},
methods: {
parseCompoundFormula(formula) {
/**
* Group 1: The upper case letter of the symbol (e.g. "N" for Na). All symbols have
* 1 and only 1 upper case letter; which is always the first character.
* Group 2: The remaining lower case letter(s) if there are any.
* Group 3: Element count (if specified) (e.g. "2" for O2)
*/
const regex = /([A-Z])([a-z]*)(\d*)/g
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Buna test yazabilir misin?

const compoundSymbols = []
let match

while ((match = regex.exec(formula)) !== null) {
const [, symbolUpperCaseChar, symbolLowerCaseChars, symbolCount] = match
compoundSymbols.push({
symbol: `${symbolUpperCaseChar}${symbolLowerCaseChars}`,
count: symbolCount ? Number(symbolCount) : 1,
})
}

return compoundSymbols
},
getElementBySymbol(symbol) {
return this.$store.getters.elements.find((e) => e.symbol === symbol)
},
setElementsByFormula(formula) {
this.elements = this.parseCompoundFormula(formula).map(({ symbol, count }) => {
return {
count,
...this.getElementBySymbol(symbol),
}
})
},
getAvailableElements(elements) {
this.loadingInstance = Loading.service({ background: 'rgba(0, 0, 0, 0.7)', lock: true })
this.foundCompound = {
Expand All @@ -221,6 +259,52 @@ export default {
const availableCompoundElements = []
const finalized = []

// this holds the suggestions with exact count matches
const primaryCompoundSuggestions = new Map()

// this holds a loose match; will match the atoms (symbols) only
const secondaryCompoundSuggestions = new Map()

const primaryRegExps = elements.map((element) => {
if (element.count > 1) {
// if there are more than 1 atoms, filter the compounds accordingly
return new RegExp(`${element.symbol}${element.count}`)
}

// if there is only one atom, perform a negative look-ahead search to filter out compounds with multiple counts
return new RegExp(`${element.symbol}(?![a-f0-9])`)
})
const secondaryRegExps = elements.map((e) => new RegExp(`${e.symbol}${e.count === 1 ? '' : e.count}`))

const performMatch = (compound, regexps, map) => {
let compoundHasAllElements = true

for (const regex of regexps) {
if (!regex.test(compound.formula)) {
compoundHasAllElements = false
break
}
}

if (compoundHasAllElements) {
if (map.size < 5) {
map.set(compound.formula, compound)
} else {
let longestFormula = ''
for (const key of map.keys()) {
if (longestFormula.length < key.length) {
longestFormula = key
}
}

if (compound.formula.length < longestFormula.length) {
map.delete(longestFormula)
map.set(compound.formula, compound)
}
}
}
}

compounds.forEach((compound) => {
let symbol = ''
let count = ''
Expand All @@ -246,6 +330,14 @@ export default {
pushAvailableElement(index)
})
availableCompoundElements.push(availableElements)

const forbidden = compound.formula.includes('?')

if (!forbidden) {
performMatch(compound, primaryRegExps, primaryCompoundSuggestions)
performMatch(compound, secondaryRegExps, secondaryCompoundSuggestions)
}

function pushAvailableElement(index) {
if (chars.length - 1 === index) {
availableElements.push({
Expand All @@ -256,6 +348,31 @@ export default {
}
})

while (primaryCompoundSuggestions.size < 5) {
const [key, value] = secondaryCompoundSuggestions.entries().next().value
secondaryCompoundSuggestions.delete(key)
primaryCompoundSuggestions.set(key, value)

if (secondaryCompoundSuggestions.size === 0) {
break
}
}

const suggestedCompounds = Array.from(primaryCompoundSuggestions.values())
suggestedCompounds.sort((a, b) => a.formula.length - b.formula.length)

// filter out the current compound formula from the suggestions (since it is already being shown)
this.suggestedCompounds = suggestedCompounds.filter((suggestion) => {
let { formula } = suggestion

for (const element of elements) {
const re = new RegExp(`[A-Z0-9]?${element.symbol}${element.count === 1 ? '' : element.count}`)
formula = formula.replace(re, '')
}

return formula.length
})

let exactCompound = null
availableCompoundElements.forEach((availableElements) => {
let isValidCompound = true
Expand Down Expand Up @@ -511,4 +628,28 @@ export default {
}
}
}

.suggestion-area {
display: flex;
width: 20vw;
flex-wrap: wrap;
gap: 5px;
justify-content: center;
margin-top: 30px;

.compound-suggestion {
background: linear-gradient(136deg, #272f3f 0%, #1d232f 100%);
padding: 7px 22px;
border-radius: 4px;
user-select: none;
cursor: pointer;
color: #fff;
opacity: 0.7;
transition: opacity 0.3s ease;

&:hover {
opacity: 1;
}
}
}
</style>
1 change: 1 addition & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
moduleNameMapper: {
'\\.(css|scss)$': '<rootDir>/tests/__mocks__/styleMock.js',
'^@/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js',
Expand Down
1 change: 1 addition & 0 deletions nuxt.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ module.exports = {
{ src: '~/plugins/element-ui', ssr: false },
{ src: '~/plugins/vue-gtag.js', ssr: false, mode: 'client' },
{ src: '~/plugins/vue-sanitize', ssr: false },
{ src: '~/plugins/directives', ssr: false },
],

// Auto import components: https://go.nuxtjs.dev/config-components
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
"@testing-library/jest-dom": "^5.16.1",
"@testing-library/user-event": "^13.5.0",
"@testing-library/vue": "^5.8.2",
"@vue/test-utils": "^1.3.0",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "^10.1.0",
"babel-jest": "^26",
Expand Down
7 changes: 7 additions & 0 deletions plugins/directives.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import Vue from 'vue'

Vue.directive('fcf', {
inserted(el) {
el.innerHTML = el.innerHTML.replace(/(\d+)/g, `<sub>$1</sub>`)
},
})
77 changes: 77 additions & 0 deletions tests/__mocks__/store/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export const getters = {
elements: jest.fn().mockReturnValue([]),
temperature: jest.fn().mockReturnValue(100),
compounds: jest.fn().mockReturnValue([]),
isotopes: jest.fn().mockReturnValue([]),
probableElements: jest.fn().mockReturnValue([]),
isIsotopeFetched: jest.fn().mockReturnValue(true),
isCompoundFetched: jest.fn().mockReturnValue(true),
isMobile: jest.fn().mockReturnValue(false),
isOriented: jest.fn().mockReturnValue(false),
}

export const mutations = {
UPDATE_TEMPERATURE: jest.fn(),
UPDATE_VIEW_TEMPERATURE: jest.fn(),
DEACTIVATE_TEMPERATURE: jest.fn(),
SET_TEMPERATURE_TYPE: jest.fn(),
SET_ELEMENTS: jest.fn(),
SET_COMPOUNDS: jest.fn(),
SET_ISOTOPES: jest.fn(),
SET_PROBABLE_ELEMENTS: jest.fn(),
SET_COMPOUNDS_FETCHED: jest.fn(),
SET_ISOTOPES_FETCHED: jest.fn(),
SHOW_INFO_MODAL: jest.fn(),
SET_SELECTED_CONTENT_ID: jest.fn(),
SET_SEARCH_TEXT: jest.fn(),
SET_IS_MOBILE: jest.fn(),
SET_IS_ORIENTED: jest.fn(),
}

export const actions = {}

export const state = {
app: {},
elements: [],
compounds: [],
isotopes: [],
probableElements: [],
temperature: 0,
selectedTemperatureType: 'c',
isTemperatureTriggered: false,
isIsotopeFetched: false,
isCompoundFetched: false,
showInfoModal: false,
selectedContentId: null,
searchText: null,
isMobile: false,
isOriented: false,
}

// eslint-disable-next-line no-underscore-dangle
export function __createMocks(custom = { getters: {}, mutations: {}, actions: {}, state: {} }) {
const mockGetters = Object.assign({}, getters, custom.getters)
const mockMutations = Object.assign({}, mutations, custom.mutations)
const mockActions = Object.assign({}, actions, custom.actions)
const mockState = Object.assign({}, state, custom.state)

return {
getters: mockGetters,
mutations: mockMutations,
actions: mockActions,
state: mockState,
store: new Vuex.Store({
getters: mockGetters,
mutations: mockMutations,
actions: mockActions,
state: mockState,
}),
}
}

export const store = __createMocks().store
1 change: 1 addition & 0 deletions tests/__mocks__/styleMock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = {}
31 changes: 31 additions & 0 deletions tests/components/CompoundSuggestion.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { createLocalVue } from '@vue/test-utils'
import { render } from '@testing-library/vue'
import Vuex from 'vuex'
// eslint-disable-next-line
import { __createMocks as createStoreMocks } from '../__mocks__/store'
import RightSideBar from '@/components/RightSideBar.vue'

jest.mock('../../store')

const localVue = createLocalVue()
localVue.use(Vuex)

describe('Compound Suggestion', () => {
let storeMocks

beforeEach(() => {
storeMocks = createStoreMocks()
render(RightSideBar, {
store: storeMocks.store,
localVue,
})
})

it('parses compound formula', () => {
// TODO: Write the body
})

it('loads compound formula after clicking on a sugestion', () => {
// TODO: Write the body
})
})
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2365,7 +2365,7 @@
optionalDependencies:
prettier "^1.18.2 || ^2.0.0"

"@vue/test-utils@^1.1.0":
"@vue/test-utils@^1.1.0", "@vue/test-utils@^1.3.0":
version "1.3.0"
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.3.0.tgz#d563decdcd9c68a7bca151d4179a2bfd6d5c3e15"
integrity sha512-Xk2Xiyj2k5dFb8eYUKkcN9PzqZSppTlx7LaQWBbdA8tqh3jHr/KHX2/YLhNFc/xwDrgeLybqd+4ZCPJSGPIqeA==
Expand Down