Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
design_edit_fns.inc
1 <?php
17 require_once SQ_FUDGE_PATH.'/wysiwyg/wysiwyg.inc';
18 require_once SQ_CORE_PACKAGE_PATH.'/designs/design_area/design_area_edit_fns.inc';
19 require_once SQ_FUDGE_PATH.'/general/file_system.inc';
20 
33 {
34 
35 
40  public function __construct()
41  {
42  parent::__construct();
43  $this->static_screens['details']['force_unlock'] = FALSE;
44 
45  }//end constructor
46 
47 
58  public function paintParseFile(Design $asset, Backend_Outputter $o, $prefix)
59  {
60  if ($asset->writeAccess('parsing')) {
61  file_upload($prefix.'_parse_file');
62  return TRUE;
63  }
64  return FALSE;
65 
66  }//end paintParseFile()
67 
68 
79  public function processParseFile(Design $asset, Backend_Outputter $o, $prefix)
80  {
81 
82  // make sure a file was uploaded before processing it
83  $upload_info = get_file_upload_info($prefix.'_parse_file');
84  if (empty($upload_info)) return FALSE;
85 
86  $parse_file = $asset->data_path.'/parse.txt';
87  $changes = FALSE;
88  $new_version = FALSE;
89 
90  $fv = $GLOBALS['SQ_SYSTEM']->getFileVersioning();
91 
92  $info = get_file_upload_info($prefix.'_parse_file');
93  if(!isset($info['tmp_name'])) {
94  trigger_error('Design parse file is not found', E_USER_WARNING);
95  return FALSE;
96  }
97  $parse_file_content = file_get_contents($info['tmp_name']);
98  if(empty($parse_file_content)) {
99  trigger_error('Empty design parse file is not allowed', E_USER_WARNING);
100  return FALSE;
101  }
102 
103  // delete existing parse file if it exists
104  if (is_file($parse_file)) {
105  $new_version = TRUE;
106  if (!unlink($parse_file)) {
107  trigger_localised_error('CORE0164', E_USER_WARNING);
108  return FALSE;
109  }
110  }
111 
112  // copy over the uploaded file
113  if (commit_file_upload($prefix.'_parse_file', $parse_file, TRUE)) {
114  // tell the asset to update the customisation at the end of the interface processing
115  $asset->_tmp['update_customisations'] = TRUE;
116  $asset->_tmp['generate_design'] = TRUE;
117  $changes = $this->parseAndProcessFile($asset);
118 
119  // if we are overwriting our current parse file, we need to add a new version to the repository
120  if ($new_version) {
121  $file_status = $fv->upToDate($parse_file);
122  if (FUDGE_FV_MODIFIED & $file_status) {
123  if (!$fv->commit($parse_file, '')) {
124  trigger_localised_error('CORE0160', E_USER_WARNING);
125  }
126  }
127  } else {
128  // attempt to add the parse file to the repository
129  if (!$fv->add($asset->data_path_suffix, $parse_file, '')) {
130  trigger_localised_error('CORE1057', E_USER_WARNING);
131  }
132  }
133  }//end if file uploaded
134 
135  // make sure we have the latest version of our file
136  if (!$fv->checkOut($asset->data_path_suffix.'/parse.txt', $asset->data_path)) {
137  trigger_localised_error('CORE0158', E_USER_WARNING);
138  return FALSE;
139  }
140 
141  return $changes;
142 
143  }//end processParseFile()
144 
145 
156  public function paintReparseFile(Design $asset, Backend_Outputter $o, $prefix)
157  {
158  if ($asset->writeAccess('attributes')) {
159  $parse_file = $asset->data_path.'/parse.txt';
160  if (!is_file($parse_file)) {
161  echo translate('core_no_existing_parsefile');
162  } else {
163  check_box($prefix.'_reparse');
164  label(translate('core_manually_reparse'), $prefix.'_reparse');
165  }
166  return TRUE;
167  }
168  return FALSE;
169 
170  }//end paintReparseFile()
171 
172 
183  public function processReparseFile(Design $asset, Backend_Outputter $o, $prefix)
184  {
185  if (isset($_POST[$prefix.'_reparse'])) {
186  if ($this->parseAndProcessFile($asset)) {
187  $asset->_tmp['update_customisations'] = TRUE;
188  $asset->_tmp['generate_design'] = TRUE;
189  return TRUE;
190  }
191  }
192  return FALSE;
193 
194  }//end processReparseFile()
195 
196 
207  public function paintEditParseFile(Design $asset, Backend_Outputter $o, $prefix)
208  {
209  require_once SQ_FUDGE_PATH.'/general/file_system.inc';
210 
211  if (SQ_ROLLBACK_VIEW) {
212  // get an older version of the parse file
213  $fv = $GLOBALS['SQ_SYSTEM']->getFileVersioning();
214  $rep_file = $asset->data_path_suffix.'/parse.txt';
215  $then = iso8601_ts($_SESSION['sq_rollback_view']['rollback_time']);
216  $info = @$fv->_checkOutCheck($rep_file, NULL, $then);
217  $parse_file = $info['source_file'];
218  } else {
219  $parse_file = $asset->data_path.'/parse.txt';
220  }
221  if (!is_file($parse_file)) {
222  echo translate('core_require_upload_parsefile');
223  return TRUE;
224  }
225 
226  $str = file_to_string($parse_file);
227 
228  if ($asset->writeAccess('parsing')) {
229  text_area($prefix.'_new_parse_file', str_replace("\t", ' ', $str), 0, 0, 0, 'style="font-family: \'Courier New\', Courier, monospace; white-space: pre-wrap; width: 99%; height: 480px"');
230  return TRUE;
231  } else {
232  // FR #2381 - Colour coding the parse file
233  $str = htmlspecialchars($str);
234  $plain_str = $str;
235 
236  // Mysource codes
237  $my_style = 'style="color:#FF0517;font-weight:bold;"';
238  $mysrc_search = Array(
239  '/&lt;MySource_(.*?(&gt;))/ims',
240  '/&lt;\/MySource_(.*?(&gt;))/ims',
241  );
242  $mysrc_replace = Array(
243  '<span '.$my_style.'>&lt;MySource_${1}</span>',
244  '<span '.$my_style.'>&lt;/MySource_${1}</span>',
245  );
246  $str = preg_replace($mysrc_search, $mysrc_replace, $str);
247 
248  // CSS codes
249  function wrap_css($matches)
250  {
251  $css_style = 'style="color:#6A287E;font-style:italic;"';
252  $return_string = '';
253  $return_string .= '<span '.$css_style.'>&lt;style'.$matches[1];
254  $white_space = Array("\r\n", "\n", "\r");
255  $return_string .= str_replace($white_space, "</span>\n<span ".$css_style.'>', $matches[3]);
256  $return_string .= '</span>';
257  return $return_string;
258  }
259  $css_search = Array(
260  '/&lt;style(.*?(&gt;))(.*?(&lt;\/style&gt;))/ims',
261  );
262  $str = preg_replace_callback($css_search, "wrap_css", $str);
263 
264  // HTML codes
265  $html_style = 'style="color:#0000A0;"';
266  $html_keywords = '!DOCTYPE|a|html|head|title|meta|link|body|script|div|span|h1|h2|h3|h4|h5|h6|ul|li|ol|table|tr|td|th|p|br|strong|pre';
267  $html_search = Array(
268  '/&lt;('.$html_keywords.')&gt;/i',
269  '/&lt;('.$html_keywords.')(.*?(\/&gt;))/ims',
270  '/&lt;('.$html_keywords.')(.*?(&gt;))/ims',
271  '/&lt;\/('.$html_keywords.')&gt;/ims',
272  );
273  $html_replace = Array(
274  '<span '.$html_style.'>&lt;${1}&gt;</span>',
275  '<span '.$html_style.'>&lt;${1}${2}</span>',
276  '<span '.$html_style.'>&lt;${1}${2}</span>',
277  '<span '.$html_style.'>&lt;/${1}&gt;</span>',
278  );
279  $str = preg_replace($html_search, $html_replace, $str);
280 
281  // Comments
282  function wrap_comment($matches)
283  {
284  $cmmt_style = 'style="color:#347C17;"';
285  $return_string = '';
286  $return_string .= '<span '.$cmmt_style.'>&lt;!-- ';
287  $white_space = Array("\r\n", "\n", "\r");
288  $return_string .= str_replace($white_space, "</span>\n<span ".$cmmt_style.'>', $matches[1]);
289  $return_string .= '</span>';
290  return $return_string;
291  }
292  $cmmt_search = Array(
293  '/&lt;!--(.*?(--&gt;))/ims',
294  );
295  $str = preg_replace_callback($cmmt_search, "wrap_comment", $str);
296 
297  // Line Numbering and cleanup
298  $pre_style = 'style="size:10px;font-family:helvetica,verdana,sans-serif;"';
299  $line_style = 'style="color:black;list-style-type:decimal;border-left: thin solid #000000;"';
300  $lines = explode("\n", $str);
301  $number_of_lines = count($lines);
302  $padding = strlen($number_of_lines);
303  foreach ($lines as $line_number => $line) {
304  // Format each line
305  $lines[$line_number] = '<li '.$line_style.' value="'.($line_number+1).'">&nbsp;&nbsp;'.$line.'</li>';
306  }
307  $formatted = implode('', $lines);
308  echo '<pre ', $pre_style, '><ol>', $formatted, '</ol></pre>';
309  }
310  return FALSE;
311 
312  }//end paintEditParseFile()
313 
314 
325  public function processEditParseFile(Design $asset, Backend_Outputter $o, $prefix)
326  {
327  if (isset($_POST[$prefix.'_new_parse_file'])) {
328 
329  $parse_file = $asset->data_path.'/parse.txt';
330  $new_file = $_POST[$prefix.'_new_parse_file'];
331 
332  if (!is_file($parse_file)) return FALSE;
333 
334  $fv = $GLOBALS['SQ_SYSTEM']->getFileVersioning();
335 
336  if(empty($new_file)) {
337  trigger_error('Empty design parse file is not allowed', E_USER_WARNING);
338  return;
339  }
340 
341  // copy over the uploaded file
342  require_once SQ_FUDGE_PATH.'/general/file_system.inc';
343  if (string_to_file($new_file, $parse_file)) {
344  // tell the asset to update the customisation at the end of the interface processing
345  $asset->_tmp['update_customisations'] = TRUE;
346  $asset->_tmp['generate_design'] = TRUE;
347  $changes = $this->parseAndProcessFile($asset);
348 
349  // add a new version to the repository
350  $file_status = $fv->upToDate($parse_file);
351  if (FUDGE_FV_MODIFIED & $file_status) {
352  if (!$fv->commit($parse_file, '')) {
353  trigger_localised_error('CORE0160', E_USER_WARNING);
354  }
355  } else {
356  $changes = TRUE;
357  }
358 
359  } else {
360  trigger_localised_error('CORE0167', E_USER_WARNING);
361  }
362 
363  // make sure we have the latest version of our file
364  if (!$fv->checkOut($asset->data_path_suffix.'/parse.txt', $asset->data_path)) {
365  trigger_localised_error('CORE0158', E_USER_WARNING);
366  return FALSE;
367  }
368 
369  if ($changes) {
370  return $this->parseAndProcessFile($asset);
371  }
372  }//end if new parse file submitted
373 
374  return FALSE;
375 
376  }//end processEditParseFile()
377 
378 
389  public function paintNewFiles(Design $asset, Backend_Outputter $o, $prefix)
390  {
391  if (!$asset->writeAccess('links')) return FALSE;
392  for ($i = 0; $i < 2; $i++) {
393  file_upload($prefix.'_assoc_file_'.$i);
394  echo "<br />\n";
395  }
396 
397  }//end paintNewFiles()
398 
399 
410  public function processNewFiles(Design $asset, Backend_Outputter $o, $prefix)
411  {
412  require_once SQ_FUDGE_PATH.'/general/file_system.inc';
413 
414  $changes = FALSE;
415 
416  for ($i = 0; $i < 2; $i++) {
417  $info = get_file_upload_info($prefix.'_assoc_file_'.$i);
418  if (empty($info)) continue;
419 
420  // if this is a tar archive, extract it
421  if (preg_match('/\\.tar\\.gz$/', $info['name'])
422  || preg_match('/\\.tgz$/', $info['name'])
423  || preg_match('/\\.tar$/', $info['name']) ) {
424 
425  require_once 'Archive/Tar.php';
426  $tar_ball = new Archive_Tar($info['tmp_name']);
427  if (($contents = $tar_ball->listContent()) != 0) {
428 
429  // Basically we want to make sure that all the files in the
430  // tar ball end up in a single directory, so we have to mess about with the extracting a bit
431  $extract_list = Array();
432  foreach ($contents as $entry) {
433  if ($entry['typeflag'] != '0' && $entry['typeflag'] != '') {
434  continue;
435  }
436 
437  $k = dirname($entry['filename']);
438  if (!isset($extract_list[$k])) {
439  $extract_list[$k] = Array();
440  }
441  $extract_list[$k][] = $entry['filename'];
442 
443  }//end foreach
444 
445  foreach ($extract_list as $remove_path => $files) {
446  // extract the files from the tar archive to a temporary directory
447  $files_dir = $asset->data_path.'/.temp_files';
448  if (!create_directory($files_dir)) return FALSE;
449  if (!clear_directory($files_dir)) return FALSE;
450 
451  $result = $tar_ball->extractList($files, $files_dir, $remove_path);
452  if (!$result) {
453  trigger_error('Failed to extract tar archive', E_USER_WARNING);
454  break;
455  } else {
456  $GLOBALS['SQ_SYSTEM']->am->includeAsset('file');
457  $design_link = Array('asset' => &$asset, 'link_type' => SQ_LINK_TYPE_2, 'value' => '', 'sort_order' => 1, 'is_dependant' => 1);
458 
459  foreach ($files as $filename) {
460  $filename = preg_replace('|^'.$remove_path.'/|', '', $filename);
461  $temp_path = $files_dir.'/'.$filename;
462  $temp_info = Array('name' => $filename, 'tmp_name' => $temp_path);
463  $temp_info['non_uploaded_file'] = TRUE;
464  if ($this->_processUploadedFile($asset, $temp_info)) {
465  $changes = TRUE;
466  }
467  }
468  }
469 
470  delete_directory($files_dir);
471 
472  }//end foreach
473 
474  }//end if
475 
476  // just create the file asset
477  } else {
478 
479  if ($this->_processUploadedFile($asset, $info)) {
480  $changes = TRUE;
481  }
482 
483  }//end if tar archive
484 
485  }//end for
486 
487  return $changes;
488 
489  }//end processNewFiles()
490 
491 
501  public function _processUploadedFile(Design $asset, $info=Array())
502  {
503  require_once SQ_FUDGE_PATH.'/general/file_system.inc';
504 
505  $existing_ids = Array();
506  $existing = $GLOBALS['SQ_SYSTEM']->am->getLinks($asset->id, SQ_LINK_TYPE_2, 'file', FALSE);
507 
508  foreach ($existing as $link) {
509  $existing_ids[$link['minorid']] = $link['linkid'];
510  }
511 
512  $existing_info = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo(array_keys($existing_ids));
513 
514  // must web-path-ify the new file name to compare, as this is eventually
515  // it's what the file will be named
516  $new_file_name = make_valid_web_paths(Array($info['name']));
517  $new_file_name = array_shift($new_file_name);
518 
519  $existing_fileid = 0;
520  foreach ($existing_info as $asset_id => $asset_info) {
521  // if the name is the same, delete the link
522  if ($asset_info['name'] == $new_file_name) {
523  $existing_fileid = $asset_id;
524  break;
525  }
526  }
527 
528  if (!$existing_fileid) {
529  // Check the filetype of the file being uploaded and create the
530  // appropriate asset type
531  switch (get_file_type($info['name'])) {
532  case 'css' :
533  $new_asset_type = 'text_file';
534  break;
535  case 'gif' :
536  case 'jpg' :
537  case 'jpeg' :
538  case 'png' :
539  $new_asset_type = 'image';
540  break;
541  default :
542  $new_asset_type = 'file';
543  break;
544  }//end switch
545 
546  $GLOBALS['SQ_SYSTEM']->am->includeAsset($new_asset_type);
547  $new_file = new $new_asset_type();
548  $new_file->_tmp['uploading_file'] = TRUE;
549  $new_file->setAttrValue('name', $info['name']);
550  $design_link = Array('asset' => &$asset, 'link_type' => SQ_LINK_TYPE_2, 'value' => '', 'sort_order' => 1, 'is_dependant' => 1);
551 
552  return $new_file->create($design_link, $info);
553 
554  } else {
555 
556  // we already have a design file with the same name, so just upload over the top of it
557  $new_file = $GLOBALS['SQ_SYSTEM']->am->getAsset($existing_fileid);
558 
559  $lock_status = $GLOBALS['SQ_SYSTEM']->am->acquireLock($new_file->id, 'attributes');
560  $edit_fns = $new_file->getEditFns();
561  $o = NULL;
562  $success = $edit_fns->processFileUpload($new_file, $o, $new_file->getPrefix(), $info);
563 
564  if ($lock_status === 1) {
565  $GLOBALS['SQ_SYSTEM']->am->releaseLock($new_file->id, 'attributes');
566  }
567 
568  return $success;
569  }
570 
571  }//end _processUploadedFile()
572 
573 
584  public function paintNewCustomisation(Design $asset, Backend_Outputter $o, $prefix)
585  {
586  if (!$asset->writeAccess('all')) {
587  $type_name = $GLOBALS['SQ_SYSTEM']->am->getTypeInfo($asset->type(), 'name');
588  echo translate('core_design_must_acquire_locks_new_customisation', strtolower($type_name));
589  return FALSE;
590  }
591 
592  check_box($prefix.'_new_customisation');
593  text_box($prefix.'_new_customisation_name', $asset->name.' - Customisation', 40);
594  return TRUE;
595 
596  }//end paintNewCustomisation()
597 
598 
609  public function processNewCustomisation(Design $asset, Backend_Outputter $o, $prefix)
610  {
611  if (empty($_POST[$prefix.'_new_customisation']) || !($new_name = trim($_POST[$prefix.'_new_customisation_name']))) {
612  return FALSE;
613  }
614 
615  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
616  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
617 
618  // First let's duplicate ourselves, ignoring dependants and the directory with the files
619  $map = Array();
620  // the new link
621  $create_link = Array();
622  // increase run level to allow setting of components without cloning permissions from parents
623  if ($asset->writeAccess('all')) {
624  $GLOBALS['SQ_SYSTEM']->setRunLevel($GLOBALS['SQ_SYSTEM']->getRunLevel() & SQ_RUN_LEVEL_FORCED);
625  // This clone will be morphed to customisation later, so it will NOT clone the parse file.
626  $asset->_tmp['custom'] = TRUE;
627  $clone = $GLOBALS['SQ_SYSTEM']->am->cloneAsset($asset, $create_link, $map, Array('attributes', 'permissions', 'roles'), FALSE);
628  unset ($asset->_tmp['custom']);
629  $GLOBALS['SQ_SYSTEM']->restoreRunLevel();
630  }
631 
632  if (is_null($clone)) {
633  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
634  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
635  return FALSE;
636  }
637 
638  // Acquire a lock on the new object
639  if (!$GLOBALS['SQ_SYSTEM']->am->acquireLock($clone->id, 'all')) {
640  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
641  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
642  return FALSE;
643  }
644 
645  // Now let's morph the dupe into a design customisation
646  if (!$cloned = $clone->morph('design_customisation')) {
647  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
648  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
649  return FALSE;
650  }
651 
652  // and link it back to ourselves
653  if (!$asset->createLink($cloned, SQ_LINK_TYPE_2, 'customisation', NULL, '1', '1')) {
654  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
655  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
656  return FALSE;
657  }
658  if (!($cloned->setAttrValue('id_name', $new_name) && $cloned->saveAttributes())) {
659  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
660  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
661  return FALSE;
662  }
663 
664  $am = $GLOBALS['SQ_SYSTEM']->am;
665 
666  // Now create the links to our design areas
667  $da_links = $asset->getDesignAreaLink();
668  foreach ($da_links as $link) {
669  $da = $am->getAsset($link['minorid'], $link['minor_type_code'], TRUE);
670  if (is_null($da)) continue;
671  if (!$cloned->createLink($da, SQ_LINK_TYPE_3, $link['value'], NULL, '1')) {
672  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
673  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
674  return FALSE;
675  }
676  }//end foreach
677 
678  // set an initial web path
679  $initial_path = strtolower($new_name);
680  require_once SQ_INCLUDE_PATH.'/general_occasional.inc';
681  $valid_paths = make_valid_web_paths(Array($initial_path));
682  $good_paths = $GLOBALS['SQ_SYSTEM']->am->webPathsInUse($asset, $valid_paths, $cloned->id, TRUE);
683  if (!$cloned->saveWebPaths($good_paths)) {
684  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
685  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
686  return FALSE;
687  }
688 
689  // link up all the files from this design to the customisation
690  $file_link_ids = Array();
691  $file_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($asset->id, SQ_LINK_TYPE_2 | SQ_LINK_TYPE_3, 'file', FALSE);
692  foreach ($file_links as $link) {
693  $minor = $am->getAsset($link['minorid'], $link['minor_type_code']);
694  if (!$cloned->createLink($minor, SQ_LINK_TYPE_3, '', NULL, 1)) {
695  trigger_localised_error('CORE0162', E_USER_WARNING);
696  $am->forgetAsset($minor);
697  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
698  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
699  return FALSE;
700  }
701  }
702  $am->forgetAsset($minor);
703 
704  // link up all the css files from this design to the customisation
705  $css_link_ids = Array();
706  $css_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($asset->id, SQ_LINK_TYPE_2 | SQ_LINK_TYPE_3, 'design_css', FALSE);
707  foreach ($css_links as $link) {
708  $minor = $am->getAsset($link['minorid'], $link['minor_type_code']);
709  if (!$cloned->createLink($minor, SQ_LINK_TYPE_3, '', NULL, 1)) {
710  trigger_localised_error('CORE0161', E_USER_WARNING);
711  $am->forgetAsset($minor);
712  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
713  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
714  return FALSE;
715  }
716  }
717  $am->forgetAsset($minor);
718 
719  // release the lock on the new object
720  if (!$GLOBALS['SQ_SYSTEM']->am->releaseLock($cloned->id, 'all')) {
721  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
722  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
723  return FALSE;
724  }
725 
726  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
727  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
728 
729  return TRUE;
730 
731  }//end processNewCustomisation()
732 
733 
744  public function paintCurrentCustomisations(Design $asset, Backend_Outputter $o, $prefix)
745  {
746  $customisation_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($asset->id, SQ_LINK_TYPE_2, 'design_customisation', TRUE, 'major', 'customisation');
747  if ($customisation_links) {
748  $am = $GLOBALS['SQ_SYSTEM']->am;
749  foreach ($customisation_links as $link) {
750  echo get_asset_tag_line($link['minorid'], 'details').'<br/>';
751  }
752 
753  } else {
754  echo translate('core_design_no_customisations_created');
755  }
756 
757  }//end paintCurrentCustomisations()
758 
759 
768  public function parseAndProcessFile(Design $asset)
769  {
770  $parse_file = $asset->data_path.'/parse.txt';
771  require_once SQ_FUDGE_PATH.'/general/file_system.inc';
772  $str = file_to_string($parse_file);
773  $contents = $this->_parseString($asset, $str);
774  $res = (!is_null($contents) && $this->_processContents($asset, $contents) && $asset->saveAttributes());
775  return $res;
776 
777  }//end parseAndProcessFile()
778 
779 
789  public function _parseString(Design $asset, $file_contents)
790  {
791  // convert the head and body tags to lowercase
792  $file_contents = preg_replace( Array('/<head/i', '/<\\/head/i', '/<body/i', '/<\\/body/i'),
793  Array('<head', '</head', '<body', '</body'),
794  $file_contents);
795 
796 
797  // Let's place an print operation after the head tag
798  // to allow us to print the default header stuff like
799  // style sheets, JS files and meta tag stuff
800  if(strpos($file_contents, '</head>') !== FALSE) {
801  $file_contents = str_replace('</head>', "\n<".$this->tag_name."_PRINT id_name='__global__' var='html_header' />\n</head>", $file_contents);
802  }
803 
804  // Let's place an print operation after the termination body tag
805  // to allow us to print the anything that has come to our attention
806  // like image rollovers
807  if(strpos($file_contents, '</body>') !== FALSE) {
808  $file_contents = str_replace('</body>', "\n<".$this->tag_name."_PRINT id_name='__global__' var='html_footer' />\n</body>", $file_contents);
809  }
810 
811 
812  return parent::_parseString($file_contents);
813 
814  }//end _parseString()
815 
816 
826  public function _processContents(Design $asset, Array $contents)
827  {
828  $id_names = Array();
829  // let's check to see if all the design areas have unique names
830  foreach ($contents as $index => $element) {
831  if ($element['_type'] != 'TAG' || $element['operation'] != 'area') {
832  continue;
833  }
834 
835  // if there is a name and it's not the the same type as the current design area
836  if (empty($element['attributes']['id_name']) || empty($element['attributes']['design_area'])) {
837  trigger_localised_error('CORE0143', E_USER_WARNING);
838  return FALSE;
839  }//end if
840 
841  // validate id name
842  if (!preg_match('/^[a-z][a-z0-9_]*$/i', $element['attributes']['id_name']) || $element['attributes']['id_name'] != preg_replace('/__+/', '', $element['attributes']['id_name'])) {
843  trigger_localised_error('CORE0181', E_USER_WARNING, $element['attributes']['id_name']);
844  return FALSE;
845  }
846 
847  $element['attributes']['design_area'] = 'design_area_'.strtolower($element['attributes']['design_area']);
848 
849  // if there is a name and it's not the the same type as the current design area
850  if (isset($id_names[$element['attributes']['id_name']])) {
851  trigger_localised_error('CORE0142', E_USER_WARNING, $element['attributes']['id_name']);
852  return FALSE;
853  }//end if
854 
855  $id_names[$element['attributes']['id_name']] = $element['attributes']['design_area'];
856 
857  }//end foreach
858 
859  $GLOBALS['SQ_SYSTEM']->changeDatabaseConnection('db2');
860  $GLOBALS['SQ_SYSTEM']->doTransaction('BEGIN');
861 
862  if (isset($GLOBALS['SQ_PROCESSED_DESIGN_AREAS'])) {
863  // let's remove any design area links that we aren't going to be using any more
864  $existing_da_links = $asset->getDesignAreaLink();
865  $existing_id_names = Array();
866  foreach ($existing_da_links as $link) {
867  $existing_id_names[$link['value']] = $link['linkid'];
868  }
869 
870  $removed_id_names = array_diff(array_keys($existing_id_names), array_keys($GLOBALS['SQ_PROCESSED_DESIGN_AREAS']));
871 
872  // now remove any unused design area customisations
873  foreach ($removed_id_names as $id_name) {
874  if (!$asset->deleteLink($existing_id_names[$id_name])) {
875  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
876  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
877  return FALSE;
878  }
879  }//end foreach
880  } else {
881  $GLOBALS['SQ_PROCESSED_DESIGN_AREAS'] = Array();
882  }
883 
884  // validate the design areas that we are going to use
885 
886  $design_areas = Array();
887 
888  // now let's check to see if any existing design areas exists
889  // and check if they are the same type as the one in the contents
890  foreach ($id_names as $id_name => $design_area) {
891 
892  $da = $asset->getDesignArea($id_name);
893 
894  // if it's a different type, then convert them
895  if (!is_null($da) && $da->type() !== $design_area) {
896  $link = $asset->getDesignAreaLink($id_name, FALSE);
897  if (!$asset->deleteLink($link['linkid'])) {
898  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
899  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
900  return FALSE;
901  }
902  unset($da); // unset so we don't set the value or all ref's to NULL
903  $da = NULL; // do this so a new version will be created
904  }
905 
906  // if it doesn't exist, create it, and acquire the lock
907  if (is_null($da)) {
908  $GLOBALS['SQ_SYSTEM']->am->includeAsset($design_area);
909  $da = new $design_area();
910  $da_link = Array('asset' => &$asset, 'link_type' => SQ_LINK_TYPE_3, 'value' => $id_name, 'is_dependant' => '1');
911  $da->setAttrValue('id_name', $id_name);
912  if (!$da->create($da_link)) {
913  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
914  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
915  return FALSE;
916  }
917  if (!$GLOBALS['SQ_SYSTEM']->am->acquireLock($da->id, 'parsing')) {
918  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
919  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
920  return FALSE;
921  }
922  }
923 
924  $design_areas[$id_name] = $da;
925 
926  }//end foreach
927 
928 
929  // Now that we have set all the design areas up we can get on with the processing of the contents array
930  foreach ($contents as $index => $element) {
931  if ($element['_type'] != 'TAG' || $element['operation'] != 'area') {
932  continue;
933  }
934 
935  $edit_fns = $design_areas[$element['attributes']['id_name']]->getEditFns();
936  if (!$edit_fns->_processContents($design_areas[$element['attributes']['id_name']], $element['contents'])) {
937  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
938  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
939  return FALSE;
940  }
941 
942  $print = !in_array(array_get_index($element['attributes'], 'print', 'yes'), Array('no', 'false', '0'));
943  $design_areas[$element['attributes']['id_name']]->setAttrValue('print', $print);
944  $cache = in_array(array_get_index($element['attributes'], 'cache', FALSE), Array('yes', 'true', '1'));
945  $design_areas[$element['attributes']['id_name']]->setAttrValue('cache', $cache);
946 
947  if (!$design_areas[$element['attributes']['id_name']]->saveAttributes()) {
948  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
949  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
950  return FALSE;
951  }
952  // we are done with this design area, release the lock
953  // otherwise we will get lock by user 0 after a full system cleanup
954  // for login form design area and password change form design area
955  // this only occurs in CLI mode
956  if (SQ_PHP_CLI) {
957  $lockInfo = $GLOBALS['SQ_SYSTEM']->am->getLockInfo($design_areas[$element['attributes']['id_name']]->id, 'parsing');
958  if (!empty($lockInfo['links']) && $lockInfo['links']['userid'] == '0') {
959  @$GLOBALS['SQ_SYSTEM']->am->releaseLock($design_areas[$element['attributes']['id_name']]->id, 'parsing');
960  }
961  }
962 
963  }//end foreach
964 
965  // now just set the contents and we are away...
966  if ($asset->setAttrValue('contents', $contents)) {
967  $GLOBALS['SQ_SYSTEM']->doTransaction('COMMIT');
968  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
969  return TRUE;
970  } else {
971  $GLOBALS['SQ_SYSTEM']->doTransaction('ROLLBACK');
972  $GLOBALS['SQ_SYSTEM']->restoreDatabaseConnection();
973  return FALSE;
974  }
975 
976  }//end _processContents()
977 
978 
989  public function paintImport(Design $asset, Backend_Outputter $o, $prefix)
990  {
991  $write_access = $asset->writeAccess('parsing');
992  $o->openField(translate('core_design_import_file'));
993  if ($write_access) {
994  file_upload($prefix.'_import_file');
995  }
996  $o->note(translate('core_design_import_note'));
997  $o->closeField();
998  $o->openField(translate('core_design_existing_asset'));
999  if ($write_access) {
1000  asset_finder($prefix.'_import_asset', 0, Array('file' => 'I'));
1001  }
1002  $o->note(translate('core_design_existing_asset_note'));
1003  $o->closeField();
1004 
1005  return TRUE;
1006 
1007  }//end paintImport()
1008 
1009 
1020  public function processImport(Design $asset, Backend_Outputter $o, $prefix)
1021  {
1022  $tar_upload = get_file_upload_info($prefix.'_import_file');
1023  if ($tar_upload === FALSE) {
1024  trigger_error(translate('core_design_import_upload_error'), E_USER_WARNING);
1025  } else {
1026  if (!empty($tar_upload)) {
1027  $import_dir = $asset->data_path.'/temp/';
1028  if (!is_dir($import_dir)) {
1029  create_directory($import_dir);
1030  }
1031  commit_file_upload($prefix.'_import_file', $import_dir, TRUE, 0, TRUE, Array('gz', 'tar', 'tgz'));
1032 
1033  $filename = $tar_upload['name'];
1034  $import_link = Array('asset' => &$asset, 'link_type' => SQ_LINK_TYPE_2, 'value' => 'export_file');
1035  $temp_info = Array('name' => $filename, 'tmp_name' => $import_dir.'/'.$filename, 'non_uploaded_file' => TRUE);
1036 
1037  $GLOBALS['SQ_SYSTEM']->am->includeAsset('file');
1038  $new_file = new File();
1039  $new_file->_tmp['uploading_file'] = TRUE;
1040  $new_file->setAttrValue('name', $filename);
1041 
1042  if (!$new_file->create($import_link, $temp_info)) {
1043  trigger_error('Failed to import File '.$filename, E_USER_WARNING);
1044  }
1045  delete_directory($import_dir);
1046  }
1047  }
1048 
1049  $selected_asset = $_POST[$prefix.'_import_asset']['assetid'];
1050  if ($selected_asset != '0') {
1051  $file = $GLOBALS['SQ_SYSTEM']->am->getAsset($selected_asset);
1052  $asset->createLink($file, SQ_LINK_TYPE_1, 'export_file');
1053  }
1054 
1055  return TRUE;
1056 
1057  }//end processImport()
1058 
1059 
1070  public function paintExport(Design $asset, Backend_Outputter $o, $prefix)
1071  {
1072  $o->sectionNote(translate('core_design_export_warning'));
1073  $write_access = $asset->writeAccess('parsing');
1074  $o->openField(translate('core_design_export_filename'));
1075  if ($write_access) {
1076  text_box($prefix.'_export_filename', '');
1077  }
1078  $o->note(translate('core_design_export_note'));
1079  $o->closeField();
1080 
1081  return TRUE;
1082 
1083  }//end paintExport()
1084 
1085 
1096  public function processExport(Design $asset, Backend_Outputter $o, $prefix)
1097  {
1098  $write_access = $asset->writeAccess('parsing');
1099 
1100  if ($write_access) {
1101  if ($_POST[$prefix.'_export_filename'] != '') {
1102  $new_file_name = $_POST[$prefix.'_export_filename'];
1103  if (strpos($new_file_name, '.tar.gz') === FALSE) {
1104  $new_file_name .= '.tar.gz';
1105  }
1106 
1107  $files_dir = $asset->data_path.'/.temp_files';
1108  if (!create_directory($files_dir)) return FALSE;
1109  if (!clear_directory($files_dir)) return FALSE;
1110 
1111  // Get the current links
1112  $links = $GLOBALS['SQ_SYSTEM']->am->getLinks($asset->id, SQ_LINK_TYPE_2 | SQ_LINK_TYPE_3, 'file', FALSE);
1113 
1114  $files_to_copy = Array();
1115  foreach ($links as $link_data) {
1116  if ($link_data['value'] == 'export_file') continue;
1117  $child_asset = $GLOBALS['SQ_SYSTEM']->am->getAsset($link_data['minorid']);
1118  $current_file_info = $child_asset->getExistingFile();
1119  $files_to_copy[$current_file_info['filename']] = $current_file_info['path'];
1120  }
1121  $archive_files = Array();
1122  foreach ($files_to_copy as $filename => $path) {
1123  copy($path, $files_dir.'/'.$filename);
1124  $archive_files[] = $files_dir.'/'.$filename;
1125  }
1126 
1127  require_once 'Archive/Tar.php';
1128 
1129  $tar_object = new Archive_Tar($files_dir.'/associated_files.tar.gz', TRUE);
1130  $tar_object->createModify($archive_files, '', $files_dir);
1131 
1132  foreach ($archive_files as $remove) {
1133  unlink($remove);
1134  }
1135 
1136  $archive_files = Array();
1137 
1138  // Should have only the associated files tar in the directory, now we just need to add the parse file
1139  if (!file_exists($asset->data_path.'/parse.txt')) {
1140  trigger_error('No Parse File to Export', E_USER_WARNING);
1141  return FALSE;
1142  }
1143 
1144  copy($asset->data_path.'/parse.txt', $files_dir.'/parse.html');
1145 
1146  $archive_files[] = $files_dir.'/parse.html';
1147  $archive_files[] = $files_dir.'/associated_files.tar.gz';
1148 
1149  $tar_object = new Archive_Tar($files_dir.'/'.$new_file_name, TRUE);
1150  $tar_object->createModify($archive_files, '', $files_dir);
1151 
1152  $temp_path = $files_dir.'/'.$new_file_name;
1153  $temp_info = Array('name' => $new_file_name, 'tmp_name' => $temp_path);
1154  $temp_info['non_uploaded_file'] = TRUE;
1155 
1156  $GLOBALS['SQ_SYSTEM']->am->includeAsset('file');
1157 
1158  $new_file = new File();
1159  $new_file->_tmp['uploading_file'] = TRUE;
1160  $new_file->setAttrValue('name', $new_file_name);
1161  $design_link = Array('asset' => &$asset, 'link_type' => SQ_LINK_TYPE_2, 'value' => 'export_file', 'sort_order' => 1, 'is_dependant' => 1);
1162 
1163  $new_file->create($design_link, $temp_info);
1164 
1165  delete_directory($files_dir);
1166  }//end if not empty filename
1167  }//end if write_access
1168 
1169  return $write_access;
1170 
1171  }//end processExport()
1172 
1173 
1184  public function paintCurrentFiles(Design $asset, Backend_Outputter $o, $prefix)
1185  {
1186  $o->sectionNote(translate('core_design_apply_warning'));
1187  $write_access = $asset->writeAccess('parsing');
1188  ?>
1189  <table class="sq-backend-table" style="width: 350px;">
1190  <tr>
1191  <td class="sq-backend-table-header" style="width: 200px;"><?php echo translate('core_design_export_file_name'); ?></td>
1192  <?php
1193  if ($write_access) {
1194  ?>
1195  <td class="sq-backend-table-header" style="width: 75px;"><?php echo translate('download'); ?></td>
1196  <td class="sq-backend-table-header" style="width: 75px;"><?php echo translate('apply'); ?></td>
1197  <?php
1198  }
1199  ?>
1200  </tr>
1201  <?php
1202  $file_links = $GLOBALS['SQ_SYSTEM']->am->getLinks($asset->id, SQ_LINK_TYPE_2, 'file', TRUE, 'major', 'export_file');
1203  $file_ids = Array();
1204  foreach ($file_links as $data) {
1205  $file_ids[] = $data['minorid'];
1206  }
1207  $file_info = $GLOBALS['SQ_SYSTEM']->am->getAssetInfo($file_ids);
1208  foreach ($file_info as $id => $data) {
1209  $file_name = $data['name'];
1210  ?>
1211  <tr>
1212  <td><?php echo $file_name; ?></td>
1213  <?php
1214  if ($write_access) {
1215  ?>
1216  <td><a href="./?a=<?php echo $id; ?>"><?php echo translate('download'); ?></a></td>
1217  <td>
1218  <?php radio_button($prefix.'_apply', $id);?>
1219  </td>
1220  <?php
1221  }
1222  ?>
1223  </tr>
1224  <?php
1225  }
1226  ?>
1227  <?php
1228  if ($write_access) {
1229  ?>
1230  <tr><td colspan="2"><?php echo translate('core_design_export_no_change'); ?></td><td><?php radio_button($prefix.'_apply', '', TRUE);?></td></tr>
1231  <?php
1232  }
1233  ?>
1234  </table>
1235  <?php
1236  return TRUE;
1237 
1238  }//end paintCurrentFiles()
1239 
1240 
1251  public function processCurrentFiles(Design $asset, Backend_Outputter $o, $prefix)
1252  {
1253  $write_access = $asset->writeAccess('parsing');
1254  if (!$write_access) return FALSE;
1255 
1256  $file_to_apply = $_POST[$prefix.'_apply'];
1257  if ($file_to_apply == '') return TRUE;
1258  $file = $GLOBALS['SQ_SYSTEM']->am->getAsset($file_to_apply);
1259  $file_info = $file->getExistingFile();
1260 
1261  require_once 'Archive/Tar.php';
1262  $tar_ball = new Archive_Tar($file_info['path']);
1263 
1264  if (($contents = $tar_ball->listContent()) != 0) {
1265  // Tar ball is fine.
1266  $extract_list = Array();
1267  foreach ($contents as $data) {
1268  $extract_list[] = $data['filename'];
1269  }
1270 
1271  $valid_parse_names = Array(
1272  'parse.txt',
1273  'parse.html',
1274  'parse.htm',
1275  'index.htm',
1276  'index.html',
1277  );
1278 
1279  $parse_file_found = FALSE;
1280  $parse_file = '';
1281  foreach ($valid_parse_names as $name) {
1282  if (in_array($name, $extract_list)) {
1283  $parse_file = $name;
1284  $parse_file_found = TRUE;
1285  break;
1286  }
1287  }
1288 
1289  if (!$parse_file_found) {
1290  trigger_error(translate('core_design_export_no_parsefile'), E_USER_WARNING);
1291  return FALSE;
1292  }
1293 
1294  $files_dir = $asset->data_path.'/.temp_files';
1295  if (!create_directory($files_dir)) return FALSE;
1296  if (!clear_directory($files_dir)) return FALSE;
1297 
1298  $result = $tar_ball->extractList($extract_list, $files_dir);
1299 
1300  // Add and link up the parse file
1301  $current_parse_file = $asset->data_path.'/parse.txt';
1302  $changes = FALSE;
1303  $new_version = FALSE;
1304 
1305  $fv = $GLOBALS['SQ_SYSTEM']->getFileVersioning();
1306 
1307  // delete existing parse file if it exists
1308  if (is_file($current_parse_file)) {
1309  $new_version = TRUE;
1310  if (!unlink($current_parse_file)) {
1311  trigger_localised_error('CORE0164', E_USER_WARNING);
1312  return FALSE;
1313  }
1314  }
1315 
1316  if (copy($files_dir.'/'.$parse_file, $current_parse_file)) {
1317 
1318  $asset->_tmp['update_customisations'] = TRUE;
1319  $asset->_tmp['generate_design'] = TRUE;
1320  $changes = $this->parseAndProcessFile($asset);
1321 
1322  // if we are overwriting our current parse file, we need to add a new version to the repository
1323  if ($new_version) {
1324  $file_status = $fv->upToDate($parse_file);
1325  if (FUDGE_FV_MODIFIED & $file_status) {
1326  if (!$fv->commit($current_parse_file, '')) {
1327  trigger_localised_error('CORE0160', E_USER_WARNING);
1328  }
1329  }
1330  } else {
1331  // attempt to add the parse file to the repository
1332  if (!$fv->add($asset->data_path_suffix, $current_parse_file, '')) {
1333  trigger_localised_error('CORE1057', E_USER_WARNING);
1334  }
1335  }
1336 
1337  // Remove Current Links
1338  $links = $GLOBALS['SQ_SYSTEM']->am->getLinks($asset->id, SQ_LINK_TYPE_2, '');
1339  $trash_folder = $GLOBALS['SQ_SYSTEM']->am->getSystemAsset('trash_folder');
1340  foreach ($links as $data) {
1341  if ($data['value'] != 'export_file') {
1342  // Move it to trash
1343  $trashed = $GLOBALS['SQ_SYSTEM']->am->getAsset($data['minorid']);
1344  $trashed->saveWebPaths(Array());
1345  $GLOBALS['SQ_SYSTEM']->am->trashAsset($trashed->id);
1346  }
1347  }
1348 
1349  $assoc_tar = '';
1350  if (in_array('associated_files.tar.gz', $extract_list)) {
1351  $assoc_tar = 'associated_files.tar.gz';
1352  }
1353  if (in_array('associated-files.tar.gz', $extract_list)) {
1354  $assoc_tar = 'associated-files.tar.gz';
1355  }
1356  if ($assoc_tar != '') {
1357  // Got associated files, now get them linked up
1358  create_directory($files_dir.'/extracted/');
1359  require_once 'Archive/Tar.php';
1360  $nested_tar_ball = new Archive_Tar($files_dir.'/associated_files.tar.gz');
1361 
1362  $nested_tar_ball->extract($files_dir.'/extracted/');
1363  $assoc_files = list_files($files_dir.'/extracted/', TRUE);
1364 
1365  foreach ($assoc_files as $full_path) {
1366  $info = Array('name' => basename($full_path), 'tmp_name' => $full_path);
1367  $info['non_uploaded_file'] = TRUE;
1368  if (!$this->_processUploadedFile($asset, $info)) {
1369  trigger_error(translate('core_design_export_associated_file_problem', basename($full_path)), E_USER_WARNING);
1370  }
1371  }
1372  }
1373 
1374  delete_directory($files_dir);
1375  }//end if copy successful
1376  } else {
1377  trigger_error(translate('core_design_export_opening_problem', $file_info['name']), E_USER_WARNING);
1378  }
1379  return $write_access;
1380 
1381  }//end processCurrentFiles()
1382 
1383 
1394  public function paintUsage(Design $asset, Backend_Outputter $o, $prefix)
1395  {
1396  $page_size = 20;
1397 
1398  $o->openRaw();
1399 
1400  $tree_tops = $GLOBALS['SQ_SYSTEM']->am->getAssetidsByLookupValue('design::%', $asset->id, TRUE);
1401 
1402  if (count($tree_tops) > 0) {
1403  $tree_tops = $this->_getTreeTops($tree_tops);
1404 
1405  $num_pages = ceil(count($tree_tops) / $page_size);
1406  $page_num = array_get_index($_POST, $prefix.'_usage_page', 1);
1407  $page_num = max($page_num, 1);
1408  $page_num = min($page_num, $num_pages);
1409 
1410  if ($num_pages == 1) {
1411  $page_tag = translate('page_number', $page_num, $num_pages);
1412  } else {
1413  $page_tag = translate('page_number_with_pager', $page_num, $num_pages, $prefix.'_usage_page');
1414  }
1415  $asset_count_tag = translate('item_range', ($page_num - 1) * $page_size + 1, min(count($tree_tops), $page_num * $page_size), count($tree_tops), strtolower(translate('assets')));
1416 
1417  $tree_tops = array_slice($tree_tops, ($page_num - 1) * $page_size, $page_size);
1418 
1419  $links = Array(
1420  'first' => '&lt;&lt;',
1421  'previous' => '&lt;',
1422  'page' => $page_tag,
1423  'next' => '&gt;',
1424  'last' => '&gt;&gt;',
1425  );
1426 
1427  if ($page_num > 1) {
1428  $links['first'] = '<a title="'.translate('pagination_go_to_first').'" style="text-decoration: none; color: #fff" href="#" onClick="return sq_pager_jump(\''.$prefix.'_usage_page\', 1)">'.$links['first'].'</a>';
1429  $links['previous'] = '<a title="'.translate('pagination_go_to_previous').'" style="text-decoration: none; color: #fff" href="#" onClick="return sq_pager_jump(\''.$prefix.'_usage_page\', '.($page_num - 1).')">'.$links['previous'].'</a>';
1430  } else {
1431  $links['first'] = '<span title="'.translate('pagination_cannot_go_further_back').'." style="color: #333">'.$links['first'].'</span>';
1432  $links['previous'] = '<span title="'.translate('pagination_cannot_go_further_back').'." style="color: #333">'.$links['previous'].'</span>';
1433  }
1434 
1435  if ($page_num < $num_pages) {
1436  $links['last'] = '<a title="'.translate('pagination_go_to_last').'" style="text-decoration: none; color: #fff" href="#" onClick="return sq_pager_jump(\''.$prefix.'_usage_page\', '.$num_pages.')">'.$links['last'].'</a>';
1437  $links['next'] = '<a title="'.translate('pagination_go_to_next').'" style="text-decoration: none; color: #fff" href="#" onClick="return sq_pager_jump(\''.$prefix.'_usage_page\', '.($page_num + 1).')">'.$links['next'].'</a>';
1438  } else {
1439  $links['last'] = '<span title="'.translate('pagination_cannot_go_further_forward').'." style="color: #333">'.$links['last'].'</span>';
1440  $links['next'] = '<span title="'.translate('pagination_cannot_go_further_forward').'." style="color: #333">'.$links['next'].'</span>';
1441  }
1442 
1443  hidden_field($prefix.'_usage_page', $page_num); ?>
1444  <table class="sq-backend-table">
1445  <thead>
1446  <tr class="sq-backend-table-row">
1447  <td class="sq-backend-table-header-header"><?php echo implode(' &nbsp; &nbsp; ', $links) ?></td>
1448  <td class="sq-backend-table-header-header" style="text-align: right; font-weight: normal"><?php echo $asset_count_tag; ?></span></td>
1449  </tr>
1450  <tr class="sq-backend-table-row">
1451  <th class="sq-backend-table-cell" colspan="2"><?php echo translate('asset'); ?></th>
1452  </tr>
1453  </thead>
1454  <tbody>
1455  <?php
1456 
1457  foreach ($tree_tops as &$tree_info) {
1458  ?><tr class="sq-backend-table-row">
1459  <td class="sq-backend-table-cell" colspan="2">
1460  <?php
1461 
1462  $tag_line = get_asset_tag_line($tree_info['assetid'], 'details');
1463 
1464  $child_count_mult = $tree_info['child_count'];
1465  if ($child_count_mult > 1) $child_count_mult = 'm';
1466  echo translate('asset_and_child_count_'.$child_count_mult, $tag_line, $tree_info['child_count']);
1467  ?>
1468  </tr>
1469  <?php
1470  }//end foreach top tree
1471  ?>
1472 
1473  </tbody>
1474  </table>
1475  <?php
1476 
1477  $o->note(translate('design_usage_explanation'));
1478 
1479  } else {
1480  $o->note(translate('core_design_usage_no_assets'));
1481  }
1482 
1483  $o->closeRaw();
1484 
1485  }//end paintUsage()
1486 
1487 
1504  public function _getTreeTops(Array $treeids)
1505  {
1506  $all_treeids = Array();
1507  foreach ($treeids as $assetid => $asset_treeids) {
1508  foreach ($asset_treeids[0] as $asset_treeid) {
1509  if (($asset_treeid === 'override') || ($asset_treeid === 'not_override')) {
1510  continue;
1511  }
1512  $all_treeids[$asset_treeid] = $assetid;
1513  }
1514  }
1515  uksort($all_treeids, Array($this, '_strlenCmp'));
1516  $res = Array();
1517  foreach ($all_treeids as $treeid => $assetid) {
1518  $treeid_copy = $treeid;
1519  while (!empty($treeid_copy)) {
1520  if (isset($res[$treeid_copy])) {
1521  $res[$treeid_copy]['child_count']++;
1522  continue(2);
1523  }
1524  $treeid_copy = substr($treeid_copy, 0, -SQ_CONF_ASSET_TREE_SIZE);
1525  }
1526  $res[$treeid]['assetid'] = $assetid;
1527  $res[$treeid]['child_count'] = 0;
1528  }
1529  ksort($res); // put in treeid order
1530  return $res;
1531 
1532  }//end _getTreeTops()
1533 
1534 
1544  public function _strlenCmp($a, $b)
1545  {
1546  return strlen($a) > strlen($b);
1547 
1548  }//end _strlenCmp()
1549 
1550 
1562  public function _paintSelection(Design $asset, Backend_Outputter $o, $prefix, $attribute)
1563  {
1564  $write_access = $asset->writeAccess('attributes');
1565  $select_options = $asset->attr($attribute);
1566 
1567  if (!empty($select_options)) {
1568  ?>
1569  <table class="sq-backend-table">
1570  <tr>
1571  <td class="sq-backend-table-header"><?php echo translate('core_design_class_name'); ?></td>
1572  <td class="sq-backend-table-header"><?php echo translate('core_design_class_short_name'); ?></td>
1573  <?php
1574  if ($write_access) {
1575  ?><td class="sq-backend-table-header"><?php echo translate('delete_question'); ?></td><?php
1576  }
1577  ?>
1578  </tr>
1579  <?php
1580  $i = 0;
1581  foreach ($select_options as $option_key => $option_value) {
1582  ?>
1583  <tr>
1584  <td class="sq-backend-table-cell">
1585  <?php
1586  if ($write_access) {
1587  text_box($prefix.'_options[key]['.$i.']', $option_key, 20);
1588  } else {
1589  echo $option_key;
1590  }
1591  ?>
1592  </td>
1593  <td class="sq-backend-table-cell" align="left">
1594  <?php
1595  if ($write_access) {
1596  text_box($prefix.'_options[val]['.$i.']', $option_value, 20);
1597  } else {
1598  echo $option_value;
1599  }
1600  ?>
1601  </td>
1602  <?php
1603  if ($write_access) {
1604  ?>
1605  <td class="sq-backend-table-cell">
1606  <?php check_box($prefix.'_options[del]['.$i.']', $option_key); ?>
1607  </td>
1608  <?php
1609  }
1610  ?>
1611  </tr>
1612  <?php
1613  $i++;
1614  }//end foreach select_options
1615  ?>
1616  </table>
1617  <?php
1618 
1619  } else {
1620  echo translate('no_select_box_options');
1621  }//end if empty
1622 
1623  // now adding two fields for new entry (key => value)
1624  if ($write_access) {
1625  $o->openField(translate('new_option'));
1626  echo '<b>'.translate('key').'</b> ';
1627  text_box($prefix.'_new_key','');
1628  echo ' <b>'.translate('value').'</b> ';
1629  text_box($prefix.'_new_val','');
1630  $o->closeField();
1631  }
1632 
1633  return TRUE;
1634 
1635  }//end _paintSelection()
1636 
1637 
1649  public function _processSelection(Design $asset, Backend_Outputter $o, $prefix, $attribute)
1650  {
1651  // need to have write access to make any changes
1652  if (!$asset->writeAccess('attributes')) return FALSE;
1653 
1654  $select_options = Array();
1655  if (isset($_POST[$prefix.'_options'])) {
1656  $option_changes = $_POST[$prefix.'_options'];
1657  foreach ($option_changes['key'] as $i => $key) {
1658  if (isset($option_changes['del'][$i])) continue;
1659  $select_options[trim($key)] = trim($option_changes['val'][$i]);
1660  }
1661  }
1662 
1663  // now get the new submitted values (if any) and add them to array
1664  if (strlen(trim($_POST[$prefix.'_new_key']))>0 && strlen(trim($_POST[$prefix.'_new_val']))>0) {
1665  $new_select_key = trim($_POST[$prefix.'_new_key']);
1666  $new_select_val = trim($_POST[$prefix.'_new_val']);
1667  $select_options[$new_select_key] = $new_select_val;
1668  }
1669 
1670  // updating asset attribute value
1671  $asset->setAttrValue($attribute, $select_options);
1672 
1673  return TRUE;
1674 
1675  }//end _processSelection()
1676 
1677 
1686  public function paintWysiwygClasses(Design $asset, Backend_Outputter $o, $prefix)
1687  {
1688  $this->_paintSelection($asset, $o, $prefix.'_wysiwyg', 'wysiwyg_classes');
1689  $o->openField('');
1690  $o->note(translate('core_design_class_wysiwyg_note'));
1691  $o->closeField();
1692 
1693  return TRUE;
1694 
1695  }//end paintWysiwygClasses()
1696 
1697 
1706  public function processWysiwygClasses(Design $asset, Backend_Outputter $o, $prefix)
1707  {
1708  $this->_processSelection($asset, $o, $prefix.'_wysiwyg', 'wysiwyg_classes');
1709 
1710  return TRUE;
1711 
1712  }//end processWysiwygClasses()
1713 
1714 
1723  public function paintDivClasses(Design $asset, Backend_Outputter $o, $prefix)
1724  {
1725  $this->_paintSelection($asset, $o, $prefix.'_div', 'div_classes');
1726  $o->openField('');
1727  $o->note(translate('core_design_class_div_note'));
1728  $o->closeField();
1729 
1730  return TRUE;
1731 
1732  }//end paintDivClasses()
1733 
1734 
1743  public function processDivClasses(Design $asset, Backend_Outputter $o, $prefix)
1744  {
1745  $this->_processSelection($asset, $o, $prefix.'_div', 'div_classes');
1746 
1747  return TRUE;
1748 
1749  }//end processDivClasses()
1750 
1751 
1752 }//end class
1753 
1754 ?>