Example #1
0
            // Group: Functions
            // _________________________________________________________________________

            public ContainerExtraData(MenuEntries.Base.Container menuEntry)
            {
                this.menuEntry           = menuEntry;
                this.jsonBeforeMembers   = null;
                this.jsonAfterMembers    = null;
                this.jsonLengthOfMembers = -1;
                this.dataFileName        = null;
                this.hashPath            = null;
            }
Example #2
0
        /* Function: BuildOutput
         * Generates the output file for the container.  It must have <ContainerExtraData.DataFileName> set.  If it finds
         * any sub-containers that also have that set, it will recursively generate files for them as well.
         */
        protected void BuildOutput(MenuEntries.Base.Container container)
        {
                        #if DEBUG
            if (container.ExtraData == null || (container.ExtraData as ContainerExtraData).StartsNewDataFile == false)
            {
                throw new Exception("BuildOutput() can only be called on containers with DataFileName set.");
            }
                        #endif

            Stack <MenuEntries.Base.Container> containersToBuild = new Stack <MenuEntries.Base.Container>();
            containersToBuild.Push(container);

            while (containersToBuild.Count > 0)
            {
                MenuEntries.Base.Container containerToBuild = containersToBuild.Pop();
                string fileName = (containerToBuild.ExtraData as ContainerExtraData).DataFileName;

                StringBuilder output = new StringBuilder();
                output.Append("NDMenu.OnSectionLoaded(\"");
                output.StringEscapeAndAppend(fileName);
                output.Append("\",[");

                if (!EngineInstance.Config.ShrinkFiles)
                {
                    output.AppendLine();
                }

                AppendMembers(containerToBuild, output, 1, containersToBuild);

                if (!EngineInstance.Config.ShrinkFiles)
                {
                    output.Append(' ', IndentSpaces);
                }

                output.Append("]);");

                System.IO.File.WriteAllText(HTMLBuilder.Menu_DataFolder + "/" + fileName, output.ToString());
            }
        }
Example #3
0
        /* Function: GenerateJSON
         * Generates JSON for all the entries in the passed container.
         */
        protected void GenerateJSON(MenuEntries.Base.Container container)
        {
            ContainerExtraData containerExtraData = new ContainerExtraData(container);

            container.ExtraData = containerExtraData;

            containerExtraData.GenerateJSON(HTMLBuilder, this);

            foreach (var member in container.Members)
            {
                if (member is MenuEntries.Base.Target)
                {
                    TargetExtraData targetExtraData = new TargetExtraData((MenuEntries.Base.Target)member);
                    member.ExtraData = targetExtraData;

                    targetExtraData.GenerateJSON(HTMLBuilder, this);
                }
                else if (member is MenuEntries.Base.Container)
                {
                    GenerateJSON((MenuEntries.Base.Container)member);
                }
            }
        }
Example #4
0
            /* Function: GenerateJSON
             */
            public void GenerateJSON(Builders.HTML htmlBuilder, JSMenuData menu)
            {
                StringBuilder output = new StringBuilder();

                output.Append("[2,");


                // Title

                if (menuEntry.CondensedTitles == null)
                {
                    if (menuEntry.Title != null)
                    {
                        output.Append('"');
                        output.StringEscapeAndAppend(menuEntry.Title.ToHTML());
                        output.Append('"');
                    }
                    // Otherwise leave an empty space before the comma.  We don't have to write out "undefined".
                }
                else
                {
                    output.Append("[\"");
                    output.StringEscapeAndAppend(menuEntry.Title.ToHTML());
                    output.Append('"');

                    foreach (string condensedTitle in menuEntry.CondensedTitles)
                    {
                        output.Append(",\"");
                        output.StringEscapeAndAppend(condensedTitle.ToHTML());
                        output.Append('"');
                    }

                    output.Append(']');
                }


                // Hash path

                output.Append(',');

                if (menuEntry is MenuEntries.Files.FileSource)
                {
                    MenuEntries.Files.FileSource fileSourceEntry = (MenuEntries.Files.FileSource)menuEntry;
                    hashPath = htmlBuilder.Source_OutputFolderHashPath(fileSourceEntry.WrappedFileSource.Number,
                                                                       fileSourceEntry.CondensedPathFromFileSource);
                }
                else if (menuEntry is MenuEntries.Files.Folder)
                {
                    MenuEntries.Base.Container container = menuEntry.Parent;

                                        #if DEBUG
                    if (container == null)
                    {
                        throw new Exception("Parent must be defined when generating JSON for menu folder \"" + menuEntry.Title + "\".");
                    }
                                        #endif

                    while ((container is MenuEntries.Files.FileSource) == false)
                    {
                        container = container.Parent;

                                                #if DEBUG
                        if (container == null)
                        {
                            throw new Exception("Couldn't find a file source among the folder \"" + menuEntry.Title + "\"'s parents when generating JSON.");
                        }
                                                #endif
                    }

                    MenuEntries.Files.Folder     folderEntry     = (MenuEntries.Files.Folder)menuEntry;
                    MenuEntries.Files.FileSource fileSourceEntry = (MenuEntries.Files.FileSource)container;

                    hashPath = htmlBuilder.Source_OutputFolderHashPath(fileSourceEntry.WrappedFileSource.Number,
                                                                       folderEntry.PathFromFileSource);
                }
                else if (menuEntry is MenuEntries.Classes.Language)
                {
                    MenuEntries.Classes.Language languageEntry = (MenuEntries.Classes.Language)menuEntry;

                    hashPath = htmlBuilder.Class_OutputFolderHashPath(languageEntry.WrappedLanguage,
                                                                      languageEntry.CondensedScopeString);
                }
                else if (menuEntry is MenuEntries.Classes.Scope)
                {
                    MenuEntries.Base.Container container = menuEntry;

                                        #if DEBUG
                    if (container == null)
                    {
                        throw new Exception("Parent must be defined when generating JSON for menu scope \"" + menuEntry.Title + "\".");
                    }
                                        #endif

                    while ((container is MenuEntries.Classes.Language) == false && container != menu.RootDatabaseMenu)
                    {
                        container = container.Parent;

                                                #if DEBUG
                        if (container == null)
                        {
                            throw new Exception("Couldn't find a language among the scope \"" + menuEntry.Title + "\"'s parents when generating JSON.");
                        }
                                                #endif
                    }

                    MenuEntries.Classes.Scope scopeEntry = (MenuEntries.Classes.Scope)menuEntry;

                    if (container == menu.RootDatabaseMenu)
                    {
                        hashPath = htmlBuilder.Database_OutputFolderHashPath(scopeEntry.WrappedScopeString);
                    }
                    else
                    {
                        MenuEntries.Classes.Language languageEntry = (MenuEntries.Classes.Language)container;
                        hashPath = htmlBuilder.Class_OutputFolderHashPath(languageEntry.WrappedLanguage, scopeEntry.WrappedScopeString);
                    }
                }
                else if (menuEntry == menu.RootFileMenu || menuEntry == menu.RootClassMenu)
                {
                    // If we're at the root file or class menu and the entry is not also a language or file source, it means there are multiple languages and/or
                    // file sources beneath it and thus there is no shared hash path.  "CSharpClass:" and "PerlClass:", "Files:" and "Files2:", etc.
                    hashPath = null;
                }
                else if (menuEntry == menu.RootDatabaseMenu)
                {
                    // If we're at the root database menu and the entry is not also a scope, it means there are multiple scopes beneath it.  However, unlike
                    // files and classes, there is still the shared "Database:" hash path.
                    hashPath = htmlBuilder.Database_OutputFolderHashPath();
                }
                                #if DEBUG
                else
                {
                    throw new Exception("Don't know how to generate JSON for container \"" + menuEntry.Title + "\".");
                }
                                #endif

                if (hashPath != null)
                {
                    output.Append('"');
                    output.StringEscapeAndAppend(hashPath);
                    output.Append('"');
                }
                // Otherwise leave an empty space before the comma.  We don't have to write out "undefined".

                output.Append(',');

                jsonBeforeMembers = output.ToString();
                jsonAfterMembers  = "]";
            }
Example #5
0
        /* Function: AppendMembers
         * A support function for <BuildOutput()>.  Appends the output of the container's members to the string, recursively
         * going through sub-containers as well.  This will not include the surrounding brackets, only the comma-separated
         * member entries.  If it finds any sub-containers that start a new data file, it will add them to containersToBuild.
         */
        protected void AppendMembers(MenuEntries.Base.Container container, StringBuilder output, int indent,
                                     Stack <MenuEntries.Base.Container> containersToBuild)
        {
            for (int i = 0; i < container.Members.Count; i++)
            {
                var member = container.Members[i];

                if (!EngineInstance.Config.ShrinkFiles)
                {
                    output.Append(' ', indent * IndentSpaces);
                }

                if (member is MenuEntries.Base.Target)
                {
                    TargetExtraData targetExtraData = (TargetExtraData)member.ExtraData;
                    output.Append(targetExtraData.JSON);
                }
                else if (member is MenuEntries.Base.Container)
                {
                    ContainerExtraData containerExtraData = (ContainerExtraData)member.ExtraData;
                    output.Append(containerExtraData.JSONBeforeMembers);

                    if (containerExtraData.StartsNewDataFile)
                    {
                        output.Append('"');
                        output.StringEscapeAndAppend(containerExtraData.DataFileName);
                        output.Append('"');

                        containersToBuild.Push((MenuEntries.Base.Container)member);
                    }
                    else
                    {
                        output.Append('[');

                        if (!EngineInstance.Config.ShrinkFiles)
                        {
                            output.AppendLine();
                        }

                        AppendMembers((MenuEntries.Base.Container)member, output, indent + 1, containersToBuild);

                        if (!EngineInstance.Config.ShrinkFiles)
                        {
                            output.Append(' ', (indent + 1) * IndentSpaces);
                        }

                        output.Append(']');
                    }

                    output.Append(containerExtraData.JSONAfterMembers);
                }
                                #if DEBUG
                else
                {
                    throw new Exception("Can't append JSON for menu entry " + member.Title + ".");
                }
                                #endif

                if (i < container.Members.Count - 1)
                {
                    output.Append(',');
                }

                if (!EngineInstance.Config.ShrinkFiles)
                {
                    output.AppendLine();
                }
            }
        }
Example #6
0
        /* Function: SegmentMenu
         * Segments the menu into smaller pieces and generates data file names.
         */
        protected void SegmentMenu(MenuEntries.Base.Container container, string dataFileType,
                                   ref StringTable <IDObjects.NumberSet> usedDataFiles)
        {
            // Generate the data file name for this container.

            IDObjects.NumberSet usedDataFileNumbers = usedDataFiles[dataFileType];

            if (usedDataFileNumbers == null)
            {
                usedDataFileNumbers = new IDObjects.NumberSet();
                usedDataFiles.Add(dataFileType, usedDataFileNumbers);
            }

            int dataFileNumber = usedDataFileNumbers.LowestAvailable;

            usedDataFileNumbers.Add(dataFileNumber);

            ContainerExtraData extraData = (ContainerExtraData)container.ExtraData;

            extraData.DataFileName = HTMLBuilder.Menu_DataFileNameOnly(dataFileType, dataFileNumber);


            // The data file has to include all the members in this container no matter what.

            int containerJSONSize = extraData.JSONBeforeMembers.Length + extraData.JSONAfterMembers.Length +
                                    extraData.JSONLengthOfMembers;

            List <MenuEntries.Base.Container> subContainers = null;

            foreach (var member in container.Members)
            {
                if (member is MenuEntries.Base.Container)
                {
                    if (subContainers == null)
                    {
                        subContainers = new List <MenuEntries.Base.Container>();
                    }

                    subContainers.Add((MenuEntries.Base.Container)member);
                }
            }


            // Now start including the contents of subcontainers until we reach the size limit.  We're going breadth-first instead of
            // depth first.

            List <MenuEntries.Base.Container> nextSubContainers = null;

            for (;;)
            {
                if (subContainers == null || subContainers.Count == 0)
                {
                    if (nextSubContainers == null || nextSubContainers.Count == 0)
                    {
                        break;
                    }
                    else
                    {
                        subContainers     = nextSubContainers;
                        nextSubContainers = null;
                    }
                }

                // Add subcontainers to the file in the order from smallest to largest.  This prevents one very large container early
                // in the list from causing all the other ones to be broken out into separate files.
                // DEPENDENCY: ContainerExtraData.JSONLengthOfMembers must cache its value for this algorithm to be efficient.

                int smallestSubContainerIndex = 0;
                int smallestSubContainerSize  = (subContainers[0].ExtraData as ContainerExtraData).JSONLengthOfMembers;

                for (int i = 1; i < subContainers.Count; i++)
                {
                    if ((subContainers[i].ExtraData as ContainerExtraData).JSONLengthOfMembers < smallestSubContainerSize)
                    {
                        smallestSubContainerIndex = i;
                        smallestSubContainerSize  = (subContainers[i].ExtraData as ContainerExtraData).JSONLengthOfMembers;
                    }
                }

                containerJSONSize += smallestSubContainerSize;

                if (containerJSONSize > SegmentLength)
                {
                    break;
                }

                foreach (var member in subContainers[smallestSubContainerIndex].Members)
                {
                    if (member is MenuEntries.Base.Container)
                    {
                        if (nextSubContainers == null)
                        {
                            nextSubContainers = new List <MenuEntries.Base.Container>();
                        }

                        nextSubContainers.Add((MenuEntries.Base.Container)member);
                    }
                }

                subContainers.RemoveAt(smallestSubContainerIndex);
            }


            // Now recurse through any remaining subcontainers so they get their own files.

            if (subContainers != null)
            {
                foreach (var subContainer in subContainers)
                {
                    SegmentMenu(subContainer, dataFileType, ref usedDataFiles);
                }
            }

            if (nextSubContainers != null)
            {
                foreach (var subContainer in nextSubContainers)
                {
                    SegmentMenu(subContainer, dataFileType, ref usedDataFiles);
                }
            }
        }