001/** 002 * 003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved. 004 * 005 * This library is free software; you can redistribute it and/or 006 * modify it under the terms of the GNU Lesser General Public 007 * License as published by the Free Software Foundation; either 008 * version 2.1 of the License, or (at your option) any later version. 009 * 010 * This library is distributed in the hope that it will be useful, 011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013 * Lesser General Public License for more details. 014 * 015 * You should have received a copy of the GNU Lesser General Public 016 * License along with this library. If not, see <http://www.gnu.org/licenses/>. 017 * 018 **/ 019package lucee.runtime.tag; 020 021import javax.servlet.jsp.tagext.Tag; 022 023import lucee.runtime.exp.ApplicationException; 024import lucee.runtime.exp.PageException; 025import lucee.runtime.ext.tag.TagImpl; 026import lucee.runtime.functions.other.GetBaseTagData; 027import lucee.runtime.op.Caster; 028import lucee.runtime.op.Decision; 029import lucee.runtime.type.Array; 030import lucee.runtime.type.ArrayImpl; 031import lucee.runtime.type.Collection; 032import lucee.runtime.type.Collection.Key; 033import lucee.runtime.type.KeyImpl; 034import lucee.runtime.type.Struct; 035 036/** 037* Allows subtag data to be saved with the base tag. Applies only to custom tags. 038* 039* 040* 041**/ 042public final class Associate extends TagImpl { 043 044 private static final Key ASSOC_ATTRS = KeyImpl.intern("AssocAttribs"); 045 046 047 /** The name of the structure in which the base tag stores subtag data. */ 048 private Collection.Key datacollection=ASSOC_ATTRS; 049 050 /** The name of the base tag. */ 051 private String basetag; 052 053 @Override 054 public void release() { 055 super.release(); 056 datacollection=ASSOC_ATTRS; 057 } 058 059 /** set the value datacollection 060 * The name of the structure in which the base tag stores subtag data. 061 * @param datacollection value to set 062 **/ 063 public void setDatacollection(String datacollection) { 064 this.datacollection=KeyImpl.init(datacollection); 065 } 066 067 /** set the value basetag 068 * The name of the base tag. 069 * @param basetag value to set 070 **/ 071 public void setBasetag(String basetag) { 072 this.basetag=basetag; 073 } 074 075 076 @Override 077 public int doStartTag() throws PageException { 078 079 // current 080 CFTag current=getCFTag(); 081 Struct value; 082 if(current==null || (value=current.getAttributesScope())==null) 083 throw new ApplicationException("invalid context, tag is no inside a custom tag"); 084 085 // parent 086 CFTag parent=GetBaseTagData.getParentCFTag(current.getParent(), basetag, -1); 087 if(parent==null) throw new ApplicationException("there is no parent tag with name ["+basetag+"]"); 088 089 Struct thisTag=parent.getThis(); 090 Object obj=thisTag.get(datacollection,null); 091 092 Array array; 093 094 if(obj==null) { 095 array=new ArrayImpl(new Object[]{value}); 096 thisTag.set(datacollection,array); 097 } 098 else if(Decision.isArray(obj) && (array=Caster.toArray(obj)).getDimension()==1) { 099 array.append(value); 100 } 101 else { 102 array=new ArrayImpl(new Object[]{obj,value}); 103 thisTag.set(datacollection,array); 104 } 105 return SKIP_BODY; 106 } 107 108 /*private static CFTag getParentCFTag(Tag srcTag,String trgTagName) { 109 String pureName=trgTagName; 110 CFTag cfTag; 111 if(StringUtil.startsWithIgnoreCase(pureName,"cf_")) { 112 pureName=pureName.substring(3); 113 } 114 if(StringUtil.startsWithIgnoreCase(pureName,"cf")) { 115 pureName=pureName.substring(2); 116 } 117 int count=0; 118 while((srcTag=srcTag.getParent())!=null) { 119 if(srcTag instanceof CFTag) { 120 if(count++==0)continue; 121 cfTag=(CFTag)srcTag; 122 if(cfTag instanceof CFTagCore){ 123 CFTagCore tc=(CFTagCore) cfTag; 124 if(tc.getName().equalsIgnoreCase(pureName)) 125 return cfTag; 126 continue; 127 } 128 if(cfTag.getAppendix().equalsIgnoreCase(pureName)) { 129 return cfTag; 130 } 131 } 132 } 133 return null; 134 }*/ 135 136 private CFTag getCFTag() { 137 Tag tag=this; 138 while((tag=tag.getParent())!=null) { 139 if(tag instanceof CFTag) { 140 return (CFTag)tag; 141 } 142 } 143 return null; 144 } 145 146 @Override 147 public int doEndTag() { 148 return EVAL_PAGE; 149 } 150 151}