/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Robert Churchill * David Hyatt * Chris Waterson * Pierre Phaneuf * Neil Deakin * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsContentCID.h" #include "nsIDocument.h" #include "nsIDOMNodeList.h" #include "nsIDOMXULDocument.h" #include "nsINodeInfo.h" #include "nsIServiceManager.h" #include "nsIXULDocument.h" #include "nsContentSupportMap.h" #include "nsRDFConMemberTestNode.h" #include "nsRDFPropertyTestNode.h" #include "nsXULSortService.h" #include "nsTemplateRule.h" #include "nsTemplateMap.h" #include "nsVoidArray.h" #include "nsXPIDLString.h" #include "nsGkAtoms.h" #include "nsXULContentUtils.h" #include "nsXULElement.h" #include "nsXULTemplateBuilder.h" #include "nsSupportsArray.h" #include "nsNodeInfoManager.h" #include "nsContentCreatorFunctions.h" #include "nsContentUtils.h" #include "nsAttrName.h" #include "nsNodeUtils.h" #include "mozAutoDocUpdate.h" #include "jsapi.h" #include "pldhash.h" #include "rdf.h" //---------------------------------------------------------------------- // // Return values for EnsureElementHasGenericChild() // #define NS_ELEMENT_GOT_CREATED NS_RDF_NO_VALUE #define NS_ELEMENT_WAS_THERE NS_OK //---------------------------------------------------------------------- // // nsXULContentBuilder // /** * The content builder generates DOM nodes from a template. Generation is done * dynamically on demand when child nodes are asked for by some other part of * content or layout. This is done for a content node by calling * CreateContents which creates one and only one level of children deeper. The * next level of content is created by calling CreateContents on each child * node when requested. * * CreateTemplateAndContainerContents is used to determine where in a * hierarchy generation is currently, related to the current node being * processed. The actual content generation is done entirely inside * BuildContentFromTemplate. * * Content generation is centered around the generation node (the node with * uri="?member" on it). Nodes above the generation node are unique and * generated only once. BuildContentFromTemplate will be passed the unique * flag as an argument for content at this point and will recurse until it * finds the generation node. * * Once the generation node has been found, the results for that content node * are added to the content map, stored in mContentSupportMap. When * CreateContents is later called for that node, the results are retrieved and * used to create a new child for each result, based on the template. * * Children below the generation node are created with CreateTemplateContents. * * If recursion is allowed, generation continues, where the generation node * becomes the container to insert into. * * The XUL lazy state bits are used to control some aspects of generation: * * eChildrenMustBeRebuilt: set to true for a node that has its children * generated lazily. If this is set, the element will * need to call into the template builder to generate * its children. This state is cleared by the element * when this call is made. * eTemplateContentsBuilt: set to true for non-generation nodes if the * children have already been created. * eContainerContentsBuilt: set to true for generation nodes to indicate that * results have been determined. */ class nsXULContentBuilder : public nsXULTemplateBuilder { public: // nsIXULTemplateBuilder interface NS_IMETHOD CreateContents(nsIContent* aElement, PRBool aForceCreation); NS_IMETHOD HasGeneratedContent(nsIRDFResource* aResource, nsIAtom* aTag, PRBool* aGenerated); NS_IMETHOD GetResultForContent(nsIDOMElement* aContent, nsIXULTemplateResult** aResult); // nsIMutationObserver interface NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED NS_DECL_NSIMUTATIONOBSERVER_NODEWILLBEDESTROYED protected: friend NS_IMETHODIMP NS_NewXULContentBuilder(nsISupports* aOuter, REFNSIID aIID, void** aResult); nsXULContentBuilder(); void Traverse(nsCycleCollectionTraversalCallback &cb) const { mSortState.Traverse(cb); } virtual void Uninit(PRBool aIsFinal); // Implementation methods nsresult OpenContainer(nsIContent* aElement); nsresult CloseContainer(nsIContent* aElement); /** * Build content from a template for a given result. This will be called * recursively or on demand and will be called for every node in the * generated content tree. See the method defintion below for details * of arguments. */ nsresult BuildContentFromTemplate(nsIContent *aTemplateNode, nsIContent *aResourceNode, nsIContent *aRealNode, PRBool aIsUnique, PRBool aIsSelfReference, nsIXULTemplateResult* aChild, PRBool aNotify, nsTemplateMatch* aMatch, nsIContent** aContainer, PRInt32* aNewIndexInContainer); /** * Copy the attributes from the template node to the node generated * from it, performing any substitutions. * * @param aTemplateNode node within template * @param aRealNode generated node to set attibutes upon * @param aResult result to look up variable->value bindings in * @param aNotify true to notify of DOM changes */ nsresult CopyAttributesToElement(nsIContent* aTemplateNode, nsIContent* aRealNode, nsIXULTemplateResult* aResult, PRBool aNotify); /** * Add any necessary persistent attributes (persist="...") from the * local store to a generated node. * * @param aTemplateNode node within template * @param aRealNode generated node to set persisted attibutes upon * @param aResult result to look up variable->value bindings in */ nsresult AddPersistentAttributes(nsIContent* aTemplateNode, nsIXULTemplateResult* aResult, nsIContent* aRealNode); /** * Recalculate any attributes that have variable references. This will * be called when a binding has been changed to update the attributes. * The attributes are copied from the node aTemplateNode in the template * to the generated node aRealNode, using the values from the result * aResult. This method will operate recursively. * * @param aTemplateNode node within template * @param aRealNode generated node to set attibutes upon * @param aResult result to look up variable->value bindings in */ nsresult SynchronizeUsingTemplate(nsIContent *aTemplateNode, nsIContent* aRealNode, nsIXULTemplateResult* aResult); /** * Remove the generated node aContent from the DOM and the hashtables * used by the content builder. */ nsresult RemoveMember(nsIContent* aContent); /** * Create the appropriate generated content for aElement, by calling * CreateTemplateContents and CreateContainerContents. Both of these * functions will generate content but under different circumstances. * * Consider the following example: * * *