Skip to content

Commit

Permalink
feat(content): improve reactivity (#688)
Browse files Browse the repository at this point in the history
* fix: properly treat falsy values in context

* feat: added reactivity and event support

* feat: added v-model support for custom components

Co-authored-by: Alexander <aab.sandash@protonmail.com>
  • Loading branch information
AlexanderBelokon and Alexander authored Jan 25, 2021
1 parent 881f6d4 commit 1fbcbbc
Showing 1 changed file with 40 additions and 8 deletions.
48 changes: 40 additions & 8 deletions packages/content/templates/nuxt-content.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,51 @@ const info = require('property-information')

const rootKeys = ['class-name', 'class', 'style']

function propsToData (props, doc) {
const rxOn = /^@|^v-on:/
const rxBind = /^:|^v-bind:/
const rxModel = /^v-model/
const nativeInputs = ['select', 'textarea', 'input']

function evalInContext (code, context) {
return new Function("with(this) { return (" + code + ") }").call(context)
}

function propsToData (node, doc) {
const { tag, props } = node
return Object.keys(props).reduce(function (data, key) {
const k = key.replace(/.*:/, '')
let obj = rootKeys.includes(k) ? data : data.attrs
const value = props[key]
const { attribute } = info.find(info.html, key)

if (key === 'v-bind') {
const val = value in doc ? doc[value] : eval(`(${value})`)
const native = nativeInputs.includes(tag)

if (rxModel.test(key) && value in doc && !native) {
const mods = key.replace(rxModel, '')
.split('.')
.filter(d => d)
.reduce((d, k) => (d[k] = true, d), {})

// As of yet we don't resolve custom v-model field/event names from components
const field = 'value'
const event = mods.lazy ? 'change' : 'input'
const processor =
mods.number ? (d => +d) :
mods.trim ? (d => d.trim()) :
d => d

obj[field] = evalInContext(value, doc)
data.on = data.on || {}
data.on[event] = e => doc[value] = processor(e)
} else if (key === 'v-bind') {
const val = value in doc ? doc[value] : evalInContext(value, doc)
obj = Object.assign(obj, val)
} else if (key.indexOf(':') === 0 || key.indexOf('v-bind:') === 0) {
key = key.replace('v-bind:', '').replace(':', '')
obj[key] = value in doc ? doc[value] : eval(`(${value})`)
} else if (rxOn.test(key)) {
key = key.replace(rxOn, '')
data.on = data.on || {}
data.on[key] = evalInContext(value, doc)
} else if (rxBind.test(key)) {
key = key.replace(rxBind, '')
obj[key] = value in doc ? doc[value] : evalInContext(value, doc)
} else if (Array.isArray(value)) {
obj[attribute] = value.join(' ')
} else {
Expand Down Expand Up @@ -56,7 +88,7 @@ function processNode (node, h, doc) {
}

const slotData = slotsToData(node || {}, h, doc)
const propData = propsToData(node.props, doc)
const propData = propsToData(node || {}, doc)
const data = Object.assign({}, slotData, propData)

/**
Expand Down

0 comments on commit 1fbcbbc

Please sign in to comment.