home *** CD-ROM | disk | FTP | other *** search
/ PC User 2003 September / Australian PC User - September 2003 (CD1).iso / magstuff / web / files / dwmx61.exe / Disk1 / data1.cab / Configuration_En / Translators / TranslationManager.js < prev    next >
Encoding:
JavaScript  |  2002-11-25  |  80.8 KB  |  2,190 lines

  1. //SHARE-IN-MEMORY=true
  2. // Copyright 2000,2001 Macromedia, Inc. All rights reserved.
  3.  
  4. var translatorInfo = new Array();
  5. var lastInStr = "";
  6. var lastOutStr = "";
  7. var lastIndex = "";
  8. var lastDynamicTextFormat = null;
  9. var g_index = "";
  10. var debugMegaLock = false;
  11. var debugTagSpan = false;
  12. var debug = false;
  13.  
  14. /////////////////////////////////////////////// TranslationManager Class //////////////////////////////////////////////////
  15.  
  16. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. // Function : TranslationManager::TranslationManager
  18. // Purpose  : Instantiate this object and call its translate method within your translators 
  19. //        translateMarkup() function.  This will create a translator that utilizes the
  20. //        translation rules defined in the XML participant files containing a
  21. //        translator section.
  22. // Arguments: translatorClass - the translator class as specified by the translators
  23. //        getTranslatorInfo() function.  This name will be used as the 
  24. //        translatorClass attribute of the MM:BeginLock tags.
  25. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  26. function TranslationManager(translatorClass, serverModel, serverLanguage)
  27. {
  28.   // Private Members
  29.   this.inStr = "";
  30.   this.translatorClass = translatorClass;
  31.   this.defaultDirectiveTag = translatorClass;  // the default tag name for directives
  32.   if (serverLanguage)
  33.   {
  34.     this.index = serverModel + ":" + serverLanguage;
  35.   }
  36.   else
  37.   {
  38.     this.index = serverModel;
  39.   }
  40.   g_index = this.index;  // for the sorting function
  41.   this.requerry = false;
  42.   this.offsetTagBegin = -1;
  43.   this.offsetTagEnd = -1;
  44.   this.currentTagName = null;
  45.   this.whereToSearch = "";
  46.   this.dynamicTextFormat = dw.getDynamicTextFormat();
  47.   this.params = new Array();
  48.   this.dataSources = new Array();
  49.   this.CFOutput = new Stack(); // Cold Fusion specific to ensure dynamic data within cfoutput tags
  50.   this.translator = new translator; // translator class which interfaces to the Translator Support Library (TSL)
  51.   if (translatorInfo[this.index] == null)
  52.   {
  53.     translatorInfo[this.index] = new Array(); // repository for XML translator information
  54.     translatorInfo[this.index].lookInAllAttributes = false;
  55.     translatorInfo[this.index].lookInAllTags = false;
  56.   }
  57.  
  58.   // Methods to use in identifying dynamic tags and attributes
  59.   this.serverModelAlwaysCheckTag = null;
  60.   this.serverModelAlwaysCheckAttribute = null;
  61.  
  62.   // Methods for constructing whole tag spans
  63.   this.inTagSpan = false;          // currently inside tag span
  64.   this.tagSpan = null;             // contents of tag span thus far
  65.   this.tagSpanRecover = false;     // on second pass through tag span
  66.   this.tagSpanName = null;         // name of tag
  67.   this.tagSpanCounter = null;      // used to match up nested tags
  68.   this.tagSpanParts = null;        // tag+name and tag+* participants
  69.   this.tagSpanSnapshot = null;
  70.   this.tagSpanLastIndex = -1;
  71.  
  72.   // Stack of tags that enclose current code (if there are any)
  73.   this.enclosingTags = new Array();
  74.  
  75.   // Object with methods getTranslation and setTranslation.  If non-null,
  76.   // will be used to cache all tag spans.
  77.   this.tagSpanCache = null;
  78.  
  79.   this.mode = "preview";
  80.   this.inEditMode = false;
  81.   this.editModeEndOffset = -1;
  82.   this.editModeFullCode = null;
  83.   this.editModeFullTranslation = null;
  84.  
  85.   // Megalocks aggregate several separate locked regions into one.
  86.   this.inMegaLock = false;
  87.   this.megaLockCode = null;
  88.   this.megaLockTranslation = null;
  89.   this.megaLockPreCodeOffset = 0;
  90.   this.megaLockSnapshot = null;
  91.  
  92.   // Maintenance for reparsing (when a tag span doesn't match any of the
  93.   // available translations or when parsing in dual-mode)
  94.   this.reparse = false;
  95.   this.reparseSnapshot = null;
  96.  
  97.   this.directives = "";
  98. }
  99.   // public methods
  100.   TranslationManager.prototype.translate          = TM_translate;
  101.   TranslationManager.prototype.notifyXMLChange      = TM_notifyXMLChange;
  102.  
  103.   // public static methods
  104.   TranslationManager.findTagLength            = TM_findTagLength;
  105.   TranslationManager.getAttributeValue          = TM_getAttributeValue;
  106.   TranslationManager.splitBody                = TM_splitBody;
  107.  
  108.   // private methods
  109.   TranslationManager.prototype.getTranslatorInfo      = TM_getTranslatorInfo;
  110.   TranslationManager.prototype.getParticipant       = TM_getParticipant;
  111.   TranslationManager.prototype.getDirective       = TM_getDirective;
  112.   TranslationManager.prototype.getAttribute       = TM_getAttribute;
  113.   TranslationManager.prototype.getText          = TM_getText;
  114.   TranslationManager.prototype.getTag           = TM_getTag;
  115.   TranslationManager.prototype.getData          = TM_getData;
  116.   TranslationManager.prototype.getTokens          = TM_getTokens;
  117.   TranslationManager.prototype.isPattern          = TM_isPattern;
  118.   TranslationManager.prototype.getCurrentTagName      = TM_getCurrentTagName;
  119.   TranslationManager.prototype.getCurrentTag        = TM_getCurrentTag;
  120.   TranslationManager.prototype.translateDirective     = TM_translateDirective;
  121.   TranslationManager.prototype.translateAttribute     = TM_translateAttribute;
  122.   TranslationManager.prototype.translateText        = TM_translateText;
  123.   TranslationManager.prototype.translateTag       = TM_translateTag;
  124.   TranslationManager.prototype.notifyTagBegin       = TM_notifyTagBegin;
  125.   TranslationManager.prototype.notifyTagEnd       = TM_notifyTagEnd;
  126.   TranslationManager.prototype.getCurrentTagOffset    = TM_getCurrentTagOffset;
  127.   TranslationManager.prototype.getParams          = TM_getParams;
  128.   TranslationManager.prototype.searchMatchesCode      = TM_searchMatchesCode;
  129.   TranslationManager.prototype.searchMatchesOpenTag   = TM_searchMatchesOpenTag;
  130.   TranslationManager.prototype.getMatchingParticipant   = TM_getMatchingParticipant
  131.   TranslationManager.prototype.startTagSpan       = TM_startTagSpan;
  132.   TranslationManager.prototype.addToTagSpan       = TM_addToTagSpan;
  133.   TranslationManager.prototype.addOpenTagToTagSpan    = TM_addOpenTagToTagSpan;
  134.   TranslationManager.prototype.addCloseTagToTagSpan   = TM_addCloseTagToTagSpan;
  135.   TranslationManager.prototype.finishTagSpan        = TM_finishTagSpan;
  136.   TranslationManager.prototype.correctOutlineIDs    = TM_correctOutlineIDs;
  137.   TranslationManager.prototype.translateTagSpan     = TM_translateTagSpan;
  138.   TranslationManager.prototype.translateTextSpan      = TM_translateTextSpan;
  139.   TranslationManager.prototype.startMegaLock        = TM_startMegaLock;
  140.   TranslationManager.prototype.addToMegaLock        = TM_addToMegaLock;
  141.   TranslationManager.prototype.finishMegaLock        = TM_finishMegaLock;
  142.   TranslationManager.prototype.startEditMode        = TM_startEditMode;
  143.   TranslationManager.prototype.endEditMode            = TM_endEditMode;
  144.   TranslationManager.prototype.setDecoration        = TM_setDecoration;
  145.   TranslationManager.prototype.initialize         = TM_reInitialize;
  146.   TranslationManager.prototype.participantSort      = TM_participantSort;
  147.   TranslationManager.prototype.lookInThisAttribute    = TM_lookInThisAttribute;
  148.   TranslationManager.prototype.alwaysCheckAttribute   = TM_alwaysCheckAttribute;
  149.   TranslationManager.prototype.lookInThisTag        = TM_lookInThisTag;
  150.   TranslationManager.prototype.alwaysCheckTag       = TM_alwaysCheckTag;
  151.   TranslationManager.prototype.lookInTags         = TM_lookInTags;
  152.   TranslationManager.prototype.pushOpenTag             = TM_pushOpenTag;
  153.   TranslationManager.prototype.popCloseTag             = TM_popCloseTag;
  154.   TranslationManager.prototype.prepForReparse        = TM_prepForReparse;
  155.   TranslationManager.prototype.takeSnapshot            = TM_takeSnapshot;
  156.   TranslationManager.prototype.restoreSnapshot            = TM_restoreSnapshot;
  157.  
  158. ///////////////////////////////////////////////
  159. // Function : TM_reInitialize
  160. // Purpose  : Informs the TSL to reinitialize itself
  161. ////////////////////////////////////////////////////////////////////////////
  162. ///////////////////////////////////////////////
  163. function TM_reInitialize()
  164. {
  165.     this.translator.initiate(this.document, this.translatorClass);
  166. }
  167.  
  168. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  169. // Function : TM_translate
  170. // Purpose  : Utilizes dw.scanSourceString to reliably parse through the given HTML string.
  171. // Arguments: the HTML string to translate
  172. // Returns  : the translation string as defined by the rules in the XML participant files
  173. //        containing translator sections.  This string should be returned by the 
  174. //        translators translateMarkup() function.
  175. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  176. function TM_translate(inStr)
  177. {
  178.   if (this.index != lastIndex || inStr != lastInStr || this.dynamicTextFormat != lastDynamicTextFormat)
  179.   {
  180.     this.inStr = inStr;
  181.     this.translator.initiate(inStr, this.translatorClass);
  182.     var callback = new TMCallback(this);
  183.     dreamweaver.scanSourceString(inStr, callback);
  184.     while (this.reparse || this.inTagSpan)
  185.     {
  186.       if (this.inTagSpan)
  187.       {
  188.         this.prepForReparse("tagspan");
  189.         // Restart the translator from the beginning of the tag span (in "recover" state)
  190.         this.inTagSpan = false;
  191.         this.tagSpanRecover = true;
  192.         callback.inTagSpan = false;
  193.       }
  194.       else if (this.inMegaLock)
  195.       {
  196.         this.prepForReparse("megalock");
  197.       }
  198.  
  199.       this.reparse = false;
  200.       if (this.reparseSnapshot)
  201.         this.restoreSnapshot(this.reparseSnapshot);
  202.  
  203.       if (debug)
  204.           alert("Restarting translator due to " +
  205.             (this.inTagSpan ? "tag span (" : "reparse (") +
  206.             this.reparseSnapshot.offset + ")...\n" + 
  207.             this.inStr);
  208.  
  209.       dreamweaver.scanSourceString(this.inStr, callback);
  210.     }
  211.     if (this.inMegaLock)
  212.     {
  213.         if (debugMegaLock)
  214.             alert("Open mega lock");
  215.         this.finishMegaLock("");
  216.     }
  217.     var outStr = this.translator.getTranslation();
  218.     this.translator.terminate();
  219.     if (inStr.length != outStr.length)
  220.     {
  221.       lastInStr = inStr;
  222.       lastOutStr = outStr;
  223.       lastIndex = this.index;
  224.     }
  225.     lastDynamicTextFormat = this.dynamicTextFormat;
  226.   }
  227.   else
  228.   {
  229.     outStr = lastOutStr;
  230.   }
  231.  
  232.   return outStr;
  233. }
  234.  
  235. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  236. // Function : TM_notifyXMLChanged
  237. // Purpose  : Informs the translator that the translatorInfo needs to be refreshed.
  238. //        Call this when the Participant files translator sections have been modified.
  239. //        Since there is no UI currently provided to define the translation rules,
  240. //        developers will need to restart UltraDev when adding/modifying participant
  241. //        files translator sections.
  242. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  243. function TM_notifyXMLChange() 
  244.   this.requerry = true;
  245. }
  246.  
  247. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  248. // Function : TM_prepForReparse
  249. // Purpose  : Sets up the TM for a reparse of a portion of the document.
  250. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  251. function TM_prepForReparse(cause, offset)
  252. {
  253.     this.reparse = true;
  254.     if (cause == "tagspan")
  255.         this.reparseSnapshot = this.tagSpanSnapshot;
  256.     else if (cause == "megalock")
  257.         this.reparseSnapshot = this.megaLockSnapshot;
  258.     else
  259.         this.reparseSnapshot = new Snapshot(this.enclosingTags, offset);
  260. }
  261.  
  262. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  263. // Function : evalPattern
  264. // Purpose    : The JavaScript interpreter needs to do some extra work (in
  265. //          js_PutCallObject) whenever it invokes any function containing
  266. //          an eval statement.  In order to avoid doing that processing
  267. //          every time that TM_getTranslatorInfo is called, the eval
  268. //          statement is wrapped inside this function.
  269. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  270. function evalPattern(pattern)
  271. {
  272.     return eval(pattern);
  273. }
  274.  
  275. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  276. // Function : TM_getTranslatorInfo
  277. // Purpose  : Build the global multi-dimensional array (translatorInfo) representing the 
  278. //        translator information from the XML participant files.
  279. //        Each server model is loaded only once unless requerry is set.
  280. //        Note: This is the sole interface between the Translation Manager and the
  281. //        Extension Data Manager (EDM).
  282. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  283. function TM_getTranslatorInfo() 
  284.   if (this.requery || (translatorInfo[this.index].participants == null))
  285.   {
  286.     // TO DO, if this.requery is true, then we need to destroy the objects in
  287.     // translatorInfo so they too will be reloaded on demand.
  288.  
  289.     // Arrays for partitioning participants by type
  290.     translatorInfo[this.index].participants = 1;
  291.     translatorInfo[this.index].directiveParticipants = new Array();
  292.     translatorInfo[this.index].attributeParticipants = new Array();
  293.     translatorInfo[this.index].textParticipants = new Array();
  294.     translatorInfo[this.index].tagOnlyParticipants = new Array();
  295.     translatorInfo[this.index].outerHTMLParticipants = new Array();
  296.  
  297.     var partArry = dw.getExtParticipants("", "translator");
  298.     if (partArry)
  299.     {
  300.       // Sort participants by priority
  301.  
  302.       var sortValue = 500;
  303.       translatorInfo[this.index].sortOrder = new Array();
  304.       for (var i = 0; i < partArry.length; i++)
  305.       {
  306.         var priority = dw.getExtDataValue(partArry[i], "translator", "priority");
  307.         if (priority.length)
  308.           translatorInfo[this.index].sortOrder[partArry[i]] = priority.valueOf();
  309.         else
  310.           translatorInfo[this.index].sortOrder[partArry[i]] = sortValue++;
  311.       }
  312.       partArry.sort(this.participantSort);
  313.  
  314.       // Process each participant in turn (collecting its data)
  315.  
  316.       for (var i = 0; i < partArry.length; i++)
  317.       {
  318.         if (translatorInfo[this.index][partArry[i]] == null)
  319.         {
  320.           translatorInfo[this.index][partArry[i]] = new Array();
  321.           var transInfo = translatorInfo[this.index][partArry[i]];
  322.  
  323.           // === TRANSLATIONS ===
  324.  
  325.           var transArry = dw.getExtDataArray(partArry[i], "translator", "translations");
  326.           if (transArry && transArry.length)
  327.           {
  328.             transInfo.translations = new Array();
  329.  
  330.             for (var j = 0; j < transArry.length; j++)
  331.             {
  332.               // Fill in translatorInfo[this.index].???participants and
  333.               // translatorInfo[this.index][partArry[i]][whereToSearch]
  334.               transData.parse(partArry[i], transArry[j], translatorInfo[this.index], this);
  335.             }
  336.           }
  337.  
  338.           // === CONTEXT ===
  339.  
  340.           var context = dw.getExtDataValue(partArry[i], "translator", "context");
  341.           if (context && context.length)
  342.             transInfo.context = context.toLowerCase();
  343.           else
  344.             transInfo.context = null;
  345.  
  346.           // === MODE ===
  347.           var mode = dw.getExtDataValue(partArry[i], "translator", "mode");
  348.           if (mode && mode.length)
  349.             transInfo.mode = mode.toLowerCase();
  350.           else
  351.             transInfo.mode = null;
  352.  
  353.           // === SEARCH PATTERNS ===
  354.  
  355.           var patternArry = dw.getExtDataArray(partArry[i], "translator", "searchPatterns");
  356.           if (patternArry && patternArry.length)
  357.           {
  358.             transInfo.patterns = new Array();
  359.             transInfo.isPatternRE = new Array();
  360.             transInfo.isOptional = new Array();
  361.             transInfo.requiredLocation = new Array();
  362.             transInfo.paramNames = new Array();
  363.             for (var j = 0; j < patternArry.length; j++)
  364.             {
  365.               var pattern = dw.getExtDataValue(partArry[i], "translator", "searchPatterns", patternArry[j]);
  366.  
  367.               if (this.isPattern(pattern))
  368.               {
  369.                 // Any participant with a regular expression in the first search pattern is
  370.                 // going to have to be checked against each attribute in each page
  371.                 if (j == 0 && !translatorInfo[this.index].lookInAllAttributes)
  372.                   if (translatorInfo[this.index].attributeParticipants[partArry[i]])
  373.                     translatorInfo[this.index].lookInAllAttributes = true;
  374.                 transInfo.isPatternRE[patternArry[j]] = true;
  375.                 transInfo.patterns[patternArry[j]] = evalPattern(pattern);
  376.               }
  377.               else
  378.               {
  379.                 // Any participant with a string in the first search pattern is only
  380.                 // going to have to be checked against each attribute in each page if
  381.                 // that string doesn't match one of our predictable patterns
  382.                 if (j == 0 && !translatorInfo[this.index].lookInAllAttributes)
  383.                   if (translatorInfo[this.index].attributeParticipants[partArry[i]])
  384.                     if (!this.alwaysCheckAttribute(pattern))
  385.                       translatorInfo[this.index].lookInAllAttributes = true;
  386.                 transInfo.isPatternRE[patternArry[j]] = false;
  387.                 transInfo.patterns[patternArry[j]] = pattern;
  388.               }
  389.  
  390.               var isOptional =
  391.                 dw.getExtDataValue(partArry[i], "translator", "searchPatterns", patternArry[j], "isOptional");
  392.               transInfo.isOptional[patternArry[j]] = (isOptional.toLowerCase() == "true");
  393.                                   
  394.               var requiredLocation =
  395.                 dw.getExtDataValue(partArry[i], "translator", "searchPatterns", patternArry[j], "requiredLocation").toLowerCase();
  396.               transInfo.requiredLocation[patternArry[j]] = "";
  397.               if (requiredLocation == "leading" ||
  398.                 requiredLocation == "trailing" ||
  399.                 requiredLocation == "opentag" ||
  400.                 requiredLocation == "tagname")
  401.                 transInfo.requiredLocation[patternArry[j]] = requiredLocation;
  402.               var paramNames = dw.getExtDataValue(partArry[i], "translator", "searchPatterns", patternArry[j], "paramNames");
  403.               if (paramNames && paramNames.length)
  404.                 transInfo.paramNames[patternArry[j]] = paramNames;
  405.             }
  406.           }
  407.         }
  408.       }
  409.     }
  410.     this.requery = false;
  411.   }
  412. }
  413.  
  414. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  415. // Function : TM_lookInThisAttribute
  416. // Purpose  : Used within the TM_callback class to see if it necessary to look
  417. //        within this particular attribute to check for a translation rule.
  418. //        This is an optimization that allows us to ignore looping through
  419. //        all participants with translation rules for most attributes.  It 
  420. //        relies on the fact that our current translation rules for attributes
  421. //        all have quicksearches defined (non-regular expression search pattern)
  422. //        that contain certain known character sequences (ie. '<%', '#', '<cf',
  423. //        and '<jsp:').  If a developer extends these any of our translators in 
  424. //        such a way that their quick search pattern does not exist or is not one
  425. //        of these expressions, then this performance boost will not kick in since
  426. //        we will not be able to quickly reject most attributes.
  427. // Arguments: code : this is the attribute value passed into the attribute callback method.
  428. // Returns  : false if we can quickly reject this attribute value (i.e we dont need to 
  429. //        search within the attribute participants for a pattern that matches this code. 
  430. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  431. function TM_lookInThisAttribute(code)
  432. {
  433.   this.getTranslatorInfo();
  434.   if (translatorInfo[this.index].lookInAllAttributes)
  435.     return true;
  436.   else if (this.alwaysCheckAttribute(code))
  437.     return true;
  438.   return false;
  439. }
  440.  
  441.  
  442. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  443. // Function : TM_alwaysCheckAttribute
  444. // Purpose  : Allows server models to specify their own attribute character
  445. //        sequences for the optimization implemented in TM_lookInThisAttribute.
  446. //        See myAlwaysCheckAttribute in JSP.htm for an example.
  447. // Arguments: code = quicksearch pattern or code from TMCallback attribute function
  448. // Returns  : true = try to translate attribute, false = skip attribute
  449. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  450. function TM_alwaysCheckAttribute(code)
  451. {
  452.   if (this.serverModelAlwaysCheckAttribute != null)
  453.     return this.serverModelAlwaysCheckAttribute(code);
  454.   else
  455.     return false;
  456. }
  457.  
  458. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  459. // Function : TM_lookInThisTag
  460. // Purpose  : Used within the TM_callback class to see if it necessary to look
  461. //        within this particular tag to check for a translation rule.
  462. //        This is an optimization that allows us to ignore looping through
  463. //        all participants with translation rules for most tags.  It 
  464. //        relies on the fact that our current translation rules for tags
  465. //        apply only to tags with known prefixes (like "jsp:" or "cf")
  466. //        If a developer adds a translation rule for a tag that doesn't
  467. //        start with one of these prefixes, then this performance boost will
  468. //        not kick in since we will not be able to quickly reject most tags.
  469. // Arguments: tagName
  470. // Returns  : false if we can quickly reject this tag (i.e we dont need to search
  471. //        within the tag participants for a pattern that matches this code).
  472. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  473. function TM_lookInThisTag(tagName)
  474. {
  475.   this.getTranslatorInfo();
  476.   if (translatorInfo[this.index].lookInAllTags)
  477.     return true;
  478.   else if (this.alwaysCheckTag(tagName))
  479.     return true;
  480.   return false;
  481. }
  482.  
  483. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  484. // Function : TM_alwaysCheckTag
  485. // Purpose  : Allows server models to specify their own tag tests for the optimization
  486. //        implemented in TM_lookInThisTag.  See myAlwaysCheckTag in JSP.htm
  487. //        for an example.
  488. // Arguments: tagName
  489. // Returns  : true = try to translate this tag, false = skip this tag
  490. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  491. function TM_alwaysCheckTag(tagName)
  492. {
  493.   if (this.serverModelAlwaysCheckTag != null)
  494.     return this.serverModelAlwaysCheckTag(tagName);
  495.   else
  496.     return false;
  497. }
  498.  
  499. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  500. // Function : TM_lookInTags
  501. // Purpose  : DEPRECATED
  502. // Arguments: 
  503. // Returns  : true if any participant for the current server model contains a tag
  504. //        search.
  505. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  506. function TM_lookInTags()
  507. {
  508.   return translatorInfo[this.index].lookInAllTags;
  509. }
  510.  
  511. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  512. // Function : TM_participantSort
  513. // Purpose  : Sorts participants based on the priority attribute of the translator tag
  514. // Arguments: ptype - the callback location where dw.scanSourceString found the code fragment
  515. //        code - the code fragment to match against the XML patterns
  516. // Returns  : Name of the participant that matches the code segment and location requirement,
  517. //        null if none found.
  518. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  519. function TM_participantSort(part1, part2)
  520. {
  521.   var result = 0;
  522.   var priority1 = translatorInfo[g_index].sortOrder[part1];
  523.   var priority2 = translatorInfo[g_index].sortOrder[part2];
  524.   if (priority1 != priority2)
  525.   {
  526.     if (priority1 < priority2)
  527.     {
  528.       result = -1;
  529.     }
  530.     else
  531.     {
  532.       result = 1;
  533.     }
  534.   }
  535.   return result;
  536. }
  537.  
  538. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  539. // Function : TM_getParticipant
  540. // Purpose  : Find the participant whose search and location specification matches the
  541. //        specified code fragment.
  542. // Arguments: ptype - the callback location where dw.scanSourceString found the code fragment
  543. //        code - the code fragment to match against the XML patterns
  544. // Returns  : Name of the participant that matches the code segment and location requirement,
  545. //        null if none found.
  546. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  547. function TM_getParticipant(pType, code)
  548. {
  549.   var participant = null;
  550.   if (pType == PTYPE_ATTRIBUTE)
  551.   { 
  552.     participant = this.getAttribute(code, TM_getParticipant.arguments[2]);
  553.   }
  554.   else
  555.   {
  556.     if (pType == PTYPE_TAG)
  557.     {
  558.       participant = this.getTag(code);
  559.     }
  560.     else
  561.     {
  562.       if (pType == PTYPE_TEXT)
  563.       {
  564.         participant = this.getText(code);
  565.       }
  566.       else
  567.       {
  568.         if (pType == PTYPE_DIRECTIVE)
  569.         {
  570.           participant = this.getDirective(code);
  571.         }
  572.       }
  573.     }
  574.   }
  575.   return participant;
  576. }
  577.  
  578. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  579. // Function : TM_getDirective
  580. // Purpose  : Find the participant whose translation name is "directive" and pattern 
  581. //        successfuly identifies the specified code segment.
  582. // Arguments: code - directive from dw.scanSourceString directive callback.
  583. // Returns  : Matching participant, otherwise null.
  584. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  585. function TM_getDirective(code)
  586. {
  587.   var participant = null;
  588.   this.getTranslatorInfo();
  589.   var index = "directive";
  590.   var arry = translatorInfo[this.index];
  591.  
  592.   if (arry.directiveParticipants)
  593.   {
  594.     for (var part in arry.directiveParticipants)
  595.     {
  596.       var translations = arry[part].translations;
  597.       if (translations)
  598.       {
  599.         if (translations[index])
  600.         {
  601.           if (this.searchMatchesCode(part, code))
  602.           {
  603.             this.whereToSearch = index;
  604.             participant = part;
  605.             break;
  606.           }
  607.         }
  608.       }
  609.     }
  610.   }
  611.   return participant;
  612. }
  613.  
  614. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  615. // Function : TM_getText
  616. // Purpose  : Find the participant whose translation name is "text" and pattern 
  617. //        successfuly identifies the specified code segment.
  618. // Arguments: code - text span from dw.scanSourceString text callback.
  619. // Returns  : Matching participant, otherwise null.
  620. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  621. function TM_getText(code)
  622. {
  623.   var participant = null;
  624.   this.getTranslatorInfo();
  625.   var index = "text";
  626.   var arry = translatorInfo[this.index];
  627.  
  628.   if (arry.textParticipants)
  629.   {
  630.     for (var part in arry.textParticipants)
  631.     {
  632.       var translations = arry[part].translations;
  633.       if (translations)
  634.       {
  635.         if (translations[index])
  636.         {
  637.           if (this.searchMatchesCode(part, code))
  638.           {
  639.             this.whereToSearch = index;
  640.             participant = part;
  641.             break;
  642.           }
  643.         }
  644.       }
  645.     }
  646.   }
  647.   return participant;
  648. }
  649.  
  650. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  651. // Function : TM_getTag
  652. // Purpose  : Find the participant whose translation name is equivalent to the current tag name
  653. //        or "*", and whose pattern successfuly identifies the specified code segment.
  654. //        Priority is given to participants whose translation name matches the current tag.
  655. //        If no participant is found, then we search for the wild card tag specification "*".
  656. // Arguments: code - tag span collected between the dw.scanSourceString openTagBegin
  657. //        and openTagEnd callbacks and the tag span between the closeTagBegin and closeTagEnd
  658. //        callbacks.
  659. // Returns  : Matching participant, otherwise null.
  660. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  661. function TM_getTag(code)
  662. {
  663.   var participant = null;
  664.   this.getTranslatorInfo();
  665.   var tag = this.getCurrentTagName();
  666.   var index = "tag+" + tag + ":tagonly";
  667.   var index2 = "tag+*:tagonly";
  668.   var arry = translatorInfo[this.index];
  669.  
  670.   if (arry.tagOnlyParticipants)
  671.   {
  672.     for (var part in arry.tagOnlyParticipants)
  673.     {
  674.       var translations = arry[part].translations;
  675.       if (translations)
  676.       {
  677.         if (translations[index])
  678.         {
  679.           if (this.searchMatchesCode(part, code))
  680.           {
  681.             this.whereToSearch = index;
  682.             participant = part;
  683.             break;
  684.           }
  685.         }
  686.         if (!participant)
  687.         {
  688.           if (translations[index2])
  689.           {
  690.             if (this.searchMatchesCode(part, code))
  691.             {
  692.               this.whereToSearch = index2;
  693.               participant = part;
  694.             }
  695.           }
  696.         }
  697.       }
  698.     }
  699.   }
  700.   return participant; 
  701. }
  702.  
  703. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  704. // Function : TM_getAttribute
  705. // Purpose  : Find the participant whose translation name is equivalent to the current 
  706. //        tag+attribute pair or "*+*", and whose pattern successfuly identifies the 
  707. //        specified code segment.
  708. //        Priority is given to participants whose translation name matches the current 
  709. //        tag+attribute pair.
  710. //        If no participant is found, then we search for the wild card tag+attribute
  711. //        specification "*+*".
  712. // Arguments: code - attribute value from dw.scanSourceString attribute callback.
  713. //        attrName - attribute name from dw.scanSourceString attribute callback.
  714. // Returns  : Matching participant, otherwise null.
  715. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  716. function TM_getAttribute(code, attrName)
  717. {
  718.   var participant = null;
  719.   this.getTranslatorInfo();
  720.   var tag = "tag+" + this.getCurrentTagName();
  721.   var attribute = "attribute+" + attrName.toLowerCase();
  722.   var index = tag + ":" + attribute;
  723.   var index2 = tag + ":attribute+*";
  724.   var index3 = "tag+*:attribute+*";
  725.   var arry = translatorInfo[this.index];
  726.  
  727.   if (arry.attributeParticipants)
  728.   {
  729.     for (var part in arry.attributeParticipants)
  730.     {
  731.       var translations = arry[part].translations;
  732.       if (translations)
  733.       {
  734.         if (translations[index])
  735.         {
  736.           // Look for specific tag + attribute matches first
  737.           if (this.searchMatchesCode(part, code))
  738.           {
  739.             this.whereToSearch = index;
  740.             participant = part;
  741.             break;
  742.           }
  743.         }
  744.         if (!participant)
  745.         {
  746.           if (translations[index2])
  747.           {
  748.             if (this.searchMatchesCode(part, code))
  749.             {
  750.               this.whereToSearch = index2;
  751.               participant = part;
  752.             }
  753.           }
  754.         }
  755.         if (!participant)
  756.         {
  757.           if (translations[index3])
  758.           {
  759.             if (this.searchMatchesCode(part, code))
  760.             {
  761.               this.whereToSearch = index3;
  762.               participant = part;
  763.             }
  764.           }
  765.         }
  766.       }
  767.     }
  768.   }
  769.   return participant;
  770. }
  771.  
  772.  
  773. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  774. // Function : TM_getParams
  775. // Purpose  : pulls parameters out of regular expression match
  776. // Arguments: params - array of params to add to
  777. //        paramNames - comma delimited list of param names
  778. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  779. function TM_getParams(params, paramNames, doEncode)
  780. {
  781.   if (paramNames && paramNames.length)
  782.   {
  783.     var paramArry = paramNames.split(",");
  784.     if (paramArry[0] && paramArry[0].length)
  785.     {
  786.       params[paramArry[0]] = RegExp.$1;
  787.       if (doEncode)
  788.         params[paramArry[0]] = dw.latin1ToNative(params[paramArry[0]]);
  789.     }
  790.     if (paramArry[1] && paramArry[1].length)
  791.     {
  792.       params[paramArry[1]] = RegExp.$2;
  793.       if (doEncode)
  794.         params[paramArry[1]] = dw.latin1ToNative(params[paramArry[1]]);
  795.     }
  796.     if (paramArry[2] && paramArry[2].length)
  797.     {
  798.       params[paramArry[2]] = RegExp.$3;
  799.       if (doEncode)
  800.         params[paramArry[2]] = dw.latin1ToNative(params[paramArry[2]]);
  801.     }
  802.     if (paramArry[3] && paramArry[3].length)
  803.     {
  804.       params[paramArry[3]] = RegExp.$4;
  805.       if (doEncode)
  806.         params[paramArry[3]] = dw.latin1ToNative(params[paramArry[3]]);
  807.     }
  808.     if (paramArry[4] && paramArry[4].length)
  809.     {
  810.       params[paramArry[4]] = RegExp.$5;
  811.       if (doEncode)
  812.         params[paramArry[4]] = dw.latin1ToNative(params[paramArry[4]]);
  813.     }
  814.     if (paramArry[5] && paramArry[5].length)
  815.     {
  816.       params[paramArry[5]] = RegExp.$6;
  817.       if (doEncode)
  818.         params[paramArry[5]] = dw.latin1ToNative(params[paramArry[5]]);
  819.     }
  820.     if (paramArry[6] && paramArry[6].length)
  821.     {
  822.       params[paramArry[6]] = RegExp.$7;
  823.       if (doEncode)
  824.         params[paramArry[6]] = dw.latin1ToNative(params[paramArry[6]]);
  825.     }
  826.     if (paramArry[7] && paramArry[7].length)
  827.     {
  828.       params[paramArry[7]] = RegExp.$8;
  829.       if (doEncode)
  830.         params[paramArry[7]] = dw.latin1ToNative(params[paramArry[7]]);
  831.     }
  832.     if (paramArry[8] && paramArry[8].length)
  833.     {
  834.       params[paramArry[8]] = RegExp.$9;
  835.       if (doEncode)
  836.         params[paramArry[8]] = dw.latin1ToNative(params[paramArry[8]]);
  837.     }
  838.   }
  839. }
  840.  
  841.  
  842. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  843. // Function : TM_searchMatchesOpenTag
  844. // Purpose : determines whether the specified code matches the search patterns with
  845. //           requiredLocation="opentag".  This can be used to eliminate some tag spans
  846. //           from consideration before we bother collecting the whole tag span.
  847. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  848. function TM_searchMatchesOpenTag(part, code)
  849. {
  850.   var found = true;
  851.   var arry = translatorInfo[this.index][part];
  852.  
  853.   if (arry.context)
  854.   {
  855.     var top = null;
  856.     if (this.enclosingTags.length > 0)
  857.       top = this.enclosingTags[this.enclosingTags.length-1];
  858.     if (arry.context != top)
  859.       return false;
  860.   }
  861.  
  862.   if (arry.mode)
  863.   {
  864.     if (arry.mode != this.mode)
  865.       return false;
  866.   }
  867.  
  868.   if (arry.patterns)
  869.   {
  870.     for (var patternName in arry.patterns)
  871.     {
  872.       if (arry.requiredLocation[patternName] == "opentag")
  873.       {
  874.         var isRE = arry.isPatternRE[patternName];
  875.         var pattern = arry.patterns[patternName];
  876.         if (!isRE)
  877.         {
  878.           var offset = code.indexOf(pattern);
  879.         }
  880.         else
  881.         {
  882.           var charSet = dw.getDocumentDOM().getCharSet();
  883.           if (charSet == "iso-8859-1")
  884.           {
  885.             code = dw.nativeToLatin1(code);
  886.           }
  887.           var offset = code.search(pattern);
  888.         }
  889.         if (offset == -1 && !arry.isOptional[patternName])
  890.         {
  891.           found = false;
  892.           break;
  893.         }
  894.       }
  895.       else if (arry.requiredLocation[patternName] == "tagname")
  896.       {
  897.         var tagName = this.currentTagName;
  898.         var isRE = arry.isPatternRE[patternName];
  899.         var pattern = arry.patterns[patternName];
  900.         if (!isRE)
  901.         {
  902.           var offset = tagName.indexOf(pattern);
  903.         }
  904.         else
  905.         {
  906.           var charSet = dw.getDocumentDOM().getCharSet();
  907.           if (charSet == "iso-8859-1")
  908.           {
  909.             tagName = dw.nativeToLatin1(tagName);
  910.           }
  911.           var offset = tagName.search(pattern);
  912.         }
  913.         if (offset == -1 && !arry.isOptional[patternName])
  914.         {
  915.           found = false;
  916.           break;
  917.         }
  918.       }
  919.     }
  920.   }
  921.  
  922.   return found;
  923. }
  924.  
  925. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  926. // Function : TM_searchMatchesCode
  927. // Purpose  : determines weather the specified code satisfies the search criteria defined
  928. //        within the XML participant translator, patterns section.
  929. //        Multiple ordered searches supported.
  930. // Arguments: part - participant name
  931. //        code - code fragment to run patterns agains
  932. // Returns  : true if match, false otherwise
  933. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  934. function TM_searchMatchesCode(part, code)
  935. {
  936.   var found = false;
  937.   var params = new Array();
  938.   var arry = translatorInfo[this.index][part];
  939.  
  940.   if (arry.context)
  941.   {
  942.     var top = null;
  943.     if (this.enclosingTags.length > 0)
  944.       top = this.enclosingTags[this.enclosingTags.length-1];
  945.     if (arry.context != top)
  946.       return false;
  947.   }
  948.  
  949.   if (arry.mode)
  950.   {
  951.     if (arry.mode != this.mode)
  952.       return false;
  953.   }
  954.  
  955.   if (arry.patterns)
  956.   {
  957.     for (var patternName in arry.patterns)
  958.     {
  959.       var isRE = arry.isPatternRE[patternName];
  960.       var pattern = arry.patterns[patternName];
  961.       if (!isRE)
  962.       {
  963.         if (arry.requiredLocation[patternName] == "")
  964.         {
  965.           var offset = code.indexOf(pattern);
  966.         }
  967.         else
  968.         {
  969.           if (arry.requiredLocation[patternName] == "leading")
  970.           {
  971.             var offset = this.inStr.substr(0, this.getCurrentTagOffset()).indexOf(pattern);
  972.           }
  973.           else
  974.           {
  975.             if (arry.requiredLocation[patternName] == "trailing")
  976.             {
  977.               var offset = this.inStr.substr(this.getCurrentTagOffset() + code.length).indexOf(pattern);
  978.             }
  979.             else
  980.             {
  981.               if (arry.requiredLocation[patternName] == "opentag")
  982.               {
  983.                 var tagLength = TranslationManager.findTagLength(code);
  984.                 if (tagLength != -1)
  985.                   var offset = code.substr(0, tagLength).indexOf(pattern);
  986.               }
  987.               else
  988.               {
  989.                 if (arry.requiredLocation[patternName] == "tagname")
  990.                 {
  991.                   var offset = this.currentTagName.indexOf(pattern);
  992.                 }
  993.               }
  994.             }
  995.           }
  996.         }
  997.       }
  998.       else
  999.       {
  1000.         if (arry.requiredLocation[patternName] == "")
  1001.         {
  1002.           var charSet = dw.getDocumentDOM().getCharSet();
  1003.           var doEncode = false;
  1004.           if (charSet == "iso-8859-1")
  1005.           {
  1006.             doEncode = true;
  1007.             code = dw.nativeToLatin1(code);
  1008.           }
  1009.           var offset = code.search(pattern);
  1010.           if (offset != -1)
  1011.           {
  1012.             var paramNames = arry.paramNames[patternName];
  1013.             this.getParams(params, paramNames, doEncode);
  1014.           }
  1015.         }
  1016.         else
  1017.         {
  1018.           if (arry.requiredLocation[patternName] == "leading")
  1019.           {
  1020.             var offset = this.inStr.substr(0, this.getCurrentTagOffset()).search(pattern);
  1021.           }
  1022.           else
  1023.           {
  1024.             if (arry.requiredLocation[patternName] == "trailing")
  1025.             {
  1026.               var offset = this.inStr.substr(this.getCurrentTagOffset() + code.length).search(pattern);
  1027.             }
  1028.             else
  1029.             {
  1030.               if (arry.requiredLocation[patternName] == "opentag")
  1031.               {
  1032.                 var tagLength = TranslationManager.findTagLength(code);
  1033.                 if (tagLength != -1)
  1034.                 {
  1035.                   var tagCode = code.substr(0, tagLength);
  1036.  
  1037.                   var charSet = dw.getDocumentDOM().getCharSet();
  1038.                   var doEncode = false;
  1039.                   if (charSet == "iso-8859-1")
  1040.                   {
  1041.                     doEncode = true;
  1042.                     tagCode = dw.nativeToLatin1(tagCode);
  1043.                   }
  1044.                   var offset = tagCode.search(pattern);
  1045.                   if (offset != -1)
  1046.                   {
  1047.                     var paramNames = arry.paramNames[patternName];
  1048.                     this.getParams(params, paramNames, doEncode);
  1049.                   }
  1050.                 }
  1051.               }
  1052.               else
  1053.               {
  1054.                 if (arry.requiredLocation[patternName] == "tagname")
  1055.                 {
  1056.                   var tagName = this.currentTagName;
  1057.                   var charSet = dw.getDocumentDOM().getCharSet();
  1058.                   var doEncode = false;
  1059.                   if (charSet == "iso-8859-1")
  1060.                   {
  1061.                     doEncode = true;
  1062.                     tagName = dw.nativeToLatin1(tagName);
  1063.                   }
  1064.                   var offset = tagName.search(pattern);
  1065.                   if (offset != -1)
  1066.                   {
  1067.                     var paramNames = arry.paramNames[patternName];
  1068.                     this.getParams(params, paramNames, doEncode);
  1069.                   }
  1070.                 }
  1071.               }
  1072.             }
  1073.           }
  1074.         }
  1075.       }
  1076.  
  1077.       if (offset != -1)
  1078.       {
  1079.         found = true;       
  1080.       }
  1081.       else
  1082.       {
  1083.         if (!arry.isOptional[patternName])
  1084.         {
  1085.           found = false;
  1086.           break;
  1087.         }
  1088.       }
  1089.     }
  1090.   }
  1091.   this.params = params;
  1092.  
  1093.   return found;
  1094. }
  1095.  
  1096. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1097. // Function : TM_getData
  1098. // Purpose  : Retreive the translation information for the given participant.  
  1099. //        Token substitution provided using the specified code fragment.
  1100. // Arguments: part - participant name
  1101. //        code - code for which participant was located
  1102. // Returns  : transData structure which contains the openTag, closeTag, display, attributes, etc.
  1103. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1104. function TM_getData(part, code, attrName)
  1105. {
  1106.   var data = null;
  1107.   if (part)
  1108.   {
  1109.     var whereToSearch = this.whereToSearch;
  1110.     var arry = translatorInfo[this.index][part].translations;
  1111.     if (arry)
  1112.     {
  1113.       if (arry[whereToSearch])
  1114.       {
  1115.         data = transData.copy(arry[whereToSearch].data);
  1116.         var tokens = this.getTokens(part, code, attrName);
  1117.         data.replaceTokens(tokens);
  1118.       }
  1119.     }
  1120.   }
  1121.   return data;
  1122. }
  1123.  
  1124. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1125. // Function : TM_getTokens(part)
  1126. // Purpose  : retreive the translation token patterns for the specified participant
  1127. // Arguments: part - participant
  1128. // Returns  : An array indexed by the token names, containing the token patterns
  1129. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1130. function TM_getTokens(part, code, attrName)
  1131. {
  1132.   var tokens = new Array();
  1133.   if (attrName && attrName != "")
  1134.   {
  1135.     tokens["attr"] = attrName;
  1136.   }
  1137.   for (var paramName in this.params)
  1138.   {
  1139.     tokens[paramName] = this.params[paramName];
  1140.   }
  1141.   return tokens;
  1142. }
  1143. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1144. // Function : TM_isPattern
  1145. // Purpose  : determines whether a string is a regular expression
  1146. // Arguments: pattern - regular expression or quick search expression (locate using indexOf)
  1147. // Returns  : true if regular expression, false otherwise
  1148. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1149. function TM_isPattern(pattern)
  1150. {
  1151.   if (pattern.charAt(0) == "/")
  1152.   {
  1153.     return true;
  1154.   }
  1155.   return false;
  1156. }
  1157.  
  1158. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1159. // Function : TM_getCurrentTagName
  1160. // Purpose  : Get the name of the active tag.  Used from openTagEnd, closeTagEnd, and
  1161. //        attribute callbacks.
  1162. // Arguments: Pass in optional attribute offset, when called from attribute callback.
  1163. // Returns  : Active tag name;
  1164. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1165. function TM_getCurrentTagName()
  1166. {
  1167.   return this.currentTagName;
  1168. }
  1169.  
  1170. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1171. // Function : TM_getCurrentTag
  1172. // Purpose  : returns active tag - example <cfoutput querry-"">
  1173. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1174. function TM_getCurrentTag()
  1175. {
  1176.   var currTag = "";
  1177.   if ((this.offsetTagBegin >= 0) && (this.offsetTagEnd >= 0))
  1178.   {
  1179.     currTag = this.inStr.substr(this.offsetTagBegin, this.offsetTagEnd - this.offsetTagBegin);
  1180.   }
  1181.   return currTag;
  1182. }
  1183.  
  1184. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1185. // Function : TM_getCurrentTagOffset
  1186. // Purpose  : returns offset of beginning of active tag
  1187. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1188. function TM_getCurrentTagOffset()
  1189. {
  1190.   return this.offsetTagBegin;
  1191. }
  1192.  
  1193. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1194. // Function : TM_notifyTagBegin
  1195. // Purpose  : returns active tag
  1196. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1197. function TM_notifyTagBegin(tag, offset)
  1198. {
  1199.   this.currentTagName = tag.toLowerCase();
  1200.   this.offsetTagBegin = offset;
  1201. }
  1202.  
  1203. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1204. // Function : TM_notifyTagEnd
  1205. // Purpose  : returns active tag
  1206. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1207. function TM_notifyTagEnd(offset)
  1208. {
  1209.   this.offsetTagEnd = offset;
  1210.   return this.getCurrentTag();
  1211. }
  1212.  
  1213. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1214. // Function : TM_translateDirective
  1215. // Purpose  : translate the directive given the translation rules (utilizes the dependent search criteria info)
  1216. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1217. function TM_translateDirective(code, offset, trans)
  1218. {
  1219.   var origPosition = this.translator.getPosition();
  1220.   var result = "";
  1221.   if (trans)
  1222.   {
  1223.     result = this.translator.translateDirective(code, offset, trans.participant, trans.type, trans.openTag, trans.closeTag, trans.attributes, trans.display, trans.lockAttributes);
  1224.   }
  1225.   else if (this.defaultDirectiveTag != this.translatorClass)
  1226.   {
  1227.     result = this.translator.translateDirective(code, offset, "script", "", this.defaultDirectiveTag, this.defaultDirectiveTag, "", "", "");
  1228.   }
  1229.   else
  1230.   {
  1231.     result = this.translator.translateDirective(code, offset, "script", "", "", "", "", "", "");
  1232.   }
  1233.   if (this.inMegaLock)
  1234.   {
  1235.     var preCode = this.inStr.substr(origPosition, offset-origPosition);
  1236.     this.addToMegaLock(preCode, code, result);
  1237.   }
  1238.   else if (this.inEditMode)
  1239.   {
  1240.     this.editModeFullTranslation.add(result);
  1241.   }
  1242. }
  1243.  
  1244. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1245. // Function : TM_translateText
  1246. // Purpose  : translate the text given the translation rules
  1247. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1248. function TM_translateText(code, offset, trans)
  1249. {
  1250.   var origPosition = this.translator.getPosition();
  1251.   var result = new Object();
  1252.   result.reparse = false;
  1253.   result.translation = "";
  1254.   if (trans)
  1255.   {
  1256.     if (trans.insertBefore)
  1257.     {
  1258.       result.translation += this.translator.translateText("", offset, trans.participant, "as is", "", "", "", trans.insertBefore, "");
  1259.     }
  1260.  
  1261.     result.translation += this.translator.translateText(code, offset, trans.participant, trans.type, trans.openTag, trans.closeTag, trans.attributes, trans.display, trans.lockAttributes);
  1262.  
  1263.     if (trans.insertAfter)
  1264.     {
  1265.       result.translation += this.translator.translateText("", offset+code.length, trans.participant, "as is", "", "", "", trans.insertAfter, "");
  1266.     }
  1267.     if (trans.reparse)
  1268.     {
  1269.         result.reparse = true;
  1270.         result.useEditMode = trans.useEditMode;
  1271.     }
  1272.   }
  1273.   else
  1274.   {
  1275.     result.translation = this.translator.translateText(code, offset, "", "", "", "", "", "", "");
  1276.   }
  1277.   if (this.inMegaLock)
  1278.   {
  1279.     var preCode = this.inStr.substr(origPosition, offset-origPosition);
  1280.     this.addToMegaLock(preCode, code, result.translation);
  1281.   }
  1282.   else if (this.inEditMode)
  1283.   {
  1284.     this.editModeFullTranslation.add(result);
  1285.   }
  1286.   return result;
  1287. }
  1288.  
  1289. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1290. // Function : TM_translateAttribute
  1291. // Purpose  : translate the attribute given the translation rules
  1292. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1293. function TM_translateAttribute(code, name, trans)
  1294. {
  1295.   if (trans)
  1296.   {
  1297.     if ((this.translatorClass == "MM_CFML") && ((trans.type == "dynamic data") || (trans.type == "dynamic image")) && trans.participant != "DynamicAttribute")
  1298.     {
  1299.       if (this.CFOutput.IsEmpty())
  1300.       {
  1301.         // Need to enforce that cfoutput tags surround the dynamic data
  1302.         if (code.search(/<cfoutput\s*>/i) == -1 || code.search(/<\/cfoutput\s*>/i) == -1)
  1303.         {
  1304.           trans = null;
  1305.         }
  1306.       }
  1307.     }
  1308.   }
  1309.   if (trans)
  1310.   {
  1311.     this.translator.translateAttribute(code, name, trans.type, trans.attributes);
  1312.   }
  1313. }
  1314.  
  1315. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1316. // Function : evalExternalFunction
  1317. // Purpose    : The JavaScript interpreter needs to do some extra work (in
  1318. //          js_PutCallObject) whenever it invokes any function containing
  1319. //          an eval statement.  In order to avoid doing that processing
  1320. //          every time that TM_translateTag is called, the eval
  1321. //          statement is wrapped inside this function.
  1322. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1323. function evalExternalFunction(funcName, code, transMgr)
  1324. {
  1325.   var functionCall = funcName + "(code, transMgr);";
  1326.   return eval(functionCall);
  1327. }
  1328.  
  1329. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1330. // Function : TM_translateTag
  1331. // Purpose  : translate the tag given the translation rules
  1332. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1333. function TM_translateTag(code, offset, trans)
  1334. {
  1335.   var origPosition = this.translator.getPosition();
  1336.   var translation = "";
  1337.   if (trans && trans.type == "external")
  1338.   {
  1339.     trans = evalExternalFunction(trans.display, code, this);
  1340.   }
  1341.  
  1342.   if (trans && trans.beginMegaLock)
  1343.   {
  1344.     this.startMegaLock(offset);
  1345.   }
  1346.  
  1347.   if (trans)
  1348.   {
  1349.     if (trans.insertBefore)
  1350.     {
  1351.       translation += this.translator.translateText("", offset, trans.participant, "as is", "", "", "", trans.insertBefore, "");
  1352.     }
  1353.  
  1354.     translation += this.translator.translateTag(code, offset, trans.participant, trans.type, trans.openTag, trans.closeTag, trans.attributes, trans.display, trans.lockAttributes);
  1355.  
  1356.     if (trans.insertAfter)
  1357.     {
  1358.       translation += this.translator.translateText("", offset+code.length, trans.participant, "as is", "", "", "", trans.insertAfter, "");
  1359.     }
  1360.   }
  1361.   else
  1362.   {
  1363.     translation = this.translator.translateTag(code, offset, "", "", "", "", "", "", "");
  1364.   }
  1365.  
  1366.   if (this.inMegaLock)
  1367.   {
  1368.     var preCode = this.inStr.substr(origPosition, offset-origPosition);
  1369.     this.addToMegaLock(preCode, code, translation);
  1370.   }
  1371.   else if (this.inEditMode)
  1372.   {
  1373.     this.editModeFullTranslation.add(translation);
  1374.   }
  1375.  
  1376.   if (trans && trans.endMegaLock)
  1377.   {
  1378.     translation = this.finishMegaLock(trans.lockAttributes);
  1379.   }
  1380.  
  1381.   var endOffset = offset + code.length;
  1382.   if (this.inEditMode && (endOffset >= this.editModeEndOffset))
  1383.   {
  1384.     this.endEditMode();
  1385.   }
  1386. }
  1387.  
  1388. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1389. // Function : TM_findTagLength
  1390. // Purpose : look ahead and find the ">" that matches this "<".
  1391. // Ignore any script blocks (e.g. <% %>) you find on the way.
  1392. // Return the length of the tag.
  1393. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1394. function TM_findTagLength(searchString)
  1395. {
  1396.   // Counter to match pairs of < and >.  Starts at 1
  1397.   // because we start looking after the first <.
  1398.   var counter = 1;
  1399.  
  1400.   // Start after the first <.  Stop after the matching >.
  1401.   for (var i = 1; i < searchString.length && counter > 0; i++)
  1402.   {
  1403.     if (searchString[i] == '<')
  1404.     counter++;
  1405.     else if (searchString[i] == '>')
  1406.     counter--;
  1407.   }
  1408.  
  1409.   if (i == searchString.length && counter > 0)
  1410.   return -1;
  1411.   else
  1412.     return i;
  1413. }
  1414.  
  1415. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1416. // Function : TM_getAttributeValue
  1417. // Purpose  : pull the ID attribute for the current tag
  1418. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1419. function TM_getAttributeValue(code, attrName)
  1420. {
  1421.   var tagLength = TranslationManager.findTagLength(code);
  1422.   var tag = code.substr(0, tagLength);
  1423.  
  1424.   var value = "";
  1425.   var expression;
  1426.  
  1427.   // name="value"
  1428.   expression = new RegExp(attrName + "\\s*=\\s*\"(((<%.*?%>)|[^<\">])*)\"", "i");
  1429.   if (tag.match(expression))
  1430.     value = RegExp.$1;
  1431.  
  1432.   // name='value'
  1433.   expression = new RegExp(attrName + "\\s*=\\s*'(((<%.*?%>)|[^<'>])*)'", "i");
  1434.   if (value == "" && tag.match(expression))
  1435.     value = RegExp.$1;
  1436.  
  1437.   // name=value
  1438.   expression = new RegExp(attrName + "\\s*=\\s*(((<%.*?%>)|[^ \t\n<\"'>])*)", "i");
  1439.   if (value == "" && tag.match(expression))
  1440.     value = RegExp.$1;
  1441.  
  1442.   return value;
  1443. }
  1444.  
  1445. ///////////////////////////////////////////////////////////////////////////
  1446. // Function : TM_splitBody
  1447. // Purpose  : Static function to locate the contents of the <body>
  1448. // tag and split the document at its boundaries.  It will only attempt
  1449. // this split if the document has a single pair of <body> tags.  Some
  1450. // server models can use this to skip over the tags outside the body
  1451. // (which don't need to be translated).
  1452. ///////////////////////////////////////////////////////////////////////////
  1453. function TM_splitBody(inStr)
  1454. {
  1455.     var result = new Object();
  1456.  
  1457.     result.preInStr = "";
  1458.     result.inStr = inStr;
  1459.     result.postInStr = "";
  1460.   
  1461.   var callback = new Object();
  1462.   callback.openTagCount = 0;
  1463.   callback.closeTagCount = 0;
  1464.   callback.innerStart = -1;
  1465.   callback.innerEnd = -1;
  1466.   callback.openTagBegin = new Function("tag,offset","if (tag.toUpperCase() == \"BODY\") { this.openTagCount++; }");
  1467.   callback.openTagEnd = new Function("offset","if (this.openTagCount == 1 && this.innerStart == -1) { this.innerStart = offset; }");
  1468.   callback.closeTagBegin = new Function("tag,offset","if (tag.toUpperCase() == \"BODY\") { this.innerEnd = offset; this.closeTagCount++; }");
  1469.  
  1470.   dw.scanSourceString(inStr, callback);
  1471.  
  1472.   if (callback.innerStart >= 0 && callback.innerEnd >= 0 && 
  1473.       callback.openTagCount == 1 && callback.closeTagCount == 1)
  1474.   {
  1475.     result.preInStr = inStr.substring(0, callback.innerStart);
  1476.     result.postInStr = inStr.substring(callback.innerEnd);
  1477.     result.inStr = inStr.substring(callback.innerStart, callback.innerEnd);
  1478.  
  1479.     // DEBUG DWfile.write("C:\\TM_splitBody.txt", "preInStr = " + result.preInStr + "\r\n\r\npostInStr = " + result.postInStr + "\r\n\r\ninStr = " + result.inStr);
  1480.   }
  1481.   else
  1482.   {
  1483.    // DEBUG DWfile.write("C:\\TM_splitBody.txt", "failed " + callback.openTagCount + ", " + callback.closeTagCount);
  1484.   }
  1485.  
  1486.     return result;
  1487. }
  1488.  
  1489. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1490. // Function : TM_translateTagSpan
  1491. // Purpose  : translate the tag span given the translation rules 
  1492. // Tag span defined to be a span of the document from the open tag to its close tag
  1493. // For example <cfoutput>#a.b#</cfoutput> is a tag span
  1494. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1495. function TM_translateTagSpan(code, offset, trailingFormat)
  1496. {
  1497.   if (this.tagSpanRecover)
  1498.   {
  1499.     this.tagSpanRecover = false;
  1500.     return false;
  1501.   }
  1502.  
  1503.   var tag = this.getCurrentTagName();
  1504.   tag = tag.toLowerCase();
  1505.   this.getTranslatorInfo();
  1506.   
  1507.   var index = "tag+" + tag + ":all";
  1508.   var index2 = "tag+*:all";
  1509.   var arry = translatorInfo[this.index];
  1510.  
  1511.   var inTagSpan = false;
  1512.   
  1513.   var possibleParticipants = null;
  1514.  
  1515.   if (arry.outerHTMLParticipants)
  1516.   {
  1517.     for (var part in arry.outerHTMLParticipants)
  1518.     {
  1519.       if (!arry[part].mode || arry[part].mode == this.mode)
  1520.       {
  1521.         var translations = arry[part].translations;
  1522.         if (translations)
  1523.         {
  1524.           // Check context, mode, and any search patterns with requiredLocation="openTag" or "tagName"
  1525.           if ((translations[index] || translations[index2]) && this.searchMatchesOpenTag(part, code))
  1526.           {
  1527.             if (possibleParticipants == null)
  1528.               possibleParticipants = new Array();
  1529.             possibleParticipants.push(part);
  1530.           }
  1531.         }
  1532.       }
  1533.     }
  1534.   }
  1535.  
  1536.   if (possibleParticipants != null)
  1537.   {
  1538.     this.startTagSpan(tag, offset - code.length, possibleParticipants);
  1539.     inTagSpan = true;
  1540.   }
  1541.  
  1542.   return inTagSpan;
  1543. }
  1544.  
  1545. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1546. // Function : TM_startTagSpan
  1547. // Purpose  : Enter the tag span state.  All new tags and text will go into
  1548. // the current tag span
  1549. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1550.  
  1551. function TM_startTagSpan(tagName, offset, participants)
  1552. {
  1553.   if (debugTagSpan)
  1554.     alert("startTagSpan..." + tagName);
  1555.   this.tagSpan = new QuickString();
  1556.   this.inTagSpan = true;
  1557.   this.tagSpanName = tagName;
  1558.   this.tagSpanCounter = 0;
  1559.   this.tagSpanParts = participants;
  1560.   this.tagSpanSnapshot = new Snapshot(this.enclosingTags, offset);
  1561. }
  1562.  
  1563. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1564. // Function : TM_addToTagSpan
  1565. // Purpose  : Add text to the current tag span.
  1566. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1567.  
  1568. function isWhiteSpace(x)
  1569. {
  1570.   return x == '\r' || x == '\n' || x == '\t' || x == ' ';
  1571. }
  1572.  
  1573. function TM_addToTagSpan(code, offset)
  1574. {
  1575.   var whitespace = "";
  1576.   if (this.tagSpanLastIndex != -1)
  1577.   {
  1578.     // White space and invalid tags don't generate a call to translateText, so
  1579.     // we need to slurp in any text that's occured since the last addToTagSpan
  1580.     extraText = this.inStr.substr(this.tagSpanLastIndex, offset-this.tagSpanLastIndex);
  1581.     this.tagSpan.add(extraText);
  1582.   }
  1583.   this.tagSpan.add(code);
  1584.   this.tagSpanLastIndex = offset + code.length;
  1585. }
  1586.  
  1587. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1588. // Function : TM_addOpenTagToTagSpan
  1589. // Purpose  : Add open tag to the current tag span.  Keep track of nested
  1590. // tags (e.g. <foo><foo></foo></foo>) with the tagSpanCounter.
  1591. // Returns  : true = continue parsing, false = stop parsing
  1592. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1593.  
  1594. function TM_addOpenTagToTagSpan(code, offset, trailingFormat)
  1595. {
  1596.   if (debugTagSpan)
  1597.     alert("addOpenTagToTagSpan..." + code);
  1598.  
  1599.   var openPattern = new RegExp("^<" + this.tagSpanName + "\\b", "i");
  1600.  
  1601.   //if (this.tagSpanCounter == 0) // first tag
  1602.   if (this.tagSpanSnapshot.offset == offset-code.length) // first tag
  1603.     this.tagSpanLastIndex = -1;
  1604.   this.addToTagSpan(code, offset-code.length);
  1605.  
  1606.   var isComplete = (trailingFormat.length > 0 &&
  1607.             trailingFormat[trailingFormat.length-1] == '/');
  1608.   if (!isComplete && (code.search(openPattern) != -1))
  1609.     this.tagSpanCounter++;
  1610.  
  1611.   if (isComplete && this.tagSpanCounter == 0)
  1612.     return this.finishTagSpan();
  1613.  
  1614.   var continueTagSpan = new Object();
  1615.   continueTagSpan.success = false;
  1616.   continueTagSpan.inTagSpan = true;
  1617.   continueTagSpan.reparse = false;
  1618.   return continueTagSpan;
  1619. }
  1620.  
  1621. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1622. // Function : TM_addCloseTagToTagSpan
  1623. // Purpose  : Add close tag to the current tag span.  Keep track of nested
  1624. // tags with the tagSpanCounter.  If this is the end of the tag span, try
  1625. // to translate it.  If translation is impossible, stop parsing (we'll have
  1626. // to start over).
  1627. // Returns  : true = continue parsing, false = stop parsing
  1628. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1629.  
  1630. function TM_addCloseTagToTagSpan(code, offset)
  1631. {
  1632.   if (debugTagSpan)
  1633.     alert("addCloseTagToTagSpan..." + code);
  1634.  
  1635.   var closePattern = new RegExp("^</" + this.tagSpanName + "\\b", "i");
  1636.  
  1637.   this.addToTagSpan(code, offset-code.length);
  1638.   if (code.search(closePattern) != -1)
  1639.     this.tagSpanCounter--;
  1640.  
  1641.   if (this.tagSpanCounter == 0)
  1642.   {
  1643.     return this.finishTagSpan();
  1644.   }
  1645.  
  1646.   var continueTagSpan = new Object();
  1647.   continueTagSpan.success = false;
  1648.   continueTagSpan.inTagSpan = true;
  1649.   continueTagSpan.reparse = false;
  1650.   return continueTagSpan;
  1651. }
  1652.  
  1653. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1654. // Function : TM_finishTagSpan
  1655. // Purpose  : Try to translate the tag span.
  1656. // Returns  : true = continue parsing, false = stop parsing
  1657. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1658.  
  1659. function TM_finishTagSpan()
  1660. {
  1661.   var origPosition = this.translator.getPosition();
  1662.   if (this.inMegaLock)
  1663.   {
  1664.     // If we end up reparsing this tag span because there isn't a
  1665.     // participant match, we need to have already inserted any leading
  1666.     // whitespace into the mega lock before that happens.
  1667.     var preCode = this.inStr.substr(origPosition, this.tagSpanSnapshot.offset-origPosition);
  1668.     this.addToMegaLock(preCode, "", "");
  1669.   }
  1670.  
  1671.   var success = new Object();
  1672.   success.success = true;
  1673.   success.inTagSpan = false;
  1674.   success.reparse = false;
  1675.  
  1676.   var failure = new Object();
  1677.   failure.success = false;
  1678.   failure.inTagSpan = true;
  1679.   failure.reparse = true;
  1680.  
  1681.   var translation;
  1682.   var tagSpanString = this.tagSpan.toString();
  1683.  
  1684.   if (debugTagSpan)
  1685.     alert("finishTagSpan...\n" + tagSpanString);
  1686.  
  1687.   if (this.tagSpanCache) // Use cached translation if available
  1688.   {
  1689.     translation = this.tagSpanCache.getTranslation(tagSpanString);
  1690.     if (translation)
  1691.     {
  1692.       translation = this.correctOutlineIDs(translation);
  1693. //      alert("CACHED TRANSLATION\n==========\n" + tagSpanString +
  1694. //            "\n===========\n" + translation);
  1695.       this.translator.insertTranslation(tagSpanString, this.tagSpanSnapshot.offset, translation);
  1696.       this.inTagSpan = false;
  1697.  
  1698.       return success;
  1699.     }
  1700.   }
  1701.  
  1702.   var index = "tag+" + this.tagSpanName + ":all";
  1703.   var index2 = "tag+*:all";
  1704.   var part = this.getMatchingParticipant(index, index2,
  1705.                        this.tagSpanParts, tagSpanString);
  1706.  
  1707.   if (part != null)
  1708.   {
  1709.     var trans = this.getData(part, tagSpanString);
  1710.  
  1711.     if (trans && trans.type == "external")
  1712.     {
  1713.       trans = evalExternalFunction(trans.display, tagSpanString, this);
  1714.       // External functions for tag spans can return null to force the
  1715.       // various components of the tag span to be parsed separately.
  1716.       if (trans == null)
  1717.         return failure;
  1718.     }
  1719.  
  1720.     if (trans && trans.beginMegaLock)
  1721.     {
  1722.         this.startMegaLock(this.tagSpanSnapshot.offset);
  1723.     }
  1724.  
  1725.     // use AppendText to prevent translated attributes being
  1726.     // appended to the end tag
  1727.     var result = this.translateText(tagSpanString, this.tagSpanSnapshot.offset, trans);
  1728.  
  1729.     if (trans && trans.endMegaLock)
  1730.     {
  1731.         result.translation = this.finishMegaLock(trans.lockAttributes);
  1732.     }
  1733.  
  1734.     if (result.reparse)
  1735.     {
  1736.       if (result.useEditMode)
  1737.       {
  1738.         this.startEditMode(this.tagSpanSnapshot.offset + tagSpanString.length,
  1739.                            tagSpanString,
  1740.                            result.translation);
  1741.       }
  1742.       // We need to leave this.inTagSpan on here, so that the next parse
  1743.       // works on the individual tags instead of the whole span
  1744.       return failure;
  1745.     }
  1746.  
  1747.     if (this.tagSpanCache) // Store translation in cache if available
  1748.     {
  1749.       this.tagSpanCache.setTranslation(tagSpanString, result.translation);
  1750.     }
  1751.  
  1752.     if (this.inMegaLock)
  1753.     {
  1754.       // We already inserted the precode at the top of this function.
  1755.       this.addToMegaLock("", tagSpanString, result.translation);
  1756.     }
  1757.  
  1758.     this.inTagSpan = false;
  1759.     return success;
  1760.   }
  1761.   else
  1762.   {
  1763.     return failure;
  1764.   }
  1765. }
  1766.  
  1767. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1768. // Function : TM_correctOutlineIDs
  1769. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1770. function TM_correctOutlineIDs(translation)
  1771. {
  1772.   var oldBaseId = null;
  1773.   var newBaseId = this.translator.getOutlineId();
  1774.   var outlineId = null;
  1775.   var attr = "mmTranslatedValueOutlineID=\"OUTLINEID=";
  1776.  
  1777.   var translationPieces = translation.split(attr);
  1778.   for (var i = 1; i < translationPieces.length; i++)
  1779.   {
  1780.     translationPieces[i] = 
  1781.         translationPieces[i].replace(/^([0-9]*)\"/, "\"");
  1782.     if (oldBaseId == null)
  1783.         oldBaseId = RegExp.$1;
  1784.     outlineId = RegExp.$1 - oldBaseId + newBaseId;
  1785.     translationPieces[i] = outlineId + translationPieces[i];
  1786.   }
  1787.  
  1788.   this.translator.setOutlineId(outlineId);
  1789.   return translationPieces.join("mmTranslatedValueOutlineID=\"OUTLINEID=");
  1790. }
  1791.  
  1792. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1793. // Function : TM_getMatchingParticipant
  1794. // Purpose  : Find a participant that matches our tag.
  1795. // Arguments: specIndex = specific index (e.g. "tag+foo:all")
  1796. //        genIndex = general index (e.g. "tag+*:all")
  1797. //        partArray = array of available participants
  1798. //        code = stuff to try to match
  1799. // Returns  : true = continue parsing, false = stop parsing
  1800. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1801.  
  1802. function TM_getMatchingParticipant(specIndex, genIndex, partArray, code)
  1803. {
  1804.   var part = null;
  1805.   var arry = translatorInfo[this.index];
  1806.  
  1807.   for (index in partArray)
  1808.   {
  1809.     var possiblePart = partArray[index];
  1810.     var translations = arry[possiblePart].translations;
  1811.     if (translations)
  1812.    {
  1813.       if (translations[specIndex])
  1814.       {
  1815.         // translationType="none" skips the translation
  1816.         if (translations[specIndex].data.type == "none")
  1817.           return null;
  1818.         if (this.searchMatchesCode(possiblePart, code))
  1819.         {
  1820.           this.whereToSearch = specIndex;
  1821.           part = possiblePart;
  1822.           break;
  1823.         }
  1824.       }
  1825.       if (!part)
  1826.       {
  1827.         if (translations[genIndex])
  1828.         {
  1829.           // translationType="none" skips the translation
  1830.           if (translations[genIndex].data.type == "none")
  1831.             return null;
  1832.           if (this.searchMatchesCode(possiblePart, code))
  1833.           {
  1834.             this.whereToSearch = genIndex;
  1835.             part = possiblePart;
  1836.           }
  1837.         }
  1838.       }
  1839.     }
  1840.   }
  1841.   return part;
  1842. }
  1843.  
  1844. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1845. // Function : TM_translateTextSpan
  1846. // Purpose  : translate the text span given the translation rules 
  1847. // Text spans may contain multiple pattern matches, we will translate all
  1848. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1849. function TM_translateTextSpan(code, offset)
  1850. {
  1851.   var part = this.getParticipant(PTYPE_TEXT, code);
  1852.   if (part && part.length)
  1853.   {
  1854.     if (translatorInfo[this.index][part].patterns);
  1855.     {
  1856.       var arry = translatorInfo[this.index][part];
  1857.       for (var patternName in arry.patterns)
  1858.       {
  1859.         var pattern = arry.patterns[patternName];
  1860.         var isRE = arry.isPatternRE[patternName];
  1861.         if (isRE)
  1862.         {
  1863.           var paramNames = arry.paramNames[patternName];
  1864.           var paramArry;
  1865.           if (paramNames)
  1866.             paramArry = paramNames.split(",");
  1867.           else
  1868.             paramArry = Array();
  1869.           var re = pattern;
  1870.           re.lastIndex = 0;
  1871.           //re.compile();
  1872.           var matchesArry;
  1873.           while ((matchesArry = re.exec(code)) != null)
  1874.           {
  1875.             var params = new Array();
  1876.             for (var i = 1; i < matchesArry.length; i++)
  1877.             {
  1878.               if (paramArry && paramArry.length >= i && paramArry[i-1].length)
  1879.               {
  1880.                 params[paramArry[i-1]] = matchesArry[i];
  1881.               }
  1882.             }
  1883.             this.params = params;
  1884.             var trans = this.getData(part, matchesArry[0]);
  1885.             var translate = true;
  1886.             if ((this.translatorClass == "MM_CFML") && ((trans.type == "dynamic data") || (trans.type == "dynamic image")))
  1887.             {
  1888.               translate = !this.CFOutput.IsEmpty();
  1889.               if (translate)
  1890.               {
  1891.                 var queryName = this.CFOutput.Peek();
  1892.                 if (queryName && queryName.length && trans.attributes.indexOf("SOURCE=\"\"") != -1)
  1893.                 {
  1894.                   trans.attributes = trans.attributes.replace(/SOURCE=""/g, "SOURCE=" + queryName);
  1895.                 }
  1896.               }
  1897.             }
  1898.             if (translate)
  1899.             {
  1900.               this.translateText(matchesArry[0], offset + matchesArry.index, trans);
  1901.             }
  1902.             //if we use the exec while loop with a non-global pattern,
  1903.             // we will produce an infinite loop.  exit the loop if not global.
  1904.             if (!re.global)
  1905.             {
  1906.               alert("INTERNAL ERROR: non-global search pattern in participant: " + part);
  1907.               break;
  1908.             }
  1909.           }
  1910.         }
  1911.       }
  1912.     }
  1913.   }
  1914. }
  1915.  
  1916. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1917. // Function : TM_startMegaLock
  1918. // Purpose  : Signals the beginning of a mega lock, where several tags, tag spans,
  1919. // and so forth should be translated and aggregated into a single locked region.
  1920. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1921. function TM_startMegaLock(offset)
  1922. {
  1923.     if (this.inMegaLock)
  1924.         return;
  1925.  
  1926.     if (debugMegaLock)
  1927.         alert("StartMegaLock(" + offset + ")");
  1928.     this.translator.previewMode(true);
  1929.     this.inMegaLock = true;
  1930.     this.megaLockPreCodeOffset = offset;
  1931.     this.megaLockCode = new QuickString();
  1932.     this.megaLockTranslation = new QuickString();
  1933.     this.megaLockSnapshot = new Snapshot(this.enclosingTags, offset);
  1934. }
  1935.  
  1936. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1937. // Function : TM_addToMegaLock
  1938. // Purpose  : Keeps megaLockCode and megaLockTranslation up to date
  1939. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1940. function TM_addToMegaLock(preCode, code, translation)
  1941. {
  1942.     if (!this.inMegaLock)
  1943.         return;
  1944.  
  1945.     if (debugMegaLock)
  1946.         alert("AddToMegaLock\n" +
  1947.         "PreCode...\n" + preCode + "\n" +
  1948.         "Code...\n" + code + "\n" +
  1949.         "Translation...\n" + translation + "\n");
  1950.  
  1951.     // If this is the first translated item, we need to drop any leading
  1952.     // whitespace characters from the code and from the translation
  1953.     if (this.megaLockCode.isEmpty())
  1954.     {
  1955.         var preCodeLength = preCode.length;
  1956.         this.megaLockPreCodeOffset = this.megaLockSnapshot.offset - preCodeLength;
  1957.         this.megaLockCode.add(code);
  1958.         this.megaLockTranslation.add(translation.substr(preCodeLength));
  1959.     }
  1960.     // Otherwise, we want to include them.
  1961.     else
  1962.     {
  1963.         this.megaLockCode.add(preCode);
  1964.         this.megaLockCode.add(code);
  1965.         this.megaLockTranslation.add(translation);
  1966.     }
  1967.  
  1968.     if (debugMegaLock)
  1969.         alert("Code...\n" + this.megaLockCode.toString());
  1970.     if (debugMegaLock)
  1971.         alert("Translation...\n" + this.megaLockTranslation.toString());
  1972. }
  1973.  
  1974. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1975. // Function : TM_finishMegaLock
  1976. // Purpose  : Signals the end of a mega lock
  1977. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  1978. function TM_finishMegaLock(lockAttributes)
  1979. {
  1980.     if (!this.inMegaLock)
  1981.         return;
  1982.  
  1983.     if (debugMegaLock)
  1984.         alert("FinishMegaLock\n" +
  1985.         "PreCodeOffset..." + this.megaLockPreCodeOffset + "\n" +
  1986.         "Offset..." + this.megaLockSnapshot.offset + "\n" +
  1987.         "Code...\n" + this.megaLockCode.toString() + "\n" +
  1988.         "Translation...\n" + this.megaLockTranslation.toString());
  1989.  
  1990.     this.translator.previewMode(false);
  1991.     this.translator.resetPosition(this.megaLockPreCodeOffset);
  1992.     var megaLockCodeString = this.megaLockCode.toString();
  1993.     var result = this.translator.translateText(megaLockCodeString, this.megaLockSnapshot.offset, "", "as is", "", "", "", this.megaLockTranslation.toString(), lockAttributes);
  1994.  
  1995.     var endOffset = this.megaLockSnapshot.offset + megaLockCodeString.length;
  1996.     
  1997.     if (this.inEditMode)
  1998.     {
  1999.         this.editModeFullTranslation.add(result);
  2000.         if (endOffset >= this.editModeEndOffset)
  2001.         {
  2002.             this.endEditMode();
  2003.         }
  2004.     }
  2005.  
  2006.     this.translator.resetPosition(endOffset);
  2007.     this.inMegaLock = false;
  2008.     this.megaLockCode = null;
  2009.     this.megaLockTranslation = null;
  2010.     return result;
  2011. }
  2012.  
  2013.  
  2014. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2015. // Function : TM_startEditMode
  2016. // Purpose  : Sets things up when we've finished parsing a control in normal mode and are ready for edit mode.
  2017. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2018. function TM_startEditMode(endOffset, code, translation)
  2019. {
  2020.     this.inEditMode = true;
  2021.     this.mode = "edit";
  2022.     this.editModeEndOffset = endOffset;
  2023.     this.editModeFullCode = code;
  2024.     this.editModeFullTranslation = new QuickString(translation);
  2025. }
  2026.  
  2027.  
  2028. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2029. // Function : TM_endEditMode
  2030. // Purpose  : Wraps things up when we've finished parsing a control in normal mode and in edit mode
  2031. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2032. function TM_endEditMode()
  2033. {
  2034.     var result = this.translator.translateTag("", this.editModeEndOffset, "", "as is", "", "", "", "<mm:toggleVisibility mode=end>", "");
  2035.     this.editModeFullTranslation.add(result);
  2036.  
  2037.     if (this.tagSpanCache)
  2038.     {
  2039.       this.tagSpanCache.setTranslation(this.editModeFullCode, this.editModeFullTranslation.toString());
  2040.     }
  2041.  
  2042.     this.inEditMode = false;
  2043.     this.mode = "preview";
  2044.     this.editModeEndOffset = -1;
  2045.     this.editModeFullCode = null;
  2046.     this.editModeFullTranslation = null;
  2047. }
  2048.  
  2049.  
  2050. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2051. // Function : TM_setDecoration
  2052. // Purpose  : sets decoration on or off.  Should be off for sections of the document
  2053. //        that have been locked by the Live Data Translators.
  2054. // Arguments: decoration - true for sections that have been locked by the Live Data translator
  2055. //        false otherwise.
  2056. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2057. function TM_setDecoration(decoration) 
  2058.   this.translator.setDecoration(decoration);
  2059. }
  2060.  
  2061.  
  2062. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2063. // Function : TM_restartParse
  2064. // Purpose  : restarts Parsing of document this gets called when we encounter a meta tag that is different
  2065. //        than the default encoding.
  2066. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2067. function TM_restartParse() 
  2068.   this.translator.restartParse();
  2069. }
  2070.  
  2071. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2072. // Function : TM_pushOpenTag
  2073. // Purpose  : Updates this.enclosingTags with a new open tag
  2074. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2075. function TM_pushOpenTag(trailingFormat)
  2076. {
  2077.   var tag = this.getCurrentTagName();
  2078.   tag = tag.toLowerCase();
  2079.  
  2080.   var isComplete = (trailingFormat.length > 0 &&
  2081.             trailingFormat[trailingFormat.length-1] == '/');
  2082.   if (!isComplete)
  2083.   {
  2084.     this.enclosingTags.push(tag);
  2085.   }
  2086. }
  2087.  
  2088. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2089. // Function : TM_popCloseTag
  2090. // Purpose  : Updates this.enclosingTags with a new close tag
  2091. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2092. function TM_popCloseTag()
  2093. {
  2094.   var tag = this.getCurrentTagName();
  2095.   tag = tag.toLowerCase();
  2096.   var found = false;
  2097.   while (this.enclosingTags.length > 0 && !found)
  2098.     found = (this.enclosingTags.pop() == tag);
  2099. }
  2100.  
  2101. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2102. // Function : Snapshot class to maintain information needed to reparse document
  2103. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2104. function Snapshot(enclosingTags, offset)
  2105. {
  2106.     this.enclosingTags = enclosingTags.concat();
  2107.     this.offset = offset;
  2108. }
  2109.  
  2110. function TM_takeSnapshot(offset)
  2111. {
  2112.     return new Snapshot(this.enclosingTags, offset);
  2113. }
  2114.  
  2115. function TM_restoreSnapshot(snapshot)
  2116. {
  2117.     this.translator.offsetAdj += snapshot.offset;
  2118.     this.translator.resetPosition(0);
  2119.     this.inStr = this.inStr.substr(snapshot.offset);
  2120.     this.megaLockPreCodeOffset -= snapshot.offset;
  2121.     this.editModeEndOffset -= snapshot.offset;
  2122.     this.enclosingTags = snapshot.enclosingTags;
  2123.     // Do these last, since snapshot may be the same as megaLockSnapshot or tagSpanSnapshot
  2124.     if (this.megaLockSnapshot)
  2125.         this.megaLockSnapshot.offset -= snapshot.offset;
  2126.     if (this.tagSpanSnapshot)
  2127.         this.tagSpanSnapshot.offset -= snapshot.offset;
  2128. }
  2129.  
  2130. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2131. // Function : Stack Class to maintain cfOutput query names
  2132. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2133. function Stack()
  2134. {
  2135. // Members
  2136.   this.data = new Array(50);
  2137.   this.tos = -1;
  2138.   Stack.prototype.Push      = Stack_Push;
  2139.   Stack.prototype.Pop       = Stack_Pop;
  2140.   Stack.prototype.Peek      = Stack_Peek;
  2141.   Stack.prototype.IsEmpty     = Stack_IsEmpty;
  2142. }
  2143.  
  2144. function Stack_Push(value)
  2145. {
  2146.   if (this.tos < -1)
  2147.   {
  2148.     this.tos = -1;
  2149.   }
  2150.   this.tos += 1;
  2151.   this.data[this.tos] = value;
  2152. }
  2153.  
  2154. function Stack_Pop()
  2155. {
  2156.   var top = null;
  2157.   if (this.tos >= 0)
  2158.   {
  2159.     top = this.data[this.tos];
  2160.     this.tos -= 1;
  2161.   }
  2162.  
  2163.   return top;
  2164. }
  2165.  
  2166. function Stack_Peek()
  2167. {
  2168.   var top = null;
  2169.   if (this.tos >= 0)
  2170.   {
  2171.     top = this.data[this.tos];
  2172.   }
  2173.  
  2174.   return top;
  2175. }
  2176.  
  2177. function Stack_IsEmpty()
  2178. {
  2179.   if (this.tos < 0)
  2180.   {
  2181.     return true;
  2182.   }
  2183.  
  2184.   return false;
  2185. }
  2186.