Rebase to main, fix formatting, align to order in composition api

Signed-off-by: Jeff James <jeff@james-online.com>
Jeff James 2026-03-25 06:20:24 -07:00
parent e84c184fb6
commit 6644a9edfd
1 changed files with 38 additions and 28 deletions

View File

@ -1,23 +1,23 @@
<template>
<span v-if="error" class="text-color-red">{{ error }}</span>
<ul v-else-if="config.listContainer" v-bind="$attrs" :class="config.containerClasses" :style="config.containerStyle">
<generic-widget-component v-for="(ctx) in childrenContexts" :context="ctx" :key="ctx.loop![forKey + '_key']" />
<generic-widget-component v-for="ctx in childrenContexts" :context="ctx" :key="ctx.loop![forKey + '_key']" />
</ul>
<!-- render without any additional container -->
<template v-else-if="config.fragment">
<!-- if parent is oh-swiper, render inside f7-swiper-slide -->
<template v-if="context.parent && ['oh-swiper', 'f7-swiper'].includes(context.parent.component.component)">
<f7-swiper-slide v-for="(ctx) in childrenContexts" v-bind="$attrs" :key="ctx.loop![forKey + '_key']">
<f7-swiper-slide v-for="ctx in childrenContexts" v-bind="$attrs" :key="ctx.loop![forKey + '_key']">
<generic-widget-component :context="ctx" />
</f7-swiper-slide>
</template>
<!-- else render -->
<template v-else>
<generic-widget-component v-for="(ctx) in childrenContexts" v-bind="$attrs" :context="ctx" :key="ctx.loop![forKey + '_key']" />
<generic-widget-component v-for="ctx in childrenContexts" v-bind="$attrs" :context="ctx" :key="ctx.loop![forKey + '_key']" />
</template>
</template>
<div v-else :class="config.containerClasses" :style="config.containerStyle">
<generic-widget-component v-for="(ctx) in childrenContexts" v-bind="$attrs" :context="ctx" :key="ctx.loop![forKey + '_key']" />
<generic-widget-component v-for="ctx in childrenContexts" v-bind="$attrs" :context="ctx" :key="ctx.loop![forKey + '_key']" />
</div>
</template>
@ -34,19 +34,20 @@ import { OhRepeater } from '@/types/components/widgets'
import * as api from '@/api'
import { ApiError } from '@/js/hey-api'
type SourceType = api.EnrichedItem | api.EnrichedGroupItem | api.EnrichedRule | api.StateOption | api.CommandOption | string | number
type SourceType = api.EnrichedItem | api.EnrichedGroupItem | api.EnrichedRule | api.StateOption | api.CommandOption | string | number
type SourceArray = SourceType[] | null
// props
// define*
const props = defineProps<{
context: WidgetContext
}>()
defineOptions({ inheritAttrs: false, widget: OhRepeaterDefinition })
// Composables
const { config, childContext, evaluateExpression, defaultSlots } = useWidgetContext(props.context)
// reactive data
// Data/State
const error = ref<string | null>(null)
const sourceCache = ref<SourceArray | null>(null)
const sourceType = ref<SourceType | null>(null)
@ -58,7 +59,7 @@ const childrenContexts = computed(() => {
const iterationContext = (ctx: WidgetContext, el: SourceType, idx: number, source: SourceArray) => {
// takes the context with the added variables
const loopVars = (ctx.loop) ? { ...ctx.loop } : {}
const loopVars = ctx.loop ? { ...ctx.loop } : {}
loopVars[forKey.value!] = el
loopVars[forKey.value! + '_idx'] = idx
loopVars[forKey.value! + '_source'] = source
@ -74,22 +75,24 @@ const childrenContexts = computed(() => {
if (filter) {
_source = _source.filter((el, idx, source) =>
evaluateExpression('filterExpr', '=' + filter,
iterationContext(childContext(props.context.component), el, idx, source)))
evaluateExpression('filterExpr', '=' + filter, iterationContext(childContext(props.context.component), el, idx, source))
)
}
if (map) {
_source = _source.map((el, idx, source) =>
evaluateExpression('mapExpr', '=' + map,
iterationContext(childContext(props.context.component), el, idx, source)))
evaluateExpression('mapExpr', '=' + map, iterationContext(childContext(props.context.component), el, idx, source))
)
}
let contexts = []
let idx = 0
const ds = defaultSlots.value as api.UiComponent[]
for (let i of _source) {
contexts.push(...ds.map((c) => {
return iterationContext(childContext(c), i, idx, _source)
}))
contexts.push(
...ds.map((c) => {
return iterationContext(childContext(c), i, idx, _source)
})
)
idx++
}
@ -97,7 +100,7 @@ const childrenContexts = computed(() => {
return contexts
})
const source = computedAsync(async () : Promise<SourceArray> => {
const source = computedAsync(async (): Promise<SourceArray> => {
const cfg = config.value
if (cfg.cacheSource && sourceCache.value != null) return sourceCache.value
@ -126,12 +129,14 @@ const source = computedAsync(async () : Promise<SourceArray> => {
let sourceResult
try {
switch(sourceType.value) {
switch (sourceType.value) {
case OhRepeater.SourceType.range:
const start = cfg.rangeStart || 0
const stop = isNaN(cfg.rangeStop) ? 10 : cfg.rangeStop
const step = cfg.rangeStep || 1
return Array(Math.floor((stop + step - start) / step)).fill(start).map((x, y) => x + y * step)
return Array(Math.floor((stop + step - start) / step))
.fill(start)
.map((x, y) => x + y * step)
case OhRepeater.SourceType.itemsWithTags:
sourceResult = await getItemsWithTags()
break
@ -149,7 +154,7 @@ const source = computedAsync(async () : Promise<SourceArray> => {
break
case OhRepeater.SourceType.array:
default:
if(!('in' in cfg)) {
if (!('in' in cfg)) {
error.value = 'oh-repeater: "in" must be defined when sourceType is none or invalid'
console.warn(error.value)
return []
@ -164,18 +169,20 @@ const source = computedAsync(async () : Promise<SourceArray> => {
return []
}
sourceCache.value = (config.value.cacheSource) ? sourceResult : null
sourceCache.value = config.value.cacheSource ? sourceResult : null
return sourceResult
})
// Methods
function simpleHash(obj: object | string): string {
const str = JSON.stringify(obj)
let hash = 0, i, chr
let hash = 0,
i,
chr
if (str.length === 0) return hash.toString()
for (i = 0; i < str.length; i++) {
chr = str.charCodeAt(i)
hash = ((hash << 5) - hash) + chr
chr = str.charCodeAt(i)
hash = (hash << 5) - hash + chr
hash |= 0 // Convert to 32bit integer
}
return (hash >>> 0).toString(36)
@ -183,7 +190,7 @@ function simpleHash(obj: object | string): string {
function getKey(el: SourceType): string {
let key = 'repeater-'
switch(sourceType.value) {
switch (sourceType.value) {
case OhRepeater.SourceType.itemsWithTags:
case OhRepeater.SourceType.itemsInGroup:
return key + (el as api.EnrichedItem).name
@ -224,7 +231,7 @@ async function getItemsWithTags() {
throw e
}
})
if(!sourceResult) return []
if (!sourceResult) return []
return sourceResult.sort(compareItems)
}
@ -253,7 +260,7 @@ async function getItemsInGroup() {
async function getItemStateOptions() {
const cfg = config.value
if(!('itemOptions' in cfg)) {
if (!('itemOptions' in cfg)) {
error.value = 'oh-repeater: itemOptions must be defined when sourceType is itemStateOptions'
console.warn(error.value)
return []
@ -297,7 +304,7 @@ async function getItemCommandOptions() {
}
})
if (!sourceResult) return []
if(!sourceResult.commandDescription) {
if (!sourceResult.commandDescription) {
console.warn(`oh-repeater: item "${cfg.itemOptions}" does not have command options`)
return []
}
@ -318,7 +325,10 @@ async function getRulesWithTags() {
}
// getRulesWithTags does not handle comma separate tags
const ruleTags = (cfg.ruleTags as string).split(',').map(t => t.trim()).filter(t => t.length > 0)
const ruleTags = (cfg.ruleTags as string)
.split(',')
.map((t) => t.trim())
.filter((t) => t.length > 0)
const sourceResult = await api.getRules({ summary: true, tags: ruleTags })
if (!sourceResult) return []