Skip to content

Commit

Permalink
Support custom namespace of components taglib
Browse files Browse the repository at this point in the history
  • Loading branch information
rainboyan committed Mar 5, 2024
1 parent 2b61c44 commit 1d80c15
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
/*
* Copyright 2022-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.graceframework.plugin.components.taglib

import groovy.transform.CompileStatic
import org.springframework.beans.factory.InitializingBean

import org.grails.taglib.NamespacedTagDispatcher
import org.grails.taglib.TagLibraryLookup
import org.grails.taglib.TagLibraryMetaUtils
import org.grails.taglib.TagOutput
import org.grails.taglib.encoder.OutputContextLookupHelper

/**
* {@link NamespacedTagDispatcher} for Component tag
*
* @author Michael Yan
* @since 0.0.2
*/
@CompileStatic
class ComponentNamespacedTagDispatcher extends GroovyObjectSupport implements NamespacedTagDispatcher, InitializingBean {

public static final String COMPONENT_NAMESPACE = 'vc'
public static final String RENDER_TAG_NAME = 'render'

private String namespace = COMPONENT_NAMESPACE
private TagLibraryLookup lookup

ComponentNamespacedTagDispatcher() {
}

@Override
void afterPropertiesSet() throws Exception {
initializeMetaClass()
}

void initializeMetaClass() {
ExpandoMetaClass emc = new ExpandoMetaClass(getClass(), false, true)
emc.initialize()
setMetaClass(emc)
registerTagMetaMethods(emc)
}

void registerTagMetaMethods(ExpandoMetaClass emc) {
TagLibraryMetaUtils.registerTagMetaMethods(emc, this.lookup, this.namespace)
}

@Override
String getNamespace() {
this.namespace
}

@Override
void setTagLibraryLookup(TagLibraryLookup lookup) {
if (!this.lookup) {
this.lookup = lookup
}
}

@Override
def methodMissing(String name, Object args) {
((GroovyObject) getMetaClass()).setProperty(name, { Object[] varArgs ->
callRender(argsToAttrs(name, varArgs), filterBodyAttr(varArgs))
})
callRender(argsToAttrs(name, args), filterBodyAttr(args))
}

private callRender(Map attrs, Object body) {
TagOutput.captureTagOutput(lookup, COMPONENT_NAMESPACE, RENDER_TAG_NAME, attrs, body,
OutputContextLookupHelper.lookupOutputContext())
}

private Map argsToAttrs(String name, Object args) {
Map<String, Object> attr = [:]
attr.component = name
if (args instanceof Object[]) {
Object[] tagArgs = ((Object[]) args)
if (tagArgs.length > 0 && tagArgs[0] instanceof Map) {
Map<String, Object> modelMap = (Map<String, Object>) tagArgs[0]
Object encodeAs = modelMap.remove(TagOutput.ENCODE_AS_ATTRIBUTE_NAME)
if (encodeAs != null) {
attr.put(TagOutput.ENCODE_AS_ATTRIBUTE_NAME, encodeAs)
}
attr.put('model', modelMap)
}
}
attr
}

private Object filterBodyAttr(Object args) {
if (args instanceof Object[]) {
Object[] tagArgs = ((Object[]) args)
if (tagArgs.length > 0) {
for (Object arg : tagArgs) {
if (!(arg instanceof Map)) {
return arg
}
}
}
}
null
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright 2022-2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.graceframework.plugin.components.taglib;

import java.util.Map;

import grails.util.CollectionUtils;

import org.grails.taglib.TagInvocationContext;
import org.grails.taglib.TagInvocationContextCustomizer;

/**
* Support custom namespace for Component tag
*
* @author Michael Yan
* @since 0.0.2
*/
public class ComponentTagInvocationContextCustomizer implements TagInvocationContextCustomizer {

@SuppressWarnings("rawtypes")
public void customize(TagInvocationContext tagInvocationContext) {
if (tagInvocationContext.getNamespace().equals("vc")) {
if (!tagInvocationContext.getTagName().equals("render")) {
String tmpTagName = tagInvocationContext.getTagName();
Map tmpAttrs = tagInvocationContext.getAttrs();
Map attrs = CollectionUtils.newMap("model", tmpAttrs, "component", tmpTagName);

tagInvocationContext.setTagName("render");
tagInvocationContext.setAttrs(attrs);
}
}
}

}
4 changes: 3 additions & 1 deletion src/main/resources/META-INF/grails.factories
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
grails.compiler.traits.TraitInjector=grails.compiler.traits.ComponentTraitInjector,grails.compiler.traits.ControllerComponentTraitInjector
grails.core.ArtefactHandler=org.graceframework.plugin.components.artefact.ComponentArtefactHandler
grails.core.ArtefactHandler=org.graceframework.plugin.components.artefact.ComponentArtefactHandler
org.grails.taglib.TagInvocationContextCustomizer=org.graceframework.plugin.components.taglib.ComponentTagInvocationContextCustomizer
org.grails.taglib.NamespacedTagDispatcher=org.graceframework.plugin.components.taglib.ComponentNamespacedTagDispatcher

0 comments on commit 1d80c15

Please sign in to comment.