]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - include/SugarFields/Parsers/MetaParser.php
Release 6.1.4
[Github/sugarcrm.git] / include / SugarFields / Parsers / MetaParser.php
1 <?php
2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4  * SugarCRM is a customer relationship management program developed by
5  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
6  * 
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU Affero General Public License version 3 as published by the
9  * Free Software Foundation with the addition of the following permission added
10  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
13  * 
14  * This program is distributed in the hope that it will be useful, but WITHOUT
15  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
17  * details.
18  * 
19  * You should have received a copy of the GNU Affero General Public License along with
20  * this program; if not, see http://www.gnu.org/licenses or write to the Free
21  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22  * 02110-1301 USA.
23  * 
24  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
26  * 
27  * The interactive user interfaces in modified source and object code versions
28  * of this program must display Appropriate Legal Notices, as required under
29  * Section 5 of the GNU Affero General Public License version 3.
30  * 
31  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32  * these Appropriate Legal Notices must retain the display of the "Powered by
33  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34  * technical reasons, the Appropriate Legal Notices must display the words
35  * "Powered by SugarCRM".
36  ********************************************************************************/
37
38
39 /**
40  * MetaParser.php
41  * 
42  * This is a utility base file to parse HTML
43  * @author Collin Lee
44  */
45 class MetaParser {
46
47 var $mPHPFile;
48 var $mView;
49 var $mModule;
50 var $mCustomPanels;
51
52 function MetaParser() {
53         
54 }
55
56 function parse() {
57    return "NOT AVAILABLE";      
58 }       
59
60 /**
61  * getFormContents
62  * Parses for contents enclosed within <form>...</form> tags
63  */
64 function getFormContents($contents, $all = true) {
65    if($all) { 
66       preg_match_all("'(<form[^>]*?>)(.*?)(</form[^>]*?>)'si", $contents, $matches);    
67       return $matches;
68    } 
69         
70    preg_match("'(<form[^>]*?>)(.*?)(</form[^>]*?>)'si", $contents, $matches);
71    return $this->convertToTagElement($matches);
72    //return $matches;
73 }
74
75
76 /**
77  * getFormElements
78  * Parses for input, select, textarea types from string content
79  * @param $contents The String contents to parse
80  * @return $matches Array of matches of PREG_SET_ORDER 
81  */
82 function getFormElements($contents) {
83    preg_match_all("'(<[ ]*?)(textarea|input|select)([^>]*?)(>)'si", $contents, $matches, PREG_PATTERN_ORDER);
84    $elems = array();
85    foreach($matches[3] as $match) {
86           $elems[] = $match;
87    }
88    return $elems;
89 }
90
91
92 /**
93  * getFormElementsNames
94  * Parses for the name values of input, select, textarea types from string content
95  * @param $contents The String contents to parse
96  * @return $matches Array of name/value pairs
97  */
98 function getFormElementsNames($contents) {
99    preg_match_all("'(<[ ]*?)(textarea|input|select)[^>]*?name=[\'\"]([^\'\"]*?)(\[\])?(_basic)?[\'\"]([^>]*?>)'si", $contents, $matches, PREG_PATTERN_ORDER);
100    return !empty($matches[3]) ? $matches[3] : null;
101 }
102
103
104 /**
105  * getTagAttribute
106  * Returns the name/value of a tag attribute where name is set to $name
107  * @param $name The name of the attribute
108  * @param $contents The contents to parse
109  * @param $filter Option regular expression to filter value
110  * @return Array of name/value for matching attribute
111  */
112 function getTagAttribute($name, $contents, $filter = '') {
113    //$exp = "'".$name."[ ]*?=[ ]*?[\'\"]([a-zA-Z0-9\_\[\]]*)[\'\"]'si";
114    
115    $exp = "'".$name."[\s]*?=[\s]*?[\'\"]([^\'^\"]*?)[\'\"]'si";
116    preg_match_all($exp, $contents, $matches, PREG_SET_ORDER);
117    if(empty($filter)) {
118           return !empty($matches[0][1]) ? $matches[0][1] : '';
119    }
120    
121    $filtered = array();
122    foreach($matches as $tag) {
123           if(preg_match($filter, $tag[1])) {    
124                  $filtered[] = $tag;
125           }
126    }
127    return $filtered;
128 }
129
130 /**
131  * getTables
132  * Returns an Array of the tables found in the file.  If $tableClass parameter
133  * is supplied, it'll return only those tables that have a matching class attribute 
134  * equal to $tableClass
135  * @param $tableClass Optional table class parameter value
136  * @return Array of table elements found
137  */
138 function getTables($tableClass = null, $contents) {
139    preg_match_all("'(<table[^>]*?>)(.*?)(</table[^>]*?>)'si", $contents, $matches, PREG_SET_ORDER);
140    if($tableClass == null) {
141           return $matches;
142    }
143    
144    $tables = array();
145    foreach($matches as $key => $table) {
146           if(strpos($table[1], $tableClass) > 0) {
147                  $tables[] = $table;
148           }
149    }
150    return $this->convertToTagElement($tables);
151 }
152
153 /**
154  * getElementsByType
155  * 
156  * Returns an Array of all elements matching type.  It will match
157  * for the outermost tags.  For example given contents:
158  * "<tr><td>Text <table><tr><td>a</td></tr></table></td></tr>"
159  * and method call getElementsByType("<td>", $contents) returns
160  * "<td>Text <table><tr><td>a</td></tr></table></td>"
161  * 
162  * @param $type The type of element to parse out and return 
163  * @return a tag element format Array
164  */
165 function getElementsByType($type, $contents) {
166    $x = strlen($contents);
167    $mark = 0;
168    $count = 0;
169    $stag1 = "<" . trim($type, " <>") . '>';
170    $stag2 = "<" . trim($type, " <>") . ' ';
171    $etag = "</".$type.">";
172    $sincrement = strlen($stag1);
173    $eincrement = strlen($etag);
174    $sarr = array();
175    $values = array();
176
177    while($count < $x) {
178              $stok = substr($contents, $count, $sincrement);
179              $etok = substr($contents, $count, $eincrement);
180              if($stok == $stag1 || $stok == $stag2) {
181                 //Reset mark;                    
182                 if(count($sarr) == 0) {
183                    $mark = $count;
184                 }
185             $sarr[] = $count;
186                 
187              } else if($etok == $etag) {
188                 array_shift($sarr);
189                 if(count($sarr) == 0) {
190                    $val = substr($contents, $mark, ($count - $mark) + $eincrement);
191                    $values[] = $val;
192                    $mark = $count;
193                 }       
194              }
195              $count++;
196    }
197    
198    $count = 0;
199    return $values;
200
201
202
203
204 /**
205  * getElementValue
206  * 
207  */
208 function getElementValue($type, $contents, $filter = "(.*?)") {
209    $exp = "'<".$type."[^>]*?>".$filter."</".$type."[^>]*?>'si";
210    preg_match($exp, $contents, $matches);
211    return isset($matches[1]) ? $matches[1] : '';        
212 }
213
214
215 function stripComments($contents) {
216    return preg_replace("'(<!--.*?-->)'si", "", $contents);
217 }
218
219 /**
220  * stripFlavorTags
221  * This method accepts the file contents and uses the $GLOBALS['sugar_flavor'] value
222  * to remove the flavor tags in the file contents if present.  If $GLOBALS['sugar_flavor']
223  * is not set, it defaults to PRO flavor
224  * @param $contents The file contents as a String value
225  * @param $result The file contents with non-matching flavor tags and their nested comments removed
226  */
227 function stripFlavorTags($contents) {
228    $flavor = isset($GLOBALS['sugar_flavor']) ? $GLOBALS['sugar_flavor'] : 'PRO';
229    $isPro = ($flavor == 'ENT' || $flavor == 'PRO') ? true : false;
230    if($isPro) {
231          $contents = preg_replace('/<!-- BEGIN: open_source -->.*?<!-- END: open_source -->/', '', $contents);
232    } else {
233          $contents = preg_replace('/<!-- BEGIN: pro -->.*?<!-- END: pro -->/', '', $contents);
234    }
235    return $contents;    
236 }
237
238 /**
239  * getMaxColumns
240  * Returns the highest number of <td>...</td> blocks within a <tr>...</tr> block.
241  * @param $contents The table contents to parse
242  * @param $filter Optional filter to parse for an attribute within the td block.
243  * @return The maximum column count
244  */ 
245 function getMaxColumns($contents, $filter) {
246    preg_match_all("'(<tr[^>]*?>)(.*?)(</tr[^>]*?>)'si", $contents, $matches, PREG_SET_ORDER);
247    $max = 0;
248    foreach($matches as $tableRows) {
249            $count = substr_count($tableRows[2], $filter);
250            if($count > $max) {
251                   $max = $count;
252            }
253    }
254    
255    return $max;
256 }
257
258 function convertToTagElement($matches) {
259    
260    $elements = array();
261   
262    foreach($matches as $data) {
263            // We need 4 because the 1,2,3 indexes make up start,body,end 
264            if(count($data) == 4) {
265                   $element = array();
266                   $element['start'] = $data[1];
267                   $element['body'] = $data[2];
268                   $element['end'] = $data[3];
269                   $elements[] = $element;
270            }
271    }
272
273    return empty($elements) ? $matches : $elements;      
274 }       
275
276 /*
277  * trimHTML
278  * This function removes the \r (return), \n (newline) and \t (tab) markup from string
279  */
280 function trimHTML($contents) {
281    $contents = str_replace(array("\r"), array(""), $contents);
282    $contents = str_replace(array("\n"), array(""), $contents);
283    $contents = str_replace(array("\t"), array(""), $contents);
284    return $contents;
285 }
286
287
288 /**
289  * getJavascript
290  * 
291  * This method parses the given $contents String and grabs all <script...>...</script> blocks.
292  * The method also converts values enclosed within "{...}" blocks that may need to be converted
293  * to Smarty syntax.
294  * 
295  * @param $contents The HTML String contents to parse
296  * 
297  * @return $javascript The formatted script blocks or null if none found
298  */
299 function getJavascript($contents, $addLiterals = true) {
300
301 $javascript = null;
302
303 //Check if there are Javascript blocks of code to process
304 preg_match_all("'(<script[^>]*?>)(.*?)(</script[^>]*?>)'si", $contents, $matches, PREG_PATTERN_ORDER);
305 if(empty($matches)) {
306    return $javascript;  
307 }
308
309 foreach($matches[0] as $scriptBlock) {
310             $javascript .= "\n" . $scriptBlock;
311 } //foreach
312
313 $javascript = substr($javascript, 1);
314
315 //Remove stuff first
316 //1) Calendar.setup {..} blocks
317 $javascript = preg_replace('/Calendar.setup[\s]*[\(][^\)]*?[\)][\s]*;/si', '', $javascript);
318
319 //Find all blocks that may need to be replaced with Smarty syntax
320 preg_match_all("'([\{])([a-zA-Z0-9_]*?)([\}])'si", $javascript, $matches, PREG_PATTERN_ORDER);
321 if(!empty($matches)) {
322         $replace = array();
323         
324         foreach($matches[0] as $xTemplateCode) {
325                     if(!isset($replace[$xTemplateCode])) {
326                        $replace[$xTemplateCode] = str_replace("{", "{\$", $xTemplateCode);
327                     } //if
328         } //foreach
329         
330         $javascript = str_replace(array_keys($replace), array_values($replace), $javascript);   
331 } //if
332
333 if(!$addLiterals) {
334    return $javascript;
335 }
336
337 return $this->parseDelimiters($javascript);
338         
339 }
340
341 function parseDelimiters($javascript) {
342         $newJavascript = '';
343         $scriptLength = strlen($javascript);
344         $count = 0;
345         $inSmartyVariable = false;
346         
347         while($count < $scriptLength) {
348         
349               if($inSmartyVariable) {
350                  $start = $count;
351                  $numOfChars = 1;
352                  while(isset($javascript[$count]) && $javascript[$count] != '}') {
353                            $count++;
354                            $numOfChars++;
355                  }
356                  
357                  $newJavascript .= substr($javascript, $start, $numOfChars);
358                  $inSmartyVariable = false;
359                 
360               } else {
361               
362                           $char = $javascript[$count];
363                           $nextChar = ($count + 1 >= $scriptLength) ? '' : $javascript[$count + 1];
364                          
365                           if($char == "{" && $nextChar == "$") {
366                                  $inSmartyVariable = true;
367                                  $newJavascript .= $javascript[$count];
368                           } else if($char == "{") {
369                                  $newJavascript .=  " {ldelim} ";
370                           } else if($char == "}") {
371                                  $newJavascript .= " {rdelim} ";
372                           } else {
373                              $newJavascript .= $javascript[$count];
374                           }
375               }
376                   $count++;
377         } //while
378         
379         return $newJavascript;  
380 }
381
382 /**
383  * findAssignedVariableName
384  * This method provides additional support in attempting to parse the  module's corresponding
385  * PHP file for either the EditView or DetailView.  In the event that the subclasses cannot
386  * find a matching vardefs.php entry in the HTML file, this method can be called to parse the
387  * PHP file to see if the assignment was made using the bean's variable.  If so, we return
388  * this variable name.
389  * 
390  * @param $name The tag name found in the HTML file for which we want to search
391  * @param $filePath The full file path for the HTML file
392  * @return The variable name found in PHP file, original $name variable if not found
393  */
394 function findAssignedVariableName($name, $filePath) {
395         
396         if($this->mPHPFile == "INVALID") {
397            return $name;        
398         }
399         
400         if(!isset($this->mPHPFile)) {
401            if(preg_match('/(.*?)(DetailView).html$/', $filePath, $matches)) {
402                  $dir = $matches[1];
403            } else if(preg_match('/(.*?)(EditView).html$/', $filePath, $matches)) {
404                  $dir = $matches[1];
405            }
406
407            if(!isset($dir) || !is_dir($dir)) {
408               $this->mPHPFile = "INVALID";      
409               return $name;
410            }
411
412        $filesInDir = $this->dirList($dir);
413        $phpFile = $matches[2].'.*?[\.]php';
414        foreach($filesInDir as $file) {
415           if(preg_match("/$phpFile/", $file)) {
416                  $this->mPHPFile = $matches[1] . $file;
417                  break;
418           }
419        }
420         
421        if(!isset($this->mPHPFile) || !file_exists($this->mPHPFile)) {
422           $this->mPHPFile = "INVALID";
423           return $name;
424        }
425         }
426
427         $phpContents = file_get_contents($this->mPHPFile);
428         $uname = strtoupper($name);
429         if(preg_match("/xtpl->assign[\(][\"\']".$uname."[\"\'][\s]*?,[\s]*?[\$]focus->(.*?)[\)]/si", $phpContents, $matches)) {
430            return $matches[1];
431         }
432         return $name;
433 }
434
435
436 /**
437  * dirList
438  * Utility method to list all the files in a given directory.
439  * 
440  * @param $directory The directory to scan
441  * @return $results The files in the directory that were found
442  */
443 function dirList ($directory) {
444
445     // create an array to hold directory list
446     $results = array();
447
448     // create a handler for the directory
449     $handler = opendir($directory);
450
451     // keep going until all files in directory have been read
452     while ($file = readdir($handler)) {
453         // if $file isn't this directory or its parent, 
454         // add it to the results array
455         if ($file != '.' && $file != '..')
456             $results[] = $file;
457     }
458
459     // tidy up: close the handler
460     closedir($handler);
461     return $results;
462 }
463
464
465 /**
466  * isCustomField
467  * This method checks the mixed variable $elementNames to see if it is a custom field.  A custom
468  * field is simply defined as a field that ends with "_c".  If $elementNames is an Array
469  * any matching custom field value will result in a true evaluation
470  * @param $elementNames Array or String value of form element name(s).
471  * @return String name of custom field; null if none found
472  */
473 function getCustomField($elementNames) {
474    
475    if(!isset($elementNames) || (!is_string($elementNames) && !is_array($elementNames))) {
476           return null;
477    }
478    
479    if(is_string($elementNames)) {
480           if(preg_match('/(.+_c)(_basic)?(\[\])?$/', $elementNames, $matches)) {
481                  return count($matches) == 1 ? $matches[0] : $matches[1];
482           }
483           return null;
484    }
485    
486    foreach($elementNames as $name) {
487           if(preg_match('/(.+_c)(_basic)?(\[\])?$/', $name, $matches)) {
488                  return count($matches) == 1 ? $matches[0] : $matches[1];
489           }
490    }
491    
492    return null;
493 }
494
495 function applyPreRules($moduleDir, $panels) {
496    if(file_exists("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php")) {
497           require_once("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php");
498           $class = $moduleDir."ParseRule";
499           $parseRule = new $class();    
500           $panels = $parseRule->preParse($panels, $this->mView);
501    } 
502    return $panels;      
503 }
504
505 function applyRules($moduleDir, $panels) {
506    return $this->applyPostRules($moduleDir, $panels);
507 }
508
509 function applyPostRules($moduleDir, $panels) {
510    //Run module specific rules
511    if(file_exists("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php")) {
512           require_once("include/SugarFields/Parsers/Rules/".$moduleDir."ParseRule.php");
513           $class = $moduleDir."ParseRule";
514           $parseRule = new $class();    
515           $panels = $parseRule->parsePanels($panels, $this->mView);
516    } 
517
518    //Now run defined rules
519    require_once("include/SugarFields/Parsers/Rules/ParseRules.php");
520    $rules = ParseRules::getRules();
521
522    foreach($rules as $rule) {
523           if(!file_exists($rule['file'])) {
524                  $GLOBALS['log']->error("Cannot run rule for " . $rule['file']);
525                  continue;
526           } //if
527           require_once($rule['file']);
528           $runRule = new $rule['class'];
529           $panels = $runRule->parsePanels($panels, $this->mView);
530
531    } //foreach
532    
533    return $panels;      
534 }
535
536 function createFileContents($moduleDir, $panels, $templateMeta=array(), $htmlFilePath) {
537
538 $header = "<?php\n\n";
539
540 if(empty($templateMeta)) {
541 $header .= "\$viewdefs['$moduleDir']['$this->mView'] = array(
542     'templateMeta' => array('maxColumns' => '2', 
543                             'widths' => array(
544                                             array('label' => '10', 'field' => '30'), 
545                                             array('label' => '10', 'field' => '30')
546                                             ),
547     ),";
548 } else {
549 $header .= "\$viewdefs['$moduleDir']['$this->mView'] = array(
550     'templateMeta' =>" . var_export($templateMeta, true) . ","; 
551
552
553 //Replace all the @sq (single quote tags that may have been inserted)
554 $header = preg_replace('/\@sq/', "'", $header);
555
556 /*
557 $contents = file_get_contents($htmlFilePath);
558
559 $javascript = $this->getJavascript($contents, true);
560
561 if(!empty($javascript)) {
562         $javascript = str_replace("'", "\\'", $javascript);
563         $header .= "\n 'javascript' => '" . $javascript . "',\n";       
564 } //if
565 */
566 $header .= "\n 'panels' =>";   
567
568 $footer = "
569 \n
570 );
571 ?>";
572
573    $metadata = ''; 
574    $body = var_export($panels, true);
575    $metadata = $header . $body . $footer;
576    $metadata = preg_replace('/(\d+)[\s]=>[\s]?/',"",$metadata);
577    return $metadata;
578         
579 }
580
581
582 /**
583  * mergePanels
584  * This function merges the $panels Array against the $masterCopy's meta data definition
585  * @param $panels meta data Array to merge
586  * @param $moduleDir Directory name of the module
587  * @param $masterCopy file path to the meta data master copy
588  * @return Array of merged $panel definition
589  */
590 function mergePanels($panels, $vardefs, $moduleDir, $masterCopy) {      
591    require($masterCopy);
592    $masterpanels = $viewdefs[$moduleDir][$this->mView]['panels'];
593    $hasMultiplePanels = $this->hasMultiplePanels($masterpanels);
594
595    if(!$hasMultiplePanels) {
596             $keys = array_keys($viewdefs[$moduleDir][$this->mView]['panels']);
597         if(!empty($keys) && count($keys) == 1) {
598                 if(strtolower($keys[0]) == 'default') {
599                    $masterpanels = array('default'=>$viewdefs[$moduleDir][$this->mView]['panels'][$keys[0]]);
600                 } else {
601                    $firstPanel = array_values($viewdefs[$moduleDir][$this->mView]['panels']);
602                    $masterpanels = array('default'=> $firstPanel[0]);
603                 }
604         } else {
605                 $masterpanels = array('default'=>$viewdefs[$moduleDir][$this->mView]['panels']);
606         }
607    }
608    foreach($masterpanels as $name=>$masterpanel) {
609                if(isset($panels[$name])) {
610                           // Get all the names in the panel
611                           $existingElements = array();
612                           $existingLocation = array();
613                           
614                           foreach($panels[$name] as $rowKey=>$row) {
615                                  foreach($row as $colKey=>$column) {
616                                         if(is_array($column) && !empty($column['name'])) {
617                                            $existingElements[$column['name']] = $column['name'];
618                                            $existingLocation[$column['name']] = array("panel"=>$name, "row"=>$rowKey, "col"=>$colKey);  
619                                         } else if(!is_array($column) && !empty($column)) {
620                                            $existingElements[$column] = $column;
621                                            $existingLocation[$column] = array("panel"=>$name, "row"=>$rowKey, "col"=>$colKey);  
622                                         }
623                                  } //foreach
624                           } //foreach
625                           
626                           // Now check against the $masterCopy
627                           foreach($masterpanel as $rowKey=>$row) {
628                                 
629                                  $addRow = array();
630         
631                                  foreach($row as $colKey=>$column) {
632                                         if(is_array($column) && isset($column['name'])) {
633                                            $id = $column['name'];       
634                                         } else if(!is_array($column) && !empty($column)) {
635                                            $id = $column;
636                                         } else {
637                                            continue;    
638                                         }
639                                         if(empty($existingElements[$id])) {
640                                            //Only add if 
641                                            // 1) if it is a required field (as defined in metadata)
642                                            // 2) or if it has a customLabel and customCode (a very deep customization)
643                                            if((is_array($column) && !empty($column['displayParams']['required'])) ||
644                                               (is_array($column) && !empty($column['customCode']) && !empty($column['customLabel']))) {
645                                                   $addRow[] = $column;
646                                            }
647                                         } else {
648                                            //Use definition from master copy instead
649                                            $panels[$existingLocation[$id]['panel']][$existingLocation[$id]['row']][$existingLocation[$id]['col']] = $column;
650                                         }                       
651                                  } //foreach
652                                  
653                                  // Add it to the $panels 
654                                  if(!empty($addRow)) {
655                                         $panels[$name][] = $addRow;
656                                  }
657                           } //foreach
658                           
659                } else {
660                           $panels[$name] = $masterpanel;
661                }
662    } //foreach
663    
664    // We're not done yet... go through the $panels Array now and try to remove duplicate
665    // or empty panels
666    foreach($panels as $name=>$panel) {
667            if(count($panel) == 0 || !isset($masterpanels[$name])) {
668                   unset($panels[$name]);
669            }
670    } //foreach
671
672    return $panels;
673 }
674
675 /**
676  * mergeTemplateMeta
677  * This function merges the $templateMeta Array against the $masterCopy's meta data definition
678  * @param $templateMeta meta data Array to merge
679  * @param $moduleDir Directory name of the module
680  * @param $masterCopy file path to the meta data master copy
681  * @return Array of merged $templateMeta definition
682  */
683 function mergeTemplateMeta($templateMeta, $moduleDir, $masterCopy) {
684    require($masterCopy);
685    $masterTemplateMeta = $viewdefs[$moduleDir][$this->mView]['templateMeta'];
686
687    if(isset($masterTemplateMeta['javascript'])) {
688           //Insert the getJSPath code back into src value
689           $masterTemplateMeta['javascript'] = preg_replace('/src\s*=\s*[\'\"].*?(modules\/|include\/)([^\.]*?\.js)([^\'\"]*?)[\'\"]/i', 'src="@sq . getJSPath(@sq${1}${2}@sq) . @sq"', $masterTemplateMeta['javascript']);
690           // BEGIN SUGAR INT
691           //$GLOBALS['log']->fatal(var_export($masterTemplateMeta['javascript'], true));
692           // END SUGAR INT
693    }
694    
695    return $masterTemplateMeta;  
696 }
697
698 function hasRequiredSpanLabel($html) {
699    if(empty($html)) {
700           return false;
701    }
702    
703    return preg_match('/\<(div|span) class=(\")?required(\")?\s?>\*<\/(div|span)>/si', $html);
704 }
705
706 function hasMultiplePanels($panels) {
707
708    if(!isset($panels) || empty($panels) || !is_array($panels)) {
709           return false;
710    }
711    
712    if(is_array($panels) && (count($panels) == 0 || count($panels) == 1)) {
713           return false;
714    }    
715    
716    foreach($panels as $panel) {
717           if(!empty($panel) && !is_array($panel)) {
718                  return false;
719           } else {
720                  foreach($panel as $row) {
721                     if(!empty($row) && !is_array($row)) {
722                        return false;            
723                     } //if
724                  } //foreach
725           } //if-else
726    } //foreach
727    
728    return true;
729 }
730
731 function getRelateFieldName($mixed='') {
732    if(!is_array($mixed)) {
733           return '';
734    } else if(count($mixed) == 2){
735       $id = '';
736           $name = '';
737           foreach($mixed as $el) {
738                  if(preg_match('/_id$/', $el)) {
739                     $id = $el;
740                  } else if(preg_match('/_name$/', $el)) {
741                     $name = $el;
742                  }
743           }
744           return (!empty($id) && !empty($name)) ? $name : '';
745    }
746    return '';
747 }
748
749 function getCustomPanels() {
750    return $this->mCustomPanels; 
751 }
752
753 /**
754  * fixTablesWithMissingTr
755  * This is a very crude function to fix instances where files declared a table as
756  * <table...><td> instead of <table...><tr><td>.  Without this helper function, the
757  * parsing could messed up.
758  * 
759  */
760 function fixTablesWithMissingTr($tableContents) {
761    if(preg_match('/(<table[^>]*?[\/]?>\s*?<td)/i', $tableContents, $matches)) {
762           return preg_replace('/(<table[^>]*?[\/]?>\s*?<td)/i', '<table><tr><td', $tableContents);
763    }
764    return $tableContents;
765 }
766
767 /**
768  * fixRowsWithMissingTr
769  * This is a very crude function to fix instances where files have an </tr> tag immediately followed by a <td> tag
770  */
771 function fixRowsWithMissingTr($tableContents) {
772    if(preg_match('/(<\/tr[^>]*?[\/]?>\s*?<td)/i', $tableContents, $matches)) {
773           return preg_replace('/(<\/tr[^>]*?[\/]?>\s*?<td)/i', '</tr><tr><td', $tableContents);
774    }
775    return $tableContents;
776 }
777
778 /**
779  * fixDuplicateTrTags
780  * This is a very crude function to fix instances where files have two consecutive <tr> tags
781  */
782 function fixDuplicateTrTags($tableContents) {
783    if(preg_match('/(<tr[^>]*?[\/]?>\s*?<tr)/i', $tableContents, $matches)) {
784           return preg_replace('/(<tr[^>]*?[\/]?>\s*?<tr)/i', '<tr', $tableContents);
785    }
786    return $tableContents;       
787 }
788
789 /**
790  * findSingleVardefElement
791  * Scans array of form elements to see if just one is a vardef element and, if so,
792  * return that vardef name
793  */
794 function findSingleVardefElement($formElements=array(), $vardefs=array()) {
795    if(empty($formElements) || !is_array($formElements)) {
796           return '';
797    }
798    
799    $found = array();
800    foreach($formElements as $el) {
801            if(isset($vardefs[$el])) {
802                   $found[] = $el;
803            }
804    }
805    
806    return count($found) == 1 ? $found[0] : '';
807 }
808
809         
810 }
811 ?>