/** * Helper to determine if a give MXMLUnitData is the only Text child of an MXMLTagData This * implies special, different processing from normal Text Datas. */ private boolean isOnlyTextChild(MXMLUnitData child) { if (child instanceof MXMLTextData && ((MXMLTextData) child).getTextType() == IMXMLTextData.TextType.TEXT) { MXMLUnitData p = child.getParentUnitData(); MXMLTagData parent = p instanceof MXMLTagData ? (MXMLTagData) p : null; if (parent != null) { return parent.getFirstChildUnit() == child && child.getNextSiblingUnit() == null; } } return false; }
/** Generate an AET Name that corresponds to the tag passed in */ private Name getNameForTag(MXMLTagData tag) { if (tag == rootTag) { return new Name(parent.getEffectiveID()); } else { String uri = tag.getURI(); if (uri != null) { return new Name(new Namespace(ABCConstants.CONSTANT_Namespace, uri), tag.getShortName()); } else { return new Name(tag.getShortName()); } } }
/** * Get the index of a text data. Grabs the parent, and iterates it's children to find out what the * index of the text data passed in should be */ private int getIndexOfText(MXMLTextData text) { MXMLUnitData parent = text.getParentUnitData(); MXMLTagData parentTag = parent instanceof MXMLTagData ? (MXMLTagData) parent : null; int index = 0; if (parentTag != null) { for (MXMLUnitData d = parentTag.getFirstChildUnit(); d != null; d = d.getNextSiblingUnit()) { if (d == text) break; else if (d instanceof MXMLTextData && ((MXMLTextData) d).getTextType() == IMXMLTextData.TextType.CDATA) ++index; } } return index; }
/** * Do a lookup of a prefix, starting with the specified tag. This method will record if the prefix * is defined outside of the <fx:XML> tag. If it is defined outside of the tag, then the prefix * will need to be added to the root XML tag as an 'xmlns' so that it will still be accessible. * * @param prefix the prefix to look for * @param tag the tag to start looking in */ void lookupPrefix(String prefix, MXMLTagData tag) { while (tag != null) { PrefixMap pm = tag.getPrefixMap(); if (pm != null && pm.containsPrefix(prefix)) // we found the prefix, and haven't gone past the root tag, so don't need to do anything // special return; else if (tag == rootTag) // don't look past the root tag tag = null; else tag = tag.getParentTag(); } // We will only get here if we have traversed past the root XML tag, and haven't found the // prefix yet // in that case, record the prefix if its defined somewhere else in the MXML document, so we can // make sure it ends up in the resulting XML literal. if (externalPrefixes.containsPrefix(prefix)) referencedPrefixes.add(prefix); }
/** * Get the index of a tag. Grabs the parent tag, and iterates it's children to find out what the * index of the tag passed in should be */ private int getIndexOfTag(MXMLTagData tag) { MXMLTagData parent = tag.getParentTag(); int index = 0; for (MXMLTagData d = parent.getFirstChild(true); d != null; d = d.getNextSibling(true)) { if (d == tag) break; else if (d.getName().equals(tag.getName())) ++index; } return index; }
/** * Process an MXMLTagData - this will write a String representation of the tag into the * StringWriter passed in. This will strip out any databinding expressions from the String, TODO: * databinding - add the databinding expressions as children of the MXMLXMLNode, and also record * what the TODO: target expressions for those are (these are the expressions to set the value in * the XML object when the TODO: PropertyChange event fires). */ void processNode(MXMLTagData tag, StringWriter sw) { sw.write('<'); if (tag.isCloseTag()) sw.write('/'); sw.write(tag.getName()); String tagPrefix = tag.getPrefix(); // lookup the prefix in case it's defined elsewhere in the document outside the XML tag if (tagPrefix != null) lookupPrefix(tagPrefix, tag); List<MXMLTagAttributeData> attrs = getAttributes(tag); for (MXMLTagAttributeData attr : attrs) { sw.write(' '); sw.write(attr.getName()); sw.write('='); sw.write('"'); sw.write(attr.getRawValue()); sw.write('"'); // lookup the prefix in case it's defined outside the XML tag String prefix = attr.getPrefix(); if (prefix != null) lookupPrefix(prefix, tag); } StringWriter childrenSW = new StringWriter(); for (MXMLUnitData unit = tag.getFirstChildUnit(); unit != null; unit = unit.getNextSiblingUnit()) { processNode(unit, childrenSW); } if (tag == rootTag) { // If we're the root tag, then add an xmlns for each prefix that was referenced by one of our // children, but was defined elsewhere in the document (like in the Application tag). for (String prefix : referencedPrefixes) { String uri = externalPrefixes.getNamespaceForPrefix(prefix); if (uri != null) { sw.write(" xmlns:"); sw.write(prefix); sw.write("=\""); sw.write(uri); sw.write('\"'); } } } if (tag.isEmptyTag()) { sw.write("/>"); } else { sw.write('>'); } sw.write(childrenSW.toString()); MXMLTagData endTag = tag.findMatchingEndTag(); if (endTag != null) { processNode(endTag, sw); } }
/** * Get a list of attributes, filtering out the attributes that have data binding values. * * @param tag The * @return */ List<MXMLTagAttributeData> getAttributes(MXMLTagData tag) { MXMLTagAttributeData[] rawAttrs = tag.getAttributeDatas(); if (rawAttrs != null) { ArrayList<MXMLTagAttributeData> attrs = new ArrayList<MXMLTagAttributeData>(rawAttrs.length); for (MXMLTagAttributeData attr : rawAttrs) { IMXMLSingleDataBindingNode db = null; if ((db = parseBindingExpression(attr)) != null) { // do databinding stuff: // 1. Walk up parent chain to compute target expression // 2. Parse databinding expression // 3. Save off both those pieces of data for use during codegen databindings.add(generateBindingNode(attr, db)); } else { attrs.add(attr); } } return attrs; } return Collections.emptyList(); }
@Override protected void processChildTag( MXMLTreeBuilder builder, MXMLTagData tag, MXMLTagData childTag, MXMLNodeInfo info) { if (info.hasSpecifierWithName(childTag.getShortName(), childTag.getStateName())) { ICompilerProblem problem = new MXMLDuplicateChildTagProblem(childTag); builder.addProblem(problem); return; } FlexProject project = builder.getProject(); // Handle child tags that are property/style/event specifiers. MXMLSpecifierNodeBase childNode = createSpecifierNode(builder, childTag.getShortName()); if (childNode != null) { // This tag is not part of the default property value. processNonDefaultPropertyContentUnit(builder, info); childNode.setSuffix(builder, childTag.getStateName()); childNode.initializeFromTag(builder, childTag); info.addChildNode(childNode); } else if (builder.getFileScope().isScriptTag(childTag) && (builder.getMXMLDialect().isEqualToOrBefore(MXMLDialect.MXML_2009))) { // In MXML 2006 and 2009, allow a <Script> tag // inside any class reference tag if (!processingDefaultProperty) { // Not processing the default property, just make a script // node and put it in the tree. MXMLScriptNode scriptNode = new MXMLScriptNode(this); scriptNode.initializeFromTag(builder, childTag); info.addChildNode(scriptNode); } else { // We are processing a default property. Script nodes need // to be a child of that default specifier nodes so that // finding a node by offset works properly. // See: http://bugs.adobe.com/jira/browse/CMP-955 processDefaultPropertyContentUnit(builder, childTag, info); } } else if (builder.getFileScope().isReparentTag(childTag)) { MXMLReparentNode reparentNode = new MXMLReparentNode(this); reparentNode.initializeFromTag(builder, childTag); info.addChildNode(reparentNode); } else { IDefinition definition = builder.getFileScope().resolveTagToDefinition(childTag); if (definition instanceof ClassDefinition) { // Handle child tags that are instance tags. IVariableDefinition defaultPropertyDefinition = getDefaultPropertyDefinition(builder); if (defaultPropertyDefinition != null && !processedDefaultProperty) { // Since there is a default property and we haven't already processed it, // assume this child instance tag is part of its value. processDefaultPropertyContentUnit(builder, childTag, info); } else { // This tag is not part of the default property value. processNonDefaultPropertyContentUnit(builder, info); MXMLInstanceNode instanceNode = MXMLInstanceNode.createInstanceNode(builder, definition.getQualifiedName(), this); instanceNode.setClassReference( project, (IClassDefinition) definition); // TODO Move this logic to initializeFromTag(). instanceNode.initializeFromTag(builder, childTag); info.addChildNode(instanceNode); } } else { // Handle child tags that are something other than property/style/event tags // or instance tags. // This tag is not part of the default property value. processNonDefaultPropertyContentUnit(builder, info); super.processChildTag(builder, tag, childTag, info); } } }