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

Refactor: Entity Variable Restructure #21

Merged
merged 24 commits into from
Feb 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
5b6bb76
refactor: make isNativeVariable a helper
jorenrui Feb 27, 2024
af54dbb
refactor: relocate ignored ids to lexer
jorenrui Feb 27, 2024
a693e66
refactor: rename this.base to this.entity
jorenrui Feb 27, 2024
b85ca1d
fix: entity undefined in events
jorenrui Feb 27, 2024
115c6e7
chore: setup path alias
jorenrui Feb 27, 2024
3dad3e1
refactor: use alias imports
jorenrui Feb 27, 2024
d83ba95
refactor: extract variables logic from entity
jorenrui Feb 27, 2024
b91a66d
refactor: relocate state of variables
jorenrui Feb 27, 2024
3f25d2a
fix: group variables not working
jorenrui Feb 27, 2024
df4c0a2
refactor: expose main on debug true
jorenrui Feb 27, 2024
db507b2
feat: track variables per entity attribute
jorenrui Feb 27, 2024
0a1cfbd
fix: check if region is selected
jorenrui Feb 27, 2024
39866e6
refactor: update usage of attribute variables and attach helpers
jorenrui Feb 27, 2024
200e85f
optimization: only re-evaluate relevant attributes on state update
jorenrui Feb 27, 2024
d1ca1a0
feat: dispose attributes and events on observer remove attribute
jorenrui Feb 27, 2024
3c6054e
docs: relocate installation steps
jorenrui Feb 27, 2024
f42c86c
refactor: update text in changing id demo
jorenrui Feb 27, 2024
757e3f7
feat: initialize variables on attribute change
jorenrui Feb 27, 2024
23f7e52
optimize: grouped usage of new Set
jorenrui Feb 27, 2024
f033eca
fix: missing group variables
jorenrui Feb 27, 2024
101a6de
Merge branch 'jr.refactor/group-variables' into jr.refactor/entity-va…
jorenrui Feb 27, 2024
1f820e5
refactor: update variable checker and waiting for promises
jorenrui Feb 27, 2024
7e018d6
fix: update isNativeVariable checker
jorenrui Feb 27, 2024
bcb1765
fix: missing async await for state.evaluate promise
jorenrui Feb 27, 2024
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
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
# MiniJS

## Installation

To setup MiniJS in your local machine, you can do the following:

1. Clone the [repository](https://github.com/Group-One-Technology/minijs).
2. Run `yarn` to install dependencies.
3. Run `yarn build` to create the `dist` folder -> output for MiniJS.
4. Run `yarn dev` to run the demo page locally.
5. Run `yarn build-watch` on another terminal to build the code whenever the Mini.js code changes.
6. Run `yarn test` to run the tests.

## The Idea

- HTML is great because it's easy to learn and extremely accessible. But HTML has shortcomings when it comes to building interfaces with interactivity.
Expand All @@ -22,6 +11,17 @@ To setup MiniJS in your local machine, you can do the following:

Read the [documentation](https://jorenrui.notion.site/Mini-js-7a51523e0a5845c782097782f49a5bae?pvs=74)

## Installation

To setup MiniJS in your local machine, you can do the following:

1. Clone the [repository](https://github.com/Group-One-Technology/minijs).
2. Run `yarn` to install dependencies.
3. Run `yarn build` to create the `dist` folder -> output for MiniJS.
4. Run `yarn dev` to run the demo page locally.
5. Run `yarn build-watch` on another terminal to build the code whenever the Mini.js code changes.
6. Run `yarn test` to run the tests.

## Setting State

`State` are variables that changes the UI or the DOM that uses it when they get updated.
Expand Down
2 changes: 1 addition & 1 deletion demo/observer.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<li>
<button
:click="this.parentNode.parentNode.removeChild(this.parentNode)"
:text="`my id is ${this.getAttribute('id')} (hover me to change) list item (click to delete)`"
:text="`look at my id list item (click to delete)`"
:mouseenter="el.isHovered = true"
:mouseleave="el.isHovered = false"
:class="el.isHovered ? 'bg-red-200' : ''"
Expand Down
15 changes: 8 additions & 7 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -263,13 +263,14 @@ <h3 class="font-bold font-mono">AirBnB Search Bar:</h3>
:change="destination = this.value;
filteredDestinations = destinations.search(destination)

if (filteredDestinations.length)
selectedDestination = filteredDestinations.first
else {
const region = regions.find((region) => region.name === destination)
if (region) selectedDestination = region.name
else selectedDestination = null
}"
const region = regions.find((region) => region.name === destination)

if (region)
selectedDestination = region.name
else if (filteredDestinations.length)
selectedDestination = filteredDestinations.first
else
selectedDestination = null"
:keyup.up="selectedDestination = filteredDestinations.previousItem(selectedDestination)"
:keyup.down="selectedDestination = filteredDestinations.nextItem(selectedDestination)"
placeholder="Search destinations"
Expand Down
121 changes: 11 additions & 110 deletions lib/entity.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { Lexer } from './generators/lexer'
import { Events } from './entity/events'
import { Attributes } from './entity/attributes'
import { State } from './state'
import { Mini } from './main'
import { State } from '@/state'
import { Mini } from '@/main'

const IGNORED_IDS = ['$', 'this']
import { Lexer } from '@/generators/lexer'

import { Events } from '@/entity/events'
import { Attributes } from '@/entity/attributes'
import { Data } from '@/entity/data'

export class Entity {
constructor(el, dynamicScripts = []) {
Expand All @@ -13,11 +14,10 @@ export class Entity {
this.tagName = el.tagName
this.dynamicScripts = dynamicScripts

this.variables = []
this.groupVariables = []
this.id = this.generateEntityUUID()

this.state = {}
this.data = new Data(this)
this.events = new Events(this)
this.attributes = new Attributes(this)
this.base.state.addEntity(this)
Expand Down Expand Up @@ -89,106 +89,7 @@ export class Entity {
}

getVariables() {
this._getVariablesFromAttributes()
this._getVariablesFromEvents()
this._initVariables()
}

_getVariablesFromAttributes() {
this.attributes.dynamicAttributes.forEach((name) => {
const attr = this.element.attributes[name]
if (!attr) return

if (name === ':each') {
const [_, variable] = attr.value.split(' in ')

const isNativeVariable =
typeof window[variable] === 'function' &&
window[variable].toString().indexOf('[native code]') === -1

if (isNativeVariable) return
if (variable in this.state) return
this.variables.push(variable)
}

if (!attr.value) return

const lexer = new Lexer(attr.value)

const identifiers = lexer.identifiers.filter((value) => {
if (IGNORED_IDS.includes(value)) return false
const variable = value.split('.')[0]
return !(variable in this.state)
})

if (name === ':group') this.groupVariables.push(...identifiers)
else this.variables.push(...identifiers)
})
}

_getVariablesFromEvents() {
this.events.dynamicEvents.forEach((event) => {
const expr = this.element.getAttribute(event)
if (!expr) return

const lexer = new Lexer(expr)

const identifiers = lexer.identifiers.filter((value) => {
if (IGNORED_IDS.includes(value)) return false
const variable = value.split('.')[0]
return !(variable in this.state)
})

this.variables.push(...identifiers)
})
}

_initVariables() {
this.variables = [...new Set(this.variables)]

this.variables.forEach((variable) => {
if (State.isElState(variable)) {
this.setAsGroup()

if (window[this.id] == null) {
window[this.id] = this.base.state.create({}, this.id)
}

this.base.state.addVariable(this.id, this.id)

if (variable !== State.EL_STATE) {
const [_, varName] = variable.split('.')
this.base.state.addEntityVariable(this.id, varName, this.id)
}
} else if (State.isGroupState(variable)) {
if (!this.group) this.group = this.getGroup()

// Cases where group is not found:
// - an each item with a :group directive being removed due to re-evaluation of :each attribute
if (this.group == null) return

if (window[this.group.id] == null) {
window[this.group.id] = this.base.state.create({}, this.group.id)
}

this.base.state.addVariable(this.group.id, this.id)

if (variable !== State.GROUP_STATE) {
const [_, varName] = variable.split('.')
this.base.state.addEntityVariable(this.group.id, varName, this.id)
}
} else if (typeof window[variable] === 'function') {
this.variables.splice(this.variables.indexOf(variable), 1)
} else {
try {
const [identifier] = variable.split('.')
window[identifier] = this.base.state.getState(identifier)
this.base.state.addVariable(identifier, this.id)
} catch (error) {
console.error('Failed to initialize variable:', variable, error)
}
}
})
this.data.init()
}

getGroup() {
Expand Down Expand Up @@ -271,15 +172,15 @@ export class Entity {

if (!entity) continue

variables.push(...entity.variables)
variables.push(...entity.data.variables)
entity.events.dispose()
this.base.state.removeEntity(entity)
}

// Clean up unused variables
const usedVariables = entities
.filter((entity) => !elements.includes(entity.element))
.reduce((acc, entity) => acc.concat(entity.variables), [])
.reduce((acc, entity) => acc.concat(entity.data.variables), [])

const unusedVariables = variables.filter(
(variable) => !usedVariables.includes(variable)
Expand Down
Loading
Loading