ILIAS  trunk Revision v11.0_alpha-1723-g8e69f309bab
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
class.ilObjStyleSheet.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
22 
29 {
31  protected \ILIAS\Style\Content\InternalRepoService $repo;
32  protected bool $is_3_10_skin = false;
33  protected string $export_sub_dir = "";
34  protected array $chars_by_type = [];
35  protected array $end_styles = [];
36  protected array $chars = [];
37  protected bool $up_to_date = false;
38  public array $style = [];
39  protected array $hidden_chars = [];
40  protected array $style_class = [];
41 
42  protected int $scope = 0;
43 
44  public static array $num_unit = array("px", "em", "rem", "ex", "%", "pt", "pc", "in", "mm", "cm");
45  public static array $num_unit_no_perc = array("px", "em", "rem", "ex", "pt", "pc", "in", "mm", "cm");
46 
47  // css parameters and their attribute values, input type and group
48  public static array $parameter = array(
49  "font-size" => array(
50  "values" => array("xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "smaller", "larger"),
51  "input" => "fontsize",
52  "group" => "text"),
53  "font-family" => array(
54  "values" => array(),
55  "input" => "text",
56  "group" => "text"),
57  "font-style" => array(
58  "values" => array("italic", "oblique", "normal"),
59  "input" => "select",
60  "group" => "text"),
61  "font-weight" => array(
62  "values" => array("bold", "normal", "bolder", "lighter"),
63  "input" => "select",
64  "group" => "text"),
65  "font-variant" => array(
66  "values" => array("small-caps", "normal"),
67  "input" => "select",
68  "group" => "text"),
69  "word-spacing" => array(
70  "values" => array(),
71  "input" => "numeric_no_perc",
72  "group" => "text"),
73  "letter-spacing" => array(
74  "values" => array(),
75  "input" => "numeric_no_perc",
76  "group" => "text"),
77  "text-decoration" => array(
78  "values" => array("underline", "overline", "line-through", "blink", "none"),
79  "input" => "select",
80  "group" => "text"),
81  "text-transform" => array(
82  "values" => array("capitalize", "uppercase", "lowercase", "none"),
83  "input" => "select",
84  "group" => "text"),
85  "color" => array(
86  "values" => array(),
87  "input" => "color",
88  "group" => "text"),
89  "text-indent" => array(
90  "values" => array(),
91  "input" => "numeric",
92  "group" => "text"),
93  "line-height" => array(
94  "values" => array(),
95  "input" => "numeric",
96  "group" => "text"),
97  "vertical-align" => array(
98  "values" => array("top", "middle", "bottom", "baseline", "sub", "super",
99  "text-top", "text-bottom"),
100  "input" => "select",
101  "group" => "text"),
102  "text-align" => array(
103  "values" => array("left", "center", "right", "justify"),
104  "input" => "select",
105  "group" => "text"),
106  "white-space" => array(
107  "values" => array("normal", "pre", "nowrap"),
108  "input" => "select",
109  "group" => "text"),
110  "margin" => array(
111  "values" => array(),
112  "input" => "trbl_numeric",
113  "subpar" => array("margin", "margin-top", "margin-right",
114  "margin-bottom", "margin-left"),
115  "group" => "margin_and_padding"),
116  "padding" => array(
117  "values" => array(),
118  "input" => "trbl_numeric",
119  "subpar" => array("padding", "padding-top", "padding-right",
120  "padding-bottom", "padding-left"),
121  "group" => "margin_and_padding"),
122  "border-width" => array(
123  "values" => array("thin", "medium", "thick"),
124  "input" => "border_width",
125  "subpar" => array("border-width", "border-top-width", "border-right-width",
126  "border-bottom-width", "border-left-width"),
127  "group" => "border"),
128  "border-color" => array(
129  "values" => array(),
130  "input" => "trbl_color",
131  "subpar" => array("border-color", "border-top-color", "border-right-color",
132  "border-bottom-color", "border-left-color"),
133  "group" => "border"),
134  "border-style" => array(
135  "values" => array("none", "hidden", "dotted", "dashed", "solid", "double",
136  "groove", "ridge", "inset", "outset"),
137  "input" => "border_style",
138  "subpar" => array("border-style", "border-top-style", "border-right-style",
139  "border-bottom-style", "border-left-style"),
140  "group" => "border"),
141 
142  "background-color" => array(
143  "values" => array(),
144  "input" => "color",
145  "group" => "background"),
146  "background-image" => array(
147  "values" => array(),
148  "input" => "background_image",
149  "group" => "background"),
150  "background-repeat" => array(
151  "values" => array("repeat", "repeat-x", "repeat-y", "no-repeat"),
152  "input" => "select",
153  "group" => "background"),
154  "background-attachment" => array(
155  "values" => array("fixed", "scroll"),
156  "input" => "select",
157  "group" => "background"),
158  "background-position" => array(
159  "values" => array("horizontal" => array("left", "center", "right"),
160  "vertical" => array("top", "center", "bottom")),
161  "input" => "background_position",
162  "group" => "background"),
163 
164  "position" => array(
165  "values" => array("absolute", "fixed", "relative", "static"),
166  "input" => "select",
167  "group" => "positioning"),
168  "top" => array(
169  "values" => array(),
170  "input" => "numeric",
171  "group" => "positioning"),
172  "bottom" => array(
173  "values" => array(),
174  "input" => "numeric",
175  "group" => "positioning"),
176  "left" => array(
177  "values" => array(),
178  "input" => "numeric",
179  "group" => "positioning"),
180  "right" => array(
181  "values" => array(),
182  "input" => "numeric",
183  "group" => "positioning"),
184  "width" => array(
185  "values" => array(),
186  "input" => "numeric",
187  "group" => "positioning"),
188  "height" => array(
189  "values" => array(),
190  "input" => "numeric",
191  "group" => "positioning"),
192  "min-height" => array(
193  "values" => array(),
194  "input" => "numeric",
195  "group" => "positioning"),
196  "float" => array(
197  "values" => array("left", "right", "none"),
198  "input" => "select",
199  "group" => "positioning"),
200  "overflow" => array(
201  "values" => array("visible", "hidden", "scroll", "auto"),
202  "input" => "select",
203  "group" => "positioning"),
204  "opacity" => array(
205  "values" => array(),
206  "input" => "percentage",
207  "group" => "special"),
208  "transform" => array(
209  "values" => array("rotate(90deg)", "rotate(180deg)", "rotate(270deg)"),
210  "input" => "select",
211  "group" => "special"),
212  "transform-origin" => array(
213  "values" => array( "horizontal" => array("left", "center", "right"),
214  "vertical" => array("top", "center", "bottom")),
215  "input" => "background_position",
216  "group" => "special"),
217  "cursor" => array(
218  "values" => array("auto", "default", "crosshair", "pointer", "move",
219  "n-resize", "ne-resize", "e-resize", "se-resize", "s-resize", "sw-resize",
220  "w-resize", "nw-resize", "text", "wait", "help"),
221  "input" => "select",
222  "group" => "special"),
223  "clear" => array(
224  "values" => array("both","left","right","none"),
225  "input" => "select",
226  "group" => "special"),
227 
228  "list-style-type.ol" => array(
229  "values" => array("decimal","lower-roman","upper-roman",
230  "lower-alpha", "upper-alpha", "lower-greek", "hebrew",
231  "decimal-leading-zero", "cjk-ideographic", "hiragana",
232  "katakana", "hiragana-iroha", "katakana-iroha", "none"),
233  "input" => "select",
234  "group" => "ol"),
235  "list-style-type.ul" => array(
236  "values" => array("disc","circle","square",
237  "none"),
238  "input" => "select",
239  "group" => "ul"),
240  "list-style-image.ul" => array(
241  "values" => array(),
242  "input" => "background_image",
243  "group" => "ul"),
244  "list-style-position.ol" => array(
245  "values" => array("inside","outside"),
246  "input" => "select",
247  "group" => "ol"),
248  "list-style-position.ul" => array(
249  "values" => array("inside","outside"),
250  "input" => "select",
251  "group" => "ul"
252  ),
253  "border-collapse" => array(
254  "values" => array("collapse","separate"),
255  "input" => "select",
256  "group" => "table"
257  ),
258  "caption-side" => array(
259  "values" => array("top","bottom","left","right"),
260  "input" => "select",
261  "group" => "table"
262  )
263  );
264 
265  // filter groups of properties that should only be
266  // displayed with matching tag (group -> tags)
267  public static array $filtered_groups =
268  array("ol" => array("ol"), "ul" => array("ul"),
269  "table" => array("table"), "positioning" => array("h1", "h2", "h3", "div", "img", "table", "a", "figure", "li", "p"));
270 
271  // style types and their super type
272  public static array $style_super_types = array(
273  "text_block" => array("text_block", "heading1", "heading2", "heading3", "code_block"),
274  "text_inline" => array("text_inline", "sub", "sup", "code_inline", "strong", "em"),
275  "section" => array("section"),
276  "link" => array("link"),
277  "table" => array("table", "table_cell", "table_caption"),
278  "list" => array("list_o", "list_u", "list_item"),
279  "flist" => array("flist_cont", "flist_head", "flist", "flist_li", "flist_a"),
280  "media" => array("media_cont", "media_caption", "iim", "marker"),
281  "tabs" => array("va_cntr", "va_icntr", "va_ihead", "va_iheada", "va_ihcap", "va_icont",
282  "ha_cntr", "ha_icntr", "ha_ihead", "ha_iheada", "ha_ihcap", "ha_icont", "ca_cntr", "ca_icntr", "ca_ihead", "ca_icont"),
283  "question" => array("question", "qtitle", "qanswer", "qinput", "qlinput", "qsubmit", "qfeedr", "qfeedw",
284  "qimg", "qordul", "qordli", "qimgd", "qetitem", "qetcorr", "qover"),
285  "page" => array("page_cont", "page_title", "page_fn")
286  );
287 
288  // these types are expandable, i.e. the user can define new style classes
289  public static array $expandable_types = array(
290  "text_block",
291  "text_inline", "section", "media_cont", "media_caption", "table", "table_cell", "flist_li", "table_caption",
292  "list_o", "list_u", "list_item",
293  "va_cntr", "va_icntr", "va_ihead", "va_iheada", "va_ihcap", "va_icont",
294  "ha_cntr", "ha_icntr", "ha_ihead", "ha_iheada", "ha_ihcap", "ha_icont",
295  "ca_cntr", "ca_icntr", "ca_ihead", "ca_icont"
296  );
297 
298  // these types can be hidden in the content editor
299  public static array $hideable_types = array(
300  "table", "table_cell"
301  );
302 
303  // tag that are used by style types
304  public static array $assigned_tags = array(
305  "text_block" => "p",
306  "heading1" => "h1",
307  "heading2" => "h2",
308  "heading3" => "h3",
309  "code_block" => "pre",
310  "em" => "em",
311  "text_inline" => "span",
312  "code_inline" => "code",
313  "sup" => "sup",
314  "sub" => "sub",
315  "strong" => "strong",
316  "section" => "div",
317  "link" => "a",
318  "table" => "table",
319  "table_cell" => "td",
320  "table_caption" => "caption",
321  "media_cont" => "figure",
322  "media_caption" => "div",
323  "iim" => "div",
324  "marker" => "a",
325  "list_o" => "ol",
326  "list_u" => "ul",
327  "list_item" => "li",
328  "flist_cont" => "div",
329  "flist_head" => "div",
330  "flist" => "ul",
331  "flist_li" => "li",
332  "flist_a" => "a",
333  "question" => "div",
334  "qtitle" => "div",
335  "qanswer" => "div",
336  "qimg" => "img",
337  "qimgd" => "a",
338  "qordul" => "ul",
339  "qordli" => "li",
340  "qetitem" => "a",
341  "qetcorr" => "span",
342  "qinput" => "input",
343  "qlinput" => "textarea",
344  "qsubmit" => "input",
345  "qfeedr" => "div",
346  "qfeedw" => "div",
347  "qover" => "div",
348  "page_cont" => "div",
349  "page_fn" => "div",
350  "page" => "div",
351  "page_title" => "h1",
352  "va_cntr" => "div",
353  "va_icntr" => "div",
354  "va_icont" => "div",
355  "va_ihead" => "div",
356  "va_iheada" => "div",
357  "va_ihcap" => "div",
358  "ha_cntr" => "div",
359  "ha_icntr" => "div",
360  "ha_icont" => "div",
361  "ha_iheada" => "div",
362  "ha_ihcap" => "div",
363  "ha_ihead" => "div",
364  "ca_cntr" => "div",
365  "ca_icntr" => "div",
366  "ca_ihead" => "div",
367  "ca_icont" => "div"
368  );
369 
370  // pseudo classes
371  public static array $pseudo_classes =
372  [
373  "a" => ["hover"],
374  "div" => ["hover", "before"],
375  "img" => ["hover"],
376  "li" => ["before"]
377  ];
378 
379  // core styles these styles MUST exists -> see also basic_style/style.xml
380  public static array $core_styles = array(
381  array("type" => "text_block", "class" => "Standard"),
382  array("type" => "text_block", "class" => "List"),
383  array("type" => "text_block", "class" => "TableContent"),
384  array("type" => "code_block", "class" => "Code"),
385  array("type" => "heading1", "class" => "Headline1"),
386  array("type" => "heading2", "class" => "Headline2"),
387  array("type" => "heading3", "class" => "Headline3"),
388  array("type" => "text_inline", "class" => "Comment"),
389  array("type" => "em", "class" => "Emph"),
390  array("type" => "text_inline", "class" => "Quotation"),
391  array("type" => "strong", "class" => "Strong"),
392  array("type" => "text_inline", "class" => "Accent"),
393  array("type" => "text_inline", "class" => "Important"),
394  array("type" => "code_inline", "class" => "CodeInline"),
395  array("type" => "sup", "class" => "Sup"),
396  array("type" => "sub", "class" => "Sub"),
397  array("type" => "link", "class" => "IntLink"),
398  array("type" => "link", "class" => "ExtLink"),
399  array("type" => "link", "class" => "FootnoteLink"),
400  array("type" => "link", "class" => "FileLink"),
401  array("type" => "link", "class" => "GlossaryLink"),
402  array("type" => "media_cont", "class" => "MediaContainer"),
403  array("type" => "media_cont", "class" => "MediaContainerMax50"),
404  array("type" => "media_cont", "class" => "MediaContainerFull100"),
405  array("type" => "table", "class" => "StandardTable"),
406  array("type" => "media_caption", "class" => "MediaCaption"),
407  array("type" => "iim", "class" => "ContentPopup"),
408  array("type" => "marker", "class" => "Marker"),
409  array("type" => "page_cont", "class" => "PageContainer"),
410  array("type" => "page", "class" => "Page"),
411  array("type" => "page_fn", "class" => "Footnote"),
412  array("type" => "page_title", "class" => "PageTitle"),
413  array("type" => "list_o", "class" => "NumberedList"),
414  array("type" => "list_u", "class" => "BulletedList"),
415  array("type" => "list_item", "class" => "StandardListItem"),
416  array("type" => "question", "class" => "Standard"),
417  array("type" => "question", "class" => "SingleChoice"),
418  array("type" => "question", "class" => "MultipleChoice"),
419  array("type" => "question", "class" => "TextQuestion"),
420  array("type" => "question", "class" => "OrderingQuestion"),
421  array("type" => "question", "class" => "MatchingQuestion"),
422  array("type" => "question", "class" => "ImagemapQuestion"),
423  array("type" => "question", "class" => "ErrorText"),
424  array("type" => "question", "class" => "TextSubset"),
425  array("type" => "question", "class" => "ClozeTest"),
426  array("type" => "qtitle", "class" => "Title"),
427  array("type" => "qanswer", "class" => "Answer"),
428  array("type" => "qimg", "class" => "QuestionImage"),
429  array("type" => "qimgd", "class" => "ImageDetailsLink"),
430  array("type" => "qordul", "class" => "OrderList"),
431  array("type" => "qordli", "class" => "OrderListItem"),
432  array("type" => "qordul", "class" => "OrderListHorizontal"),
433  array("type" => "qordli", "class" => "OrderListItemHorizontal"),
434  array("type" => "qetitem", "class" => "ErrorTextItem"),
435  array("type" => "qetitem", "class" => "ErrorTextSelected"),
436  array("type" => "qetcorr", "class" => "ErrorTextCorrected"),
437  array("type" => "qinput", "class" => "TextInput"),
438  array("type" => "qlinput", "class" => "LongTextInput"),
439  array("type" => "qsubmit", "class" => "Submit"),
440  array("type" => "qfeedr", "class" => "FeedbackRight"),
441  array("type" => "qfeedw", "class" => "FeedbackWrong"),
442  array("type" => "qover", "class" => "Correct"),
443  array("type" => "qover", "class" => "Inorrect"),
444  array("type" => "qover", "class" => "StatusMessage"),
445  array("type" => "qover", "class" => "WrongAnswersMessage"),
446  array("type" => "flist_cont", "class" => "FileListContainer"),
447  array("type" => "flist_head", "class" => "FileListHeading"),
448  array("type" => "flist", "class" => "FileList"),
449  array("type" => "flist_li", "class" => "FileListItem"),
450  array("type" => "flist_a", "class" => "FileListItemLink")
451  );
452 
453  public static array $templates = array(
454  "table" => array(
455  "table" => "table",
456  "caption" => "table_caption",
457  "row_head" => "table_cell",
458  "row_foot" => "table_cell",
459  "col_head" => "table_cell",
460  "col_foot" => "table_cell",
461  "odd_row" => "table_cell",
462  "even_row" => "table_cell",
463  "odd_col" => "table_cell",
464  "even_col" => "table_cell"),
465  "vaccordion" => array(
466  "va_cntr" => "va_cntr",
467  "va_icntr" => "va_icntr",
468  "va_ihead" => "va_ihead",
469  "va_iheada" => "va_iheada",
470  "va_ihcap" => "va_ihcap",
471  "va_icont" => "va_icont"
472  ),
473  "haccordion" => array(
474  "ha_cntr" => "ha_cntr",
475  "ha_icntr" => "ha_icntr",
476  "ha_ihead" => "ha_ihead",
477  "ha_iheada" => "ha_iheada",
478  "ha_ihcap" => "ha_ihcap",
479  "ha_icont" => "ha_icont"
480  ),
481  "carousel" => array(
482  "ca_cntr" => "ca_cntr",
483  "ca_icntr" => "ca_icntr",
484  "ca_ihead" => "ca_ihead",
485  "ca_icont" => "ca_icont"
486  )
487  );
488 
489  // basic style xml file, image directory and dom
490  protected static string $basic_style_file = "../vendor/ilias/Style/basic_style/style.xml";
491  protected static string $basic_style_zip = "../vendor/ilias/Style/basic_style/style.zip";
492  protected static string $basic_style_image_dir = "./components/ILIAS/COPage/basic_style/images";
493  protected static ?DOMDocument $basic_style_dom = null;
494 
495  public function __construct(
496  int $a_id = 0,
497  bool $a_call_by_reference = false
498  ) {
499  global $DIC;
500 
501  $this->db = $DIC->database();
502  $this->lng = $DIC->language();
503  $this->type = "sty";
504  $this->style = array();
505  $this->ilias = $DIC["ilias"];
506  $this->domain = $DIC->contentStyle()->internal()->domain();
507 
508  if ($a_call_by_reference) {
509  $this->ilias->raiseError("Can't instantiate style object via reference id.", $this->ilias->error_obj->FATAL);
510  }
511  parent::__construct($a_id, false);
512  $this->repo = $DIC->contentStyle()->internal()->repo();
513  }
514 
515  public static function getBasicZipPath(): string
516  {
517  return self::$basic_style_zip;
518  }
519 
523  public function setUpToDate(bool $a_up_to_date = true): void
524  {
525  $this->up_to_date = $a_up_to_date;
526  }
527 
528  public function getUpToDate(): bool
529  {
530  return $this->up_to_date;
531  }
532 
533  public function setScope(int $a_scope): void
534  {
535  $this->scope = $a_scope;
536  }
537 
538  public function getScope(): int
539  {
540  return $this->scope;
541  }
542 
543  public static function _writeUpToDate(
544  int $a_id,
545  bool $a_up_to_date
546  ): void {
547  global $DIC;
548 
549  $ilDB = $DIC->database();
550 
551  $q = "UPDATE style_data SET uptodate = " .
552  $ilDB->quote((int) $a_up_to_date, "integer") .
553  " WHERE id = " . $ilDB->quote($a_id, "integer");
554  $ilDB->manipulate($q);
555  }
556 
557  public static function writeOwner($obj_id, $style_id)
558  {
559  global $DIC;
560  $ilDB = $DIC->database();
561 
562  $q = "UPDATE style_data SET owner_obj = " .
563  $ilDB->quote((int) $obj_id, "integer") .
564  " WHERE id = " . $ilDB->quote($style_id, "integer");
565  $ilDB->manipulate($q);
566  }
567 
568  public static function _lookupUpToDate(int $a_id): bool
569  {
570  global $DIC;
571 
572  $ilDB = $DIC->database();
573 
574  $q = "SELECT uptodate FROM style_data " .
575  " WHERE id = " . $ilDB->quote($a_id, "integer");
576  $res = $ilDB->query($q);
577  $sty = $ilDB->fetchAssoc($res);
578 
579  return (bool) $sty["uptodate"];
580  }
581 
585  public static function _writeStandard(
586  int $a_id,
587  bool $a_std
588  ): void {
589  global $DIC;
590 
591  $ilDB = $DIC->database();
592 
593  $q = "UPDATE style_data SET standard = " .
594  $ilDB->quote((int) $a_std, "integer") .
595  " WHERE id = " . $ilDB->quote($a_id, "integer");
596  $ilDB->manipulate($q);
597  }
598 
599  public static function _writeScope(int $a_id, int $a_scope): void
600  {
601  global $DIC;
602 
603  $ilDB = $DIC->database();
604 
605  $q = "UPDATE style_data SET category = " .
606  $ilDB->quote($a_scope, "integer") .
607  " WHERE id = " . $ilDB->quote($a_id, "integer");
608  $ilDB->manipulate($q);
609  }
610 
614  public static function _lookupStandard(int $a_id): bool
615  {
616  global $DIC;
617 
618  $ilDB = $DIC->database();
619 
620  $q = "SELECT * FROM style_data " .
621  " WHERE id = " . $ilDB->quote($a_id, "integer");
622  $res = $ilDB->query($q);
623  $sty = $ilDB->fetchAssoc($res);
624 
625  return (bool) ($sty["standard"] ?? false);
626  }
627 
628  public static function _writeActive(int $a_id, bool $a_active): void
629  {
630  global $DIC;
631 
632  $ilDB = $DIC->database();
633 
634  $q = "UPDATE style_data SET active = " .
635  $ilDB->quote((int) $a_active, "integer") .
636  " WHERE id = " . $ilDB->quote($a_id, "integer");
637  $ilDB->manipulate($q);
638  }
639 
643  public static function _lookupActive(int $a_id): bool
644  {
645  global $DIC;
646 
647  $ilDB = $DIC->database();
648 
649  $q = "SELECT * FROM style_data " .
650  " WHERE id = " . $ilDB->quote($a_id, "integer");
651  $res = $ilDB->query($q);
652  $sty = $ilDB->fetchAssoc($res);
653 
654  return (bool) $sty["active"];
655  }
656 
661  public static function _getStandardStyles(
662  bool $a_exclude_default_style = false,
663  bool $a_include_deactivated = false,
664  int $a_scope = 0
665  ): array {
666  global $DIC;
667 
668  $ilDB = $DIC->database();
669  $ilSetting = $DIC->settings();
670  $tree = $DIC->repositoryTree();
671 
672  $default_style = $ilSetting->get("default_content_style_id");
673 
674  $and_str = "";
675  if (!$a_include_deactivated) {
676  $and_str = " AND active = 1";
677  }
678 
679  $q = "SELECT * FROM style_data " .
680  " WHERE standard = 1" . $and_str;
681  $res = $ilDB->query($q);
682  $styles = array();
683  while ($sty = $ilDB->fetchAssoc($res)) {
684  if (!$a_exclude_default_style || $default_style != $sty["id"]) {
685  // check scope
686  if ($a_scope > 0 && $sty["category"] > 0) {
687  if ($tree->isInTree((int) $sty["category"]) &&
688  $tree->isInTree($a_scope)) {
689  $path = $tree->getPathId($a_scope);
690  if (!in_array((int) $sty["category"], $path)) {
691  continue;
692  }
693  }
694  }
695  $styles[(int) $sty["id"]] = ilObject::_lookupTitle((int) $sty["id"]);
696  }
697  }
698 
699  return $styles;
700  }
701 
702 
708  public static function _getClonableContentStyles(): array
709  {
710  global $DIC;
711 
712  $ilAccess = $DIC->access();
713  $ilDB = $DIC->database();
714 
715  $clonable_styles = array();
716 
717  $q = "SELECT * FROM style_data";
718  $style_set = $ilDB->query($q);
719  while ($style_rec = $ilDB->fetchAssoc($style_set)) {
720  $clonable = false;
721  if ($style_rec["standard"] == 1) {
722  if ($style_rec["active"] == 1) {
723  $clonable = true;
724  }
725  } else {
726  $obj_ids = ilObjContentObject::_lookupContObjIdByStyleId((int) $style_rec["id"]);
727  if (count($obj_ids) == 0) {
728  $obj_ids = self::lookupObjectForStyle((int) $style_rec["id"]);
729  }
730  foreach ($obj_ids as $id) {
731  $ref = ilObject::_getAllReferences((int) $id);
732  foreach ($ref as $ref_id) {
733  if ($ilAccess->checkAccess("write", "", $ref_id)) {
734  $clonable = true;
735  }
736  }
737  }
738  }
739  if ($clonable) {
740  $clonable_styles[(int) $style_rec["id"]] =
741  ilObject::_lookupTitle((int) $style_rec["id"]);
742  }
743  }
744 
745  asort($clonable_styles);
746 
747  return $clonable_styles;
748  }
749 
750  public static function _getBasicStyleDom(): DOMDocument
751  {
752  if (!is_object(self::$basic_style_dom)) {
753  self::$basic_style_dom = new DOMDocument();
754  self::$basic_style_dom->load(self::$basic_style_file);
755  }
756 
757  return self::$basic_style_dom;
758  }
759 
760  public static function getBasicImageDir(): string
761  {
762  return self::$basic_style_image_dir;
763  }
764 
765 
769  public function create(
770  int $a_from_style = 0,
771  bool $a_import_mode = false
772  ): int {
773  global $DIC;
774 
775  $ilDB = $this->db;
776 
777  $id = parent::create();
778 
779  $service = $DIC->contentStyle()
780  ->internal();
781  $access_manager = $service->domain()->access(
782  0,
783  $DIC->user()->getId()
784  );
785  $access_manager->enableWrite(true);
786  $color_manager = $service->domain()->color($this->getId(), $access_manager);
787 
788  if ($a_from_style == 0) {
789  if (!$a_import_mode) {
790  throw new Exception("Can't create style without a from style in non-import mode.");
791  } else {
792  // add style_data record
793  $q = "INSERT INTO style_data (id, uptodate, category) VALUES " .
794  "(" . $ilDB->quote($this->getId(), "integer") . ", 0," .
795  $ilDB->quote($this->getScope(), "integer") . ")";
796  $ilDB->manipulate($q);
797  }
798  } else {
799  // get style parameter records
800  $def = array();
801  $q = "SELECT * FROM style_parameter WHERE style_id = " .
802  $ilDB->quote($a_from_style, "integer");
803  $par_set = $ilDB->query($q);
804  while ($par_rec = $ilDB->fetchAssoc($par_set)) {
805  $def[] = array("tag" => $par_rec["tag"], "class" => $par_rec["class"],
806  "parameter" => $par_rec["parameter"], "value" => $par_rec["value"],
807  "type" => $par_rec["type"], "mq_id" => $par_rec["mq_id"], "custom" => $par_rec["custom"]);
808  }
809 
810  $char_repo = $this->repo->characteristic();
811  $char_repo->cloneAllFromStyle($a_from_style, $this->getId());
812 
813 
814  // copy media queries
815  $from_style = new ilObjStyleSheet($a_from_style);
816  $mqs = $from_style->getMediaQueries();
817  $mq_mapping = array();
818  foreach ($mqs as $mq) {
819  $nid = $this->addMediaQuery($mq["mquery"]);
820  $mq_mapping[$mq["id"]] = $nid;
821  }
822 
823  // default style settings
824  foreach ($def as $sty) {
825  $id = $ilDB->nextId("style_parameter");
826  $q = "INSERT INTO style_parameter (id, style_id, tag, class, parameter, value, type, mq_id, custom) VALUES " .
827  "(" .
828  $ilDB->quote($id, "integer") . "," .
829  $ilDB->quote($this->getId(), "integer") . "," .
830  $ilDB->quote($sty["tag"], "text") . "," .
831  $ilDB->quote($sty["class"], "text") . "," .
832  $ilDB->quote($sty["parameter"], "text") . "," .
833  $ilDB->quote($sty["value"], "text") . "," .
834  $ilDB->quote($sty["type"], "text") . "," .
835  $ilDB->quote((int) ($mq_mapping[$sty["mq_id"]] ?? 0), "integer") . "," .
836  $ilDB->quote($sty["custom"], "integer") .
837  ")";
838  $ilDB->manipulate($q);
839  }
840 
841  // add style_data record
842  $q = "INSERT INTO style_data (id, uptodate, category) VALUES " .
843  "(" . $ilDB->quote($this->getId(), "integer") . ", 0," .
844  $ilDB->quote($this->getScope(), "integer") . ")";
845  $ilDB->manipulate($q);
846 
847  // copy images
848  $this->domain->style($this->getId())->cloneResourceContainer($from_style->getId());
849  // copy colors
850  $colors = $from_style->getColors();
851  foreach ($colors as $c) {
852  $color_manager->addColor($c["name"], $c["code"]);
853  }
854 
855  // copy templates
857  foreach ($tcts as $tct => $v) {
858  $templates = $from_style->getTemplates($tct);
859  foreach ($templates as $t) {
860  $this->addTemplate($tct, $t["name"], $t["classes"]);
861  }
862  }
863  }
864 
865  $this->read();
866  if (!$a_import_mode) {
867  $this->writeCSSFile();
868  }
869 
870  return $id;
871  }
872 
876  public function characteristicExists(
877  string $a_char,
878  string $a_style_type
879  ): bool {
880  $ilDB = $this->db;
881 
882  $set = $ilDB->queryF(
883  "SELECT style_id FROM style_char WHERE style_id = %s AND characteristic = %s AND type = %s",
884  array("integer", "text", "text"),
885  array($this->getId(), $a_char, $a_style_type)
886  );
887  if ($ilDB->fetchAssoc($set)) {
888  return true;
889  }
890  return false;
891  }
892 
893  public function addCharacteristic(
894  string $a_type,
895  string $a_char,
896  bool $a_hidden = false,
897  int $order_nr = 0,
898  bool $outdated = false
899  ): void {
900  $ilDB = $this->db;
901 
902  // delete characteristic record
903  $ilDB->insert("style_char", [
904  "style_id" => ["integer", $this->getId()],
905  "type" => ["text", $a_type],
906  "characteristic" => ["text", $a_char],
907  "hide" => ["integer", (int) $a_hidden],
908  "outdated" => ["integer", (int) $outdated],
909  "order_nr" => ["integer", $order_nr]
910  ]);
911 
912  $this->setUpToDate(false);
913  $this->_writeUpToDate($this->getId(), false);
914  }
915 
919  public function getCharacteristics(
920  string $a_type = "",
921  bool $a_no_hidden = false,
922  bool $a_include_core = true
923  ): array {
924  $chars = array();
925 
926  if ($a_type == "") {
927  $chars = $this->chars;
928  }
929  if (isset($this->chars_by_type[$a_type])) {
930  foreach ($this->chars_by_type[$a_type] as $c) {
931  if ($a_include_core || !self::isCoreStyle($a_type, $c)) {
932  $chars[] = $c;
933  }
934  }
935  }
936 
937  if ($a_no_hidden) {
938  foreach ($chars as $k => $char) {
939  if ($a_type == "" && $this->hidden_chars[$char["type"] . ":" . $char["class"]]) {
940  unset($chars[$k]);
941  } elseif ($this->hidden_chars[$a_type . ":" . $char] ?? false) {
942  unset($chars[$k]);
943  }
944  }
945  }
946 
947  return $chars;
948  }
949 
950  public function setCharacteristics(array $a_chars): void
951  {
952  $this->chars = $a_chars;
953  }
954 
958  public function saveHideStatus(
959  string $a_type,
960  string $a_char,
961  bool $a_hide
962  ): void {
963  $ilDB = $this->db;
964 
965  $ilDB->manipulate(
966  "UPDATE style_char SET " .
967  " hide = " . $ilDB->quote((int) $a_hide, "integer") .
968  " WHERE style_id = " . $ilDB->quote($this->getId(), "integer") . " AND " .
969  " type = " . $ilDB->quote($a_type, "text") . " AND " .
970  " characteristic = " . $ilDB->quote($a_char, "text")
971  );
972  }
973 
977  public function getHideStatus(
978  string $a_type,
979  string $a_char
980  ): bool {
981  $ilDB = $this->db;
982 
983  $set = $ilDB->query(
984  "SELECT hide FROM style_char " .
985  " WHERE style_id = " . $ilDB->quote($this->getId(), "integer") . " AND " .
986  " type = " . $ilDB->quote($a_type, "text") . " AND " .
987  " characteristic = " . $ilDB->quote($a_char, "text")
988  );
989  $rec = $ilDB->fetchAssoc($set);
990 
991  return (bool) ($rec["hide"] ?? false);
992  }
993 
997  public function ilClone(): int
998  {
999  $lng = $this->lng;
1000 
1001  $lng->loadLanguageModule("style");
1002 
1003  $new_obj = new ilObjStyleSheet();
1004  $new_obj->setTitle($this->getTitle() . " (" . $lng->txt("sty_acopy") . ")");
1005  $new_obj->setType($this->getType());
1006  $new_obj->setDescription($this->getDescription());
1007  $new_obj->create($this->getId());
1008 
1009  $new_obj->writeStyleSetting(
1010  "disable_auto_margins",
1011  $this->lookupStyleSetting("disable_auto_margins")
1012  );
1013 
1014  return $new_obj->getId();
1015  }
1016 
1020  public function copyImagesToDir(string $a_target): void
1021  {
1022  ilFileUtils::rCopy($this->getImagesDirectory(), $a_target);
1023  }
1024 
1034  public function addParameter(
1035  string $a_tag,
1036  string $a_par,
1037  string $a_type,
1038  int $a_mq_id = 0,
1039  bool $a_custom = false
1040  ): void {
1041  $ilDB = $this->db;
1042 
1043  $avail_params = $this->getAvailableParameters();
1044  $tag = explode(".", $a_tag);
1045  $value = $avail_params[$a_par][0];
1046  $id = $ilDB->nextId("style_parameter");
1047  $q = "INSERT INTO style_parameter (id,style_id, type, tag, class, parameter, value, mq_id, custom) VALUES " .
1048  "(" .
1049  $ilDB->quote($id, "integer") . "," .
1050  $ilDB->quote($this->getId(), "integer") . "," .
1051  $ilDB->quote($a_type, "text") . "," .
1052  $ilDB->quote($tag[0], "text") . "," .
1053  $ilDB->quote($tag[1], "text") . "," .
1054  $ilDB->quote($a_par, "text") . "," .
1055  $ilDB->quote($value, "text") . "," .
1056  $ilDB->quote($a_mq_id, "integer") . "," .
1057  $ilDB->quote($a_custom, "integer") .
1058  ")";
1059  $ilDB->manipulate($q);
1060  $this->read();
1061  $this->writeCSSFile();
1062  }
1063 
1068  public function createImagesDirectory(): void
1069  {
1071  }
1072 
1077  public static function _createImagesDirectory(
1078  int $a_style_id
1079  ): void {
1080  global $DIC;
1081 
1082  $ilErr = $DIC["ilErr"];
1083 
1084  $sty_data_dir = ilFileUtils::getWebspaceDir() . "/sty";
1085  if (!is_dir($sty_data_dir)) {
1086  ilFileUtils::makeDir($sty_data_dir);
1087  }
1088  if (!is_writable($sty_data_dir)) {
1089  $ilErr->raiseError("Style data directory (" . $sty_data_dir
1090  . ") not writeable.", $ilErr->FATAL);
1091  }
1092 
1093  $style_dir = $sty_data_dir . "/sty_" . $a_style_id;
1094  if (!is_dir($style_dir)) {
1095  ilFileUtils::makeDir($style_dir);
1096  }
1097  if (!is_dir($style_dir)) {
1098  $ilErr->raiseError("Creation of style directory failed (" .
1099  $style_dir . ").", $ilErr->FATAL);
1100  }
1101 
1102  // create images subdirectory
1103  $im_dir = $style_dir . "/images";
1104  if (!is_dir($im_dir)) {
1105  ilFileUtils::makeDir($im_dir);
1106  }
1107  if (!is_dir($im_dir)) {
1108  $ilErr->raiseError("Creation of Import Directory failed (" .
1109  $im_dir . ").", $ilErr->FATAL);
1110  }
1111 
1112  // create thumbnails directory
1113  $thumb_dir = $style_dir . "/images/thumbnails";
1114  ilFileUtils::makeDir($thumb_dir);
1115  if (!is_dir($thumb_dir)) {
1116  $ilErr->raiseError("Creation of Import Directory failed (" .
1117  $thumb_dir . ").", $ilErr->FATAL);
1118  }
1119  }
1120 
1121  public function getImagesDirectory(): string
1122  {
1124  }
1125 
1126  public static function _getImagesDirectory(int $a_style_id): string
1127  {
1128  return ilFileUtils::getWebspaceDir() . "/sty/sty_" . $a_style_id .
1129  "/images";
1130  }
1131 
1132  public function getThumbnailsDirectory(): string
1133  {
1134  return $this->getImagesDirectory() .
1135  "/thumbnails";
1136  }
1137 
1141  public function deleteParameter(int $a_id): void
1142  {
1143  $ilDB = $this->db;
1144 
1145  $q = "DELETE FROM style_parameter WHERE id = " .
1146  $ilDB->quote($a_id, "integer");
1147  $ilDB->query($q);
1148  }
1149 
1150 
1158  public function deleteCustomStylePars(
1159  string $a_tag,
1160  string $a_class,
1161  string $a_type,
1162  int $a_mq_id = 0
1163  ): void {
1164  $ilDB = $this->db;
1165 
1166  $q = "DELETE FROM style_parameter WHERE " .
1167  " style_id = " . $ilDB->quote($this->getId(), "integer") . " AND " .
1168  " tag = " . $ilDB->quote($a_tag, "text") . " AND " .
1169  " class = " . $ilDB->quote($a_class, "text") . " AND " .
1170  " mq_id = " . $ilDB->quote($a_mq_id, "integer") . " AND " .
1171  " custom = " . $ilDB->quote(1, "integer") . " AND " .
1172  " " . $ilDB->equals("type", $a_type, "text", true);
1173 
1174  $ilDB->manipulate($q);
1175  }
1176 
1180  public function deleteStyleParOfChar(
1181  string $a_type,
1182  string $a_class
1183  ): void {
1184  $ilDB = $this->db;
1185 
1186  $q = "DELETE FROM style_parameter WHERE " .
1187  " style_id = " . $ilDB->quote($this->getId(), "integer") . " AND " .
1188  " class = " . $ilDB->quote($a_class, "text") . " AND " .
1189  " " . $ilDB->equals("type", $a_type, "text", true);
1190 
1191  $ilDB->manipulate($q);
1192  }
1193 
1194 
1195  public function delete(): bool
1196  {
1197  $ilDB = $this->db;
1198 
1199  // delete object
1200  parent::delete();
1201 
1202  // check whether this style is global default
1203  $def_style = $this->ilias->getSetting("default_content_style_id");
1204  if ($def_style == $this->getId()) {
1205  $this->ilias->deleteSetting("default_content_style_id");
1206  }
1207 
1208  // check whether this style is global fixed
1209  $fixed_style = $this->ilias->getSetting("fixed_content_style_id");
1210  if ($fixed_style == $this->getId()) {
1211  $this->ilias->deleteSetting("fixed_content_style_id");
1212  }
1213 
1214  // delete style parameter
1215  $q = "DELETE FROM style_parameter WHERE style_id = " .
1216  $ilDB->quote($this->getId(), "integer");
1217  $ilDB->manipulate($q);
1218 
1219  // delete style file
1220  $css_file_name = ilFileUtils::getWebspaceDir() . "/css/style_" . $this->getId() . ".css";
1221  if (is_file($css_file_name)) {
1222  unlink($css_file_name);
1223  }
1224 
1225  // delete media queries
1226  $ilDB->manipulate(
1227  "DELETE FROM sty_media_query WHERE " .
1228  " style_id = " . $ilDB->quote($this->getId(), "integer")
1229  );
1230 
1231  // delete entries in learning modules
1233 
1234  // delete style data record
1235  $q = "DELETE FROM style_data WHERE id = " .
1236  $ilDB->quote($this->getId(), "integer");
1237  $ilDB->manipulate($q);
1238 
1239  return true;
1240  }
1241 
1242 
1246  public function read(): void
1247  {
1248  $ilDB = $this->db;
1249 
1250  parent::read();
1251 
1252  $q = "SELECT * FROM style_parameter WHERE style_id = " .
1253  $ilDB->quote($this->getId(), "integer") . " ORDER BY tag, class, type, mq_id ";
1254  $style_set = $ilDB->query($q);
1255  $ctag = "";
1256  $cclass = "";
1257  $ctype = "";
1258  $cmq_id = 0;
1259  $this->style = array();
1260  // workaround for bug #17586, see also http://stackoverflow.com/questions/3066356/multiple-css-classes-properties-overlapping-based-on-the-order-defined
1261  // e.g. ha_iheada must be written after ha_ihead, since they are acting on the same dom node
1262  // styles that must be added at the end
1263  $this->end_styles = array();
1264  $tag = null;
1265  while ($style_rec = $ilDB->fetchAssoc($style_set)) {
1266  if ($style_rec["tag"] != $ctag || $style_rec["class"] != $cclass
1267  || $style_rec["type"] != $ctype || $style_rec["mq_id"] != $cmq_id) {
1268  // add current tag array to style array
1269  if (is_array($tag)) {
1270  if (in_array($ctype, array("ha_iheada", "va_iheada"))) {
1271  $this->end_styles[] = $tag;
1272  } else {
1273  $this->style[] = $tag;
1274  }
1275  }
1276  $tag = array();
1277  }
1278  $ctag = $style_rec["tag"];
1279  $cclass = $style_rec["class"];
1280  $ctype = $style_rec["type"];
1281  $cmq_id = $style_rec["mq_id"];
1282  $tag[] = $style_rec;
1283  // added $cmq_id
1284  $this->style_class[$ctype][$cclass][$cmq_id][$style_rec["parameter"]] = $style_rec["value"];
1285  }
1286  if (is_array($tag)) {
1287  $this->style[] = $tag;
1288  }
1289  foreach ($this->end_styles as $s) {
1290  $this->style[] = $s;
1291  }
1292  //var_dump($this->style_class);
1293  $q = "SELECT * FROM style_data WHERE id = " .
1294  $ilDB->quote($this->getId(), "integer");
1295  $res = $ilDB->query($q);
1296  $sty = $ilDB->fetchAssoc($res);
1297  $this->setUpToDate((bool) $sty["uptodate"]);
1298  $this->setScope((int) $sty["category"]);
1299 
1300  // get style characteristics records
1301  $this->chars = array();
1302  $this->chars_by_type = array();
1303  $q = "SELECT * FROM style_char WHERE style_id = " .
1304  $ilDB->quote($this->getId(), "integer") .
1305  " ORDER BY type ASC, characteristic ASC";
1306  $par_set = $ilDB->query($q);
1307  while ($par_rec = $ilDB->fetchAssoc($par_set)) {
1308  $this->chars[] = array("type" => $par_rec["type"], "class" => $par_rec["characteristic"], "hide" => $par_rec["hide"]);
1309  $this->chars_by_type[$par_rec["type"]][] = $par_rec["characteristic"];
1310  if ($par_rec["hide"]) {
1311  $this->hidden_chars[$par_rec["type"] . ":" . $par_rec["characteristic"]] = true;
1312  }
1313  }
1314  // var_dump($this->style); exit;
1315  }
1316 
1320  public function writeCSSFile(
1321  string $a_target_file = "",
1322  string $a_image_dir = ""
1323  ): void {
1324 
1325  if (true) {
1326  $style_manager = $this->domain->style($this->getId());
1327  $style_manager->writeCss();
1328 
1329  $this->setUpToDate();
1330  $this->_writeUpToDate($this->getId(), true);
1331 
1332  return;
1333  }
1334 
1335  $style = $this->getStyle();
1336 
1337  if (!is_dir(ilFileUtils::getWebspaceDir() . "/css")) {
1339  }
1340 
1341  if ($a_target_file == "") {
1342  $css_file_name = ilFileUtils::getWebspaceDir() . "/css/style_" . $this->getId() . ".css";
1343  } else {
1344  $css_file_name = $a_target_file;
1345  }
1346  $css_file = fopen($css_file_name, 'wb');
1347 
1348  $page_background = "";
1349 
1350  $mqs = array(array("mquery" => "", "id" => 0));
1351  foreach ($this->getMediaQueries() as $mq) {
1352  $mqs[] = $mq;
1353  }
1354 
1355  // iterate all media queries
1356  foreach ($mqs as $mq) {
1357  if ($mq["id"] > 0) {
1358  fwrite($css_file, "@media " . $mq["mquery"] . " {\n");
1359  }
1360  reset($style);
1361  foreach ($style as $tag) {
1362  if ($tag[0]["mq_id"] != $mq["id"]) {
1363  continue;
1364  }
1365  if (is_int(strpos($tag[0]["class"], "before")) && !is_int(strpos($tag[0]["class"], "::before"))) {
1366  $tag[0]["class"] = str_replace(":before", "::before", $tag[0]["class"]);
1367  }
1368  fwrite($css_file, $tag[0]["tag"] . ".ilc_" . $tag[0]["type"] . "_" . $tag[0]["class"] . "\n");
1369  // echo "<br>";
1370  // var_dump($tag[0]["type"]);
1371  if ($tag[0]["tag"] == "td") {
1372  fwrite($css_file, ",th" . ".ilc_" . $tag[0]["type"] . "_" . $tag[0]["class"] . "\n");
1373  }
1374  if (in_array($tag[0]["tag"], array("h1", "h2", "h3"))) {
1375  fwrite($css_file, ",div.ilc_text_block_" . $tag[0]["class"] . "\n");
1376  fwrite($css_file, ",html.il-no-tiny-bg body#tinymce.ilc_text_block_" . $tag[0]["class"] . " > p \n");
1377  }
1378  if ($tag[0]["type"] == "section") { // sections can use a tags, if links are used
1379  fwrite($css_file, ",div a.ilc_" . $tag[0]["type"] . "_" . $tag[0]["class"] . "\n");
1380  }
1381  if ($tag[0]["type"] == "strong") {
1382  fwrite($css_file, ",span.ilc_text_inline_" . $tag[0]["class"] . "\n");
1383  }
1384  if ($tag[0]["type"] == "em") {
1385  fwrite($css_file, ",span.ilc_text_inline_" . $tag[0]["class"] . "\n");
1386  }
1387  if ($tag[0]["type"] == "text_block") {
1388  fwrite($css_file, ",html.il-no-tiny-bg body#tinymce.ilc_text_block_" . $tag[0]["class"] . " > p, #copg-editor-slate-content p.ilc_text_block_" . $tag[0]["class"] . "\n");
1389  }
1390  if ($tag[0]["class"] == "VAccordCntr") {
1391  fwrite($css_file, ",div.ilc_va_cntr_AccordCntr\n");
1392  }
1393  if ($tag[0]["class"] == "VAccordICntr") {
1394  fwrite($css_file, ",div.ilc_va_icntr_AccordICntr\n");
1395  }
1396  if ($tag[0]["class"] == "VAccordICont") {
1397  fwrite($css_file, ",div.ilc_va_icont_AccordICont\n");
1398  }
1399  if ($tag[0]["class"] == "VAccordIHead") {
1400  fwrite($css_file, ",div.ilc_va_ihead_AccordIHead\n");
1401  }
1402  if ($tag[0]["class"] == "VAccordIHead:hover") {
1403  fwrite($css_file, ",div.ilc_va_ihead_AccordIHead:hover\n");
1404  }
1405  if ($tag[0]["class"] == "VAccordIHeadActive") {
1406  fwrite($css_file, ",div.ilc_va_iheada_AccordIHeadActive\n");
1407  }
1408  if ($tag[0]["class"] == "VAccordIHeadActive:hover") {
1409  fwrite($css_file, ",div.ilc_va_iheada_AccordIHeadActive:hover\n");
1410  }
1411  fwrite($css_file, "{\n");
1412 
1413  // collect table border attributes
1414  $t_border = array();
1415 
1416  foreach ($tag as $par) {
1417  $cur_par = $par["parameter"] ?? '';
1418  $cur_val = $par["value"] ?? '';
1419 
1420  // replace named colors
1421  if (is_int(strpos($cur_par, "color")) && substr(trim($cur_val), 0, 1) == "!") {
1422  $cur_val = $this->getColorCodeForName(substr($cur_val, 1));
1423  }
1424 
1425  if ($tag[0]["type"] == "table" && is_int(strpos($par["parameter"], "border"))) {
1426  $t_border[$cur_par] = $cur_val;
1427  }
1428 
1429  if (in_array($cur_par, array("background-image", "list-style-image"))) {
1430  if (is_int(strpos($cur_val, "/"))) { // external
1431  $cur_val = "url(" . $cur_val . ")";
1432  } else { // internal
1433  if ($a_image_dir == "") {
1434  $cur_val = "url(../sty/sty_" . $this->getId() . "/images/" . $cur_val . ")";
1435  } else {
1436  $cur_val = "url(" . $a_image_dir . "/" . $cur_val . ")";
1437  }
1438  }
1439  }
1440 
1441  if ($cur_par == "opacity") {
1442  $cur_val = ((int) $cur_val) / 100;
1443  }
1444 
1445  fwrite($css_file, "\t" . $cur_par . ": " . $cur_val . ";\n");
1446 
1447  // IE6 fix for minimum height
1448  /*
1449  if ($cur_par == "min-height") {
1450  fwrite($css_file, "\t" . "height" . ": " . "auto !important" . ";\n");
1451  fwrite($css_file, "\t" . "height" . ": " . $cur_val . ";\n");
1452  }*/
1453 
1454  // opacity fix
1455  if ($cur_par == "opacity") {
1456  fwrite($css_file, "\t" . '-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=' . ($cur_val * 100) . ')"' . ";\n");
1457  fwrite($css_file, "\t" . 'filter: alpha(opacity=' . ($cur_val * 100) . ')' . ";\n");
1458  fwrite($css_file, "\t" . '-moz-opacity: ' . $cur_val . ";\n");
1459  }
1460 
1461  // transform fix
1462  if ($cur_par == "transform") {
1463  fwrite($css_file, "\t" . '-webkit-transform: ' . $cur_val . ";\n");
1464  fwrite($css_file, "\t" . '-moz-transform: ' . $cur_val . ";\n");
1465  fwrite($css_file, "\t" . '-ms-transform: ' . $cur_val . ";\n");
1466  }
1467 
1468  // transform-origin fix
1469  if ($cur_par == "transform-origin") {
1470  fwrite($css_file, "\t" . '-webkit-transform-origin: ' . $cur_val . ";\n");
1471  fwrite($css_file, "\t" . '-moz-transform-origin: ' . $cur_val . ";\n");
1472  fwrite($css_file, "\t" . '-ms-transform-origin: ' . $cur_val . ";\n");
1473  }
1474 
1475  // save page background
1476  if ($tag[0]["tag"] == "div" && $tag[0]["class"] == "Page"
1477  && $cur_par == "background-color") {
1478  $page_background = $cur_val;
1479  }
1480  }
1481  fwrite($css_file, "}\n");
1482  fwrite($css_file, "\n");
1483 
1484  // use table border attributes for th td as well
1485  /* if ($tag[0]["type"] == "table")
1486  {
1487  if (count($t_border) > 0)
1488  {
1489  fwrite ($css_file, $tag[0]["tag"].".ilc_".$tag[0]["type"]."_".$tag[0]["class"]." th,".
1490  $tag[0]["tag"].".ilc_".$tag[0]["type"]."_".$tag[0]["class"]." td\n");
1491  fwrite ($css_file, "{\n");
1492  foreach ($t_border as $p => $v)
1493  {
1494  // fwrite ($css_file, "\t".$p.": ".$v.";\n");
1495  }
1496  fwrite ($css_file, "}\n");
1497  fwrite ($css_file, "\n");
1498  }
1499  }*/
1500  }
1501 
1502  if ($page_background != "") {
1503  fwrite($css_file, "td.ilc_Page\n");
1504  fwrite($css_file, "{\n");
1505  fwrite($css_file, "\t" . "background-color: " . $page_background . ";\n");
1506  fwrite($css_file, "}\n");
1507  }
1508  if ($mq["id"] > 0) {
1509  fwrite($css_file, "}\n");
1510  }
1511  }
1512  fclose($css_file);
1513  // exit;
1514  $this->setUpToDate();
1515  $this->_writeUpToDate($this->getId(), true);
1516  }
1517 
1524  public static function getEffectiveContentStyleId(
1525  int $a_style_id
1526  ): int {
1527  global $DIC;
1528 
1529  $ilSetting = $DIC->settings();
1530 
1531  // check global fixed content style
1532  $fixed_style = $ilSetting->get("fixed_content_style_id");
1533  if ($fixed_style > 0) {
1534  $a_style_id = (int) $fixed_style;
1535  }
1536 
1537  // check global default style
1538  if ($a_style_id <= 0) {
1539  $a_style_id = (int) $ilSetting->get("default_content_style_id");
1540  }
1541 
1542  if ($a_style_id > 0 && ilObject::_lookupType($a_style_id) === "sty") {
1543  return $a_style_id;
1544  }
1545 
1546  return 0;
1547  }
1548 
1549  public function getParametersOfClass(
1550  string $a_type,
1551  string $a_class,
1552  int $a_mq_id = 0
1553  ): array {
1554  if (is_array($this->style_class[$a_type][$a_class][$a_mq_id])) {
1555  return $this->style_class[$a_type][$a_class][$a_mq_id];
1556  }
1557  return array();
1558  }
1559 
1560  public static function getExportContentStylePath(): string
1561  {
1562  return "content_style/style.css";
1563  }
1564 
1569  public static function getContentStylePath(
1570  int $a_style_id,
1571  bool $add_random = true,
1572  bool $add_token = true
1573  ): string {
1574  global $DIC;
1575  $ilSetting = $DIC->settings();
1576 
1577  $random = new \Random\Randomizer();
1578  $rand = $random->getInt(1, 999999);
1579 
1580  // check global fixed content style
1581  $fixed_style = $ilSetting->get("fixed_content_style_id");
1582  if ($fixed_style > 0) {
1583  $a_style_id = (int) $fixed_style;
1584  }
1585 
1586  // check global default style
1587  if ($a_style_id <= 0) {
1588  $a_style_id = (int) $ilSetting->get("default_content_style_id");
1589  }
1590 
1591  if ($a_style_id > 0 && ilObject::_exists($a_style_id)) {
1592  // check whether file is up to date
1593  if (!ilObjStyleSheet::_lookupUpToDate($a_style_id)) {
1594  $style = new ilObjStyleSheet($a_style_id);
1595  $style->writeCSSFile();
1596  }
1597 
1598  $style_manager = $DIC->contentStyle()->internal()->domain()->style($a_style_id);
1599  $path = $style_manager->getPath();
1600  return $path;
1601  } else { // todo: work this out
1602  return "./components/ILIAS/COPage/css/content.css";
1603  }
1604  }
1605 
1606  public static function getContentPrintStyle(): string
1607  {
1608  return "./components/ILIAS/COPage/css/print_content.css";
1609  }
1610 
1611  public static function getSyntaxStylePath(): string
1612  {
1613  return "./components/ILIAS/COPage/css/syntaxhighlight.css";
1614  }
1615 
1616  public static function getBaseContentStylePath(): string
1617  {
1618  return "./components/ILIAS/COPage/css/content_base.css";
1619  }
1620 
1621  public function update(): bool
1622  {
1623  $ilDB = $this->db;
1624 
1625  parent::update();
1626  $this->read(); // this could be done better
1627  $this->writeCSSFile();
1628 
1629  $q = "UPDATE style_data " .
1630  "SET category = " . $ilDB->quote($this->getScope(), "integer") .
1631  " WHERE id = " . $ilDB->quote($this->getId(), "integer");
1632  $ilDB->manipulate($q);
1633 
1634  return true;
1635  }
1636 
1640  public function updateStyleParameter(
1641  int $a_id,
1642  string $a_value
1643  ): void {
1644  $ilDB = $this->db;
1645 
1646  $q = "UPDATE style_parameter SET VALUE = " .
1647  $ilDB->quote($a_value, "text") . " WHERE id = " .
1648  $ilDB->quote($a_id, "integer");
1649  $style_set = $ilDB->manipulate($q);
1650  }
1651 
1652  public function getStyle(): array
1653  {
1654  return $this->style;
1655  }
1656 
1657  public function setStyle(array $a_style): void
1658  {
1659  $this->style = $a_style;
1660  }
1661 
1662  public function handleXmlString(string $a_str): string
1663  {
1664  return str_replace("&", "&amp;", $a_str);
1665  }
1666 
1671  public function getXML(): string
1672  {
1673  $xml = "<StyleSheet>\n";
1674 
1675  // title and description
1676  $xml .= "<Title>" . $this->handleXmlString($this->getTitle()) . "</Title>";
1677  $xml .= "<Description>" . $this->handleXmlString($this->getDescription()) . "</Description>\n";
1678 
1679  // style classes
1680  foreach ($this->chars as $char) {
1681  $xml .= "<Style Tag=\"" . ilObjStyleSheet::_determineTag($char["type"]) .
1682  "\" Type=\"" . $char["type"] . "\" Class=\"" . $char["class"] . "\">\n";
1683  foreach ($this->style as $style) {
1684  if ($style[0]["type"] == $char["type"] && $style[0]["class"] == $char["class"]) {
1685  foreach ($style as $tag) {
1686  $xml .= "<StyleParameter Name=\"" . $tag["parameter"] . "\" Value=\"" . $tag["value"] . "\" Custom=\"" . $tag["custom"] . "\" />\n";
1687  }
1688  }
1689  }
1690  $xml .= "</Style>\n";
1691  }
1692 
1693  // colors
1694  foreach ($this->getColors() as $color) {
1695  $xml .= "<StyleColor Name=\"" . $color["name"] . "\" Code=\"" . $color["code"] . "\"/>\n";
1696  }
1697 
1698  // templates
1700  foreach ($tcts as $tct => $v) {
1701  $ts = $this->getTemplates($tct);
1702 
1703  foreach ($ts as $t) {
1704  $xml .= "<StyleTemplate Type=\"" . $tct . "\" Name=\"" . $t["name"] . "\">\n";
1705  foreach ($t["classes"] as $ct => $c) {
1706  if ($c != "") {
1707  $xml .= "<StyleTemplateClass ClassType=\"" . $ct . "\" Class=\"" . $c . "\"/>\n";
1708  }
1709  }
1710  $xml .= "</StyleTemplate>\n";
1711  }
1712  }
1713 
1714 
1715  $xml .= "</StyleSheet>";
1716  //echo "<pre>".htmlentities($xml)."</pre>"; exit;
1717  return $xml;
1718  }
1719 
1720  public function createExportDirectory(): string
1721  {
1722  $sty_data_dir = ilFileUtils::getDataDir() . "/sty";
1723  ilFileUtils::makeDir($sty_data_dir);
1724  if (!is_writable($sty_data_dir)) {
1725  $this->ilias->raiseError("Style data directory (" . $sty_data_dir
1726  . ") not writeable.", $this->ilias->error_obj->FATAL);
1727  }
1728 
1729  $style_dir = $sty_data_dir . "/sty_" . $this->getId();
1730  ilFileUtils::makeDir($style_dir);
1731  if (!is_dir($style_dir)) {
1732  $this->ilias->raiseError("Creation of style directory failed (" .
1733  $style_dir . ").", $this->ilias->error_obj->FATAL);
1734  }
1735 
1736  // create export subdirectory
1737  $ex_dir = $style_dir . "/export";
1738  ilFileUtils::makeDir($ex_dir);
1739  if (!is_dir($ex_dir)) {
1740  $this->ilias->raiseError("Creation of Import Directory failed (" .
1741  $ex_dir . ").", $this->ilias->error_obj->FATAL);
1742  }
1743 
1744  return $ex_dir;
1745  }
1746 
1747  public function cleanExportDirectory(): void
1748  {
1749  $sty_data_dir = ilFileUtils::getDataDir() . "/sty";
1750  $style_dir = $sty_data_dir . "/sty_" . $this->getId();
1751  // create export subdirectory
1752  $ex_dir = $style_dir . "/export";
1753 
1754  if (is_dir($ex_dir)) {
1755  ilFileUtils::delDir($ex_dir, true);
1756  }
1757  }
1758 
1759  public function createExportSubDirectory()
1760  {
1761  $ex_dir = $this->createExportDirectory();
1762  $ex_sub_dir = $ex_dir . "/" . $this->getExportSubDir();
1763  ilFileUtils::makeDir($ex_sub_dir);
1764  if (!is_writable($ex_sub_dir)) {
1765  $this->ilias->raiseError("Style data directory (" . $ex_sub_dir
1766  . ") not writeable.", $this->ilias->error_obj->FATAL);
1767  }
1768  $ex_sub_images_dir = $ex_sub_dir . "/images";
1769  ilFileUtils::makeDir($ex_sub_images_dir);
1770  if (!is_writable($ex_sub_images_dir)) {
1771  $this->ilias->raiseError("Style data directory (" . $ex_sub_images_dir
1772  . ") not writeable.", $this->ilias->error_obj->FATAL);
1773  }
1774  }
1775 
1779  public function setExportSubDir(string $a_dir): void
1780  {
1781  $this->export_sub_dir = $a_dir;
1782  }
1783 
1787  public function getExportSubDir(): string
1788  {
1789  if ($this->export_sub_dir == "") {
1790  return "sty_" . $this->getId();
1791  } else {
1792  return $this->export_sub_dir;
1793  }
1794  }
1795 
1802  public function export(): string
1803  {
1804  $this->cleanExportDirectory();
1805  $ex_dir = $this->createExportDirectory();
1806  $this->createExportSubDirectory();
1807  $this->exportXML($ex_dir . "/" . $this->getExportSubDir());
1808  //echo "-".$this->getImagesDirectory()."-".$ex_dir."/".$this->getExportSubDir()."/images"."-";
1810  $this->getImagesDirectory(),
1811  $ex_dir . "/" . $this->getExportSubDir() . "/images"
1812  );
1813  if (is_file($ex_dir . "/" . $this->getExportSubDir() . ".zip")) {
1814  unlink($ex_dir . "/" . $this->getExportSubDir() . ".zip");
1815  }
1817  $ex_dir . "/" . $this->getExportSubDir(),
1818  $ex_dir . "/" . $this->getExportSubDir() . ".zip"
1819  );
1820 
1821  return $ex_dir . "/" . $this->getExportSubDir() . ".zip";
1822  }
1823 
1827  public function exportXML(string $a_dir): void
1828  {
1829  $file = $a_dir . "/style.xml";
1830 
1831  // open file
1832  if (!($fp = fopen($file, 'wb'))) {
1833  die("<strong>Error</strong>: Could not open \"" . $file . "\" for writing" .
1834  " in <strong>" . __FILE__ . "</strong> on line <strong>" . __LINE__ . "</strong><br />");
1835  }
1836 
1837  // set file permissions
1838  chmod($file, 0770);
1839 
1840  // write xml data into the file
1841  fwrite($fp, $this->getXML());
1842 
1843  // close file
1844  fclose($fp);
1845  }
1846 
1847  public function createImportDirectory(): string
1848  {
1849  $sty_data_dir = ilFileUtils::getDataDir() . "/sty";
1850  ilFileUtils::makeDir($sty_data_dir);
1851  if (!is_writable($sty_data_dir)) {
1852  $this->ilias->raiseError("Style data directory (" . $sty_data_dir
1853  . ") not writeable.", $this->ilias->error_obj->FATAL);
1854  }
1855 
1856  $style_dir = $sty_data_dir . "/sty_" . $this->getId();
1857  ilFileUtils::makeDir($style_dir);
1858  if (!is_dir($style_dir)) {
1859  $this->ilias->raiseError("Creation of style directory failed (" .
1860  $style_dir . ").", $this->ilias->error_obj->FATAL);
1861  }
1862 
1863  // create import subdirectory
1864  $im_dir = $style_dir . "/import";
1865  ilFileUtils::makeDir($im_dir);
1866  if (!is_dir($im_dir)) {
1867  $this->ilias->raiseError("Creation of Import Directory failed (" .
1868  $im_dir . ").", $this->ilias->error_obj->FATAL);
1869  }
1870 
1871  return $im_dir;
1872  }
1873 
1881  public function import($a_file): void
1882  {
1883  parent::create();
1884  $subdir = "";
1885  $im_dir = $this->createImportDirectory();
1886 
1887  // handle uploaded files
1888  if (is_array($a_file)) {
1890  $a_file["tmp_name"],
1891  $a_file["name"],
1892  $im_dir . "/" . $a_file["name"]
1893  );
1894  $file_name = $a_file["name"];
1895  } else { // handle not directly uploaded files
1896  $pi = pathinfo($a_file);
1897  $file_name = $pi["basename"];
1898  copy($a_file, $im_dir . "/" . $file_name);
1899  }
1900  $file = pathinfo($file_name);
1901 
1902  // unzip file
1903  if (strtolower($file["extension"]) == "zip") {
1904  $this->domain->resources()->zip()->unzipFile($im_dir . "/" . $file_name);
1905  $subdir = basename($file["basename"], "." . $file["extension"]);
1906  if (!is_dir($im_dir . "/" . $subdir)) {
1907  $subdir = "style"; // check style subdir
1908  }
1909  $xml_file = $im_dir . "/" . $subdir . "/style.xml";
1910  } else { // handle xml file directly (old style)
1911  $xml_file = $im_dir . "/" . $file_name;
1912  }
1913 
1914  // load information from xml file
1915  //echo "-$xml_file-";
1916  $this->createFromXMLFile($xml_file, true);
1917 
1919  $this->read();
1920  $this->writeCSSFile();
1921  }
1922 
1927  public function createFromXMLFile(
1928  string $a_file,
1929  bool $a_skip_parent_create = false
1930  ): void {
1931  $ilDB = $this->db;
1932 
1933  $this->is_3_10_skin = false;
1934 
1935  if (!$a_skip_parent_create) {
1936  parent::create();
1937  }
1938  $importParser = new ilStyleImportParser($a_file, $this);
1939  $importParser->startParsing();
1940 
1941  // store style parameter
1942  foreach ($this->style as $style) {
1943  foreach ($style as $tag) {
1944  $id = $ilDB->nextId("style_parameter");
1945 
1946  // migrate old table PageFrame/PageContainer to div
1947  if (in_array($tag["class"], array("PageFrame", "PageContainer")) &&
1948  $tag["tag"] == "table") {
1949  $tag["tag"] = "div";
1950  if ($tag["parameter"] == "width" && $tag["value"] == "100%") {
1951  continue;
1952  }
1953  }
1954 
1955  if ($tag["type"] === "text_block" && $tag["tag"] === "div") {
1956  $tag["tag"] = "p";
1957  }
1958 
1959  $q = "INSERT INTO style_parameter (id,style_id, tag, class, parameter, type, value, custom) VALUES " .
1960  "(" .
1961  $ilDB->quote($id, "integer") . "," .
1962  $ilDB->quote($this->getId(), "integer") . "," .
1963  $ilDB->quote($tag["tag"], "text") . "," .
1964  $ilDB->quote($tag["class"], "text") . "," .
1965  $ilDB->quote($tag["parameter"], "text") . "," .
1966  $ilDB->quote($tag["type"], "text") . "," .
1967  $ilDB->quote($tag["value"], "text") . "," .
1968  $ilDB->quote((bool) $tag["custom"], "integer") .
1969  ")";
1970  $ilDB->manipulate($q);
1971  }
1972  }
1973 
1974  // store characteristics
1975  $this->is_3_10_skin = true;
1976  foreach ($this->chars as $char) {
1977  if ($char["type"] != "") {
1978  $s = substr($char["class"], strlen($char["class"]) - 6);
1979  if ($s != ":hover") {
1980  $ilDB->replace(
1981  "style_char",
1982  array(
1983  "style_id" => array("integer", $this->getId()),
1984  "type" => array("text", $char["type"]),
1985  "characteristic" => array("text", ilStr::subStr($char["class"], 0, 30))),
1986  array("hide" => array("integer", 0))
1987  );
1988  $this->is_3_10_skin = false;
1989  }
1990  }
1991  }
1992 
1993  // add style_data record
1994  $q = "INSERT INTO style_data (id, uptodate) VALUES " .
1995  "(" . $ilDB->quote($this->getId(), "integer") . ", 0)";
1996  $ilDB->manipulate($q);
1997 
1998  $this->update();
1999  $this->read();
2000 
2001  if ($this->is_3_10_skin) {
2002  $this->do_3_10_Migration();
2003  }
2004  //$this->writeCSSFile();
2005  }
2006 
2010  public function getStyleParameterGroups(): array
2011  {
2012  $groups = array();
2013 
2014  foreach (self::$parameter as $parameter => $props) {
2015  $groups[$props["group"]][] = $parameter;
2016  }
2017  return $groups;
2018  }
2019 
2020  public static function _getStyleParameterInputType(string $par): string
2021  {
2022  $input = self::$parameter[$par]["input"];
2023  return $input;
2024  }
2025 
2026  public static function _getStyleParameterSubPar(string $par): string
2027  {
2028  $subpar = self::$parameter[$par]["subpar"];
2029  return $subpar;
2030  }
2031 
2032  public static function _getStyleParameters(
2033  string $a_tag = ""
2034  ): array {
2035  if ($a_tag == "") {
2036  return self::$parameter;
2037  }
2038  $par = array();
2039  foreach (self::$parameter as $k => $v) {
2040  if (isset(self::$filtered_groups[$v["group"]]) &&
2041  !in_array($a_tag, self::$filtered_groups[$v["group"]])) {
2042  continue;
2043  }
2044  $par[$k] = $v;
2045  }
2046  return $par;
2047  }
2048 
2049  public static function _getFilteredGroups(): array
2050  {
2051  return self::$filtered_groups;
2052  }
2053 
2054  public static function _getStyleParameterNumericUnits(
2055  bool $a_no_percentage = false
2056  ): array {
2057  if ($a_no_percentage) {
2058  return self::$num_unit_no_perc;
2059  }
2060  return self::$num_unit;
2061  }
2062 
2063  public static function _getStyleParameterValues(
2064  string $par
2065  ): array {
2066  return self::$parameter[$par]["values"];
2067  }
2068 
2069  public static function _getStyleSuperTypes(): array
2070  {
2071  return self::$style_super_types;
2072  }
2073 
2074  public static function _isExpandable(string $a_type): bool
2075  {
2076  return in_array($a_type, self::$expandable_types);
2077  }
2078 
2079  public static function _isHideable(string $a_type): bool
2080  {
2081  return in_array($a_type, self::$hideable_types);
2082  }
2083 
2084  public static function _getStyleSuperTypeForType(
2085  string $a_type
2086  ): string {
2087  foreach (self::$style_super_types as $s => $t) {
2088  if (in_array($a_type, $t)) {
2089  return $s;
2090  }
2091  if ($a_type == $s) {
2092  return $s;
2093  }
2094  }
2095  return "";
2096  }
2097 
2098  public static function _getCoreStyles(): array
2099  {
2100  $c_styles = array();
2101  foreach (self::$core_styles as $cstyle) {
2102  $c_styles[$cstyle["type"] . "." . ilObjStyleSheet::_determineTag($cstyle["type"]) . "." . $cstyle["class"]]
2103  = array("type" => $cstyle["type"],
2104  "tag" => ilObjStyleSheet::_determineTag($cstyle["type"]),
2105  "class" => $cstyle["class"]);
2106  }
2107  return $c_styles;
2108  }
2109 
2110  public static function isCoreStyle(
2111  string $a_type,
2112  string $a_class
2113  ): bool {
2114  foreach (self::$core_styles as $s) {
2115  if ($s["type"] == $a_type && $s["class"] == $a_class) {
2116  return true;
2117  }
2118  }
2119  return false;
2120  }
2121 
2125  public static function _getTemplateClassTypes(
2126  string $a_template_type = ""
2127  ): array {
2128  if ($a_template_type == "") {
2129  return self::$templates;
2130  }
2131  return self::$templates[$a_template_type];
2132  }
2133 
2134  public static function _getPseudoClasses(string $tag): array
2135  {
2136  return self::$pseudo_classes[$tag] ?? [];
2137  }
2138 
2139  // e.g. table, row_head > table_cell
2141  string $t,
2142  string $k
2143  ): string {
2144  return self::$templates[$t][$k];
2145  }
2146 
2147  public static function _determineTag(string $a_type): string
2148  {
2149  return self::$assigned_tags[$a_type];
2150  }
2151 
2152  public static function getAvailableParameters(): array
2153  {
2154  $pars = array();
2155  foreach (self::$parameter as $p => $v) {
2156  $pars[$p] = $v["values"];
2157  }
2158 
2159  return $pars;
2160  }
2161 
2165  public static function _addMissingStyleClassesToStyle(
2166  int $a_id
2167  ): void {
2168  $styles = array(array("id" => $a_id));
2170  }
2171 
2176  public static function _addMissingStyleClassesToAllStyles(
2177  ?array $a_styles = null
2178  ): void {
2179  global $DIC;
2180 
2181  $ilDB = $DIC->database();
2182 
2183  if (is_null($a_styles)) {
2184  $styles = ilObject::_getObjectsDataForType("sty");
2185  } else {
2186  $styles = $a_styles;
2187  }
2188  $core_styles = ilObjStyleSheet::_getCoreStyles();
2190 
2191  // get all core image files
2192  $core_images = array();
2193  $core_dir = self::$basic_style_image_dir;
2194  if (is_dir($core_dir)) {
2195  $dir = opendir($core_dir);
2196  while ($file = readdir($dir)) {
2197  if (substr($file, 0, 1) != "." && is_file($core_dir . "/" . $file)) {
2198  $core_images[] = $file;
2199  }
2200  }
2201  }
2202 
2203  foreach ($styles as $style) {
2204  $id = $style["id"];
2205 
2206  foreach ($core_styles as $cs) {
2207  // check, whether core style class exists
2208  $set = $ilDB->queryF(
2209  "SELECT * FROM style_char WHERE style_id = %s " .
2210  "AND type = %s AND characteristic = %s",
2211  array("integer", "text", "text"),
2212  array($id, $cs["type"], $cs["class"])
2213  );
2214 
2215  // if not, add core style class
2216  if (!($rec = $ilDB->fetchAssoc($set))) {
2217  $ilDB->manipulateF(
2218  "INSERT INTO style_char (style_id, type, characteristic) " .
2219  " VALUES (%s,%s,%s) ",
2220  array("integer", "text", "text"),
2221  array($id, $cs["type"], $cs["class"])
2222  );
2223 
2224  $xpath = new DOMXPath($bdom);
2225  $par_nodes = $xpath->query("/StyleSheet/Style[@Tag = '" . $cs["tag"] . "' and @Type='" .
2226  $cs["type"] . "' and @Class='" . $cs["class"] . "']/StyleParameter");
2227  foreach ($par_nodes as $par_node) {
2228  // check whether style parameter exists
2229  $set = $ilDB->queryF(
2230  "SELECT * FROM style_parameter WHERE style_id = %s " .
2231  "AND type = %s AND class = %s AND tag = %s AND parameter = %s",
2232  array("integer", "text", "text", "text", "text"),
2233  array($id, $cs["type"], $cs["class"],
2234  $cs["tag"], $par_node->getAttribute("Name"))
2235  );
2236 
2237  // if not, create style parameter
2238  if (!($ilDB->fetchAssoc($set))) {
2239  $spid = $ilDB->nextId("style_parameter");
2240  $st = $ilDB->manipulateF(
2241  "INSERT INTO style_parameter (id, style_id, type, class, tag, parameter, value) " .
2242  " VALUES (%s,%s,%s,%s,%s,%s,%s)",
2243  array("integer", "integer", "text", "text", "text", "text", "text"),
2244  array($spid, $id, $cs["type"], $cs["class"], $cs["tag"],
2245  $par_node->getAttribute("Name"), $par_node->getAttribute("Value"))
2246  );
2247  }
2248  }
2249  }
2250  }
2251 
2252  // now check, whether some core image files are missing
2255  foreach ($core_images as $cim) {
2256  if (!is_file($imdir . "/" . $cim)) {
2257  copy($core_dir . "/" . $cim, $imdir . "/" . $cim);
2258  }
2259  }
2260  }
2261  }
2262 
2263  //
2264  // Color management
2265  //
2266 
2270  public function do_3_10_Migration(): void
2271  {
2272  $ilDB = $this->db;
2273 
2274  $this->do_3_9_Migration($this->getId());
2275 
2276  $this->do_3_10_CharMigration($this->getId());
2277 
2278  // style_char: type for characteristic
2279  $st = $ilDB->prepareManip("UPDATE style_char SET type = ? WHERE characteristic = ?" .
2280  " AND style_id = ? ", array("text", "text", "integer"));
2281  $ilDB->execute($st, array("media_cont", "Media", $this->getId()));
2282  $ilDB->execute($st, array("media_caption", "MediaCaption", $this->getId()));
2283  $ilDB->execute($st, array("page_fn", "Footnote", $this->getId()));
2284  $ilDB->execute($st, array("page_nav", "LMNavigation", $this->getId()));
2285  $ilDB->execute($st, array("page_title", "PageTitle", $this->getId()));
2286  $ilDB->execute($st, array("page_cont", "Page", $this->getId()));
2287 
2288  // style_parameter: type for class
2289  $st = $ilDB->prepareManip("UPDATE style_parameter SET type = ? WHERE class = ?" .
2290  " AND style_id = ? ", array("text", "text", "integer"));
2291  $ilDB->execute($st, array("media_cont", "Media", $this->getId()));
2292  $ilDB->execute($st, array("media_caption", "MediaCaption", $this->getId()));
2293  $ilDB->execute($st, array("page_fn", "Footnote", $this->getId()));
2294  $ilDB->execute($st, array("page_nav", "LMNavigation", $this->getId()));
2295  $ilDB->execute($st, array("page_title", "PageTitle", $this->getId()));
2296  $ilDB->execute($st, array("table", "Page", $this->getId()));
2297 
2298  $st = $ilDB->prepareManip("UPDATE style_parameter SET tag = ? WHERE class = ?" .
2299  " AND style_id = ? ", array("text", "text", "integer"));
2300  $ilDB->execute($st, array("div", "MediaCaption", $this->getId()));
2301 
2302  // style_char: characteristic for characteristic
2303  $st = $ilDB->prepareManip("UPDATE style_char SET characteristic = ? WHERE characteristic = ?" .
2304  " AND style_id = ? ", array("text", "text", "integer"));
2305  $ilDB->execute($st, array("MediaContainer", "Media", $this->getId()));
2306  $ilDB->execute($st, array("PageContainer", "Page", $this->getId()));
2307 
2308  // style_parameter: class for class
2309  $st = $ilDB->prepareManip("UPDATE style_parameter SET class = ? WHERE class = ?" .
2310  " AND style_id = ? ", array("text", "text", "integer"));
2311  $ilDB->execute($st, array("MediaContainer", "Media", $this->getId()));
2312  $ilDB->execute($st, array("PageContainer", "Page", $this->getId()));
2313 
2314  // force rewriting of container style
2315  $st = $ilDB->prepareManip("DELETE FROM style_char WHERE type = ?" .
2316  " AND style_id = ? ", array("text", "integer"));
2317  $ilDB->execute($st, array("page_cont", $this->getId()));
2318  $st = $ilDB->prepareManip("DELETE FROM style_parameter WHERE type = ?" .
2319  " AND style_id = ? ", array("text", "integer"));
2320  $ilDB->execute($st, array("page_cont", $this->getId()));
2321  }
2322 
2328  public function do_3_10_CharMigration(int $a_id = 0): void
2329  {
2330  $ilDB = $this->db;
2331 
2332  $add_str = "";
2333  if ($a_id > 0) {
2334  $add_str = " AND style_id = " . $ilDB->quote($a_id, "integer");
2335  }
2336 
2337  $set = $ilDB->query($q = "SELECT DISTINCT style_id, tag, class FROM style_parameter WHERE " .
2338  $ilDB->equals("type", "", "text", true) . " " . $add_str);
2339 
2340  while ($rec = $ilDB->fetchAssoc($set)) {
2341  // derive types from tag
2342  $types = array();
2343  switch ($rec["tag"]) {
2344  case "div":
2345  case "p":
2346  if (in_array($rec["class"], array("Headline3", "Headline1",
2347  "Headline2", "TableContent", "List", "Standard", "Remark",
2348  "Additional", "Mnemonic", "Citation", "Example"))) {
2349  $types[] = "text_block";
2350  }
2351  if (in_array($rec["class"], array("Block", "Remark",
2352  "Additional", "Mnemonic", "Example", "Excursus", "Special"))) {
2353  $types[] = "section";
2354  }
2355  if (in_array($rec["class"], array("Page", "Footnote", "PageTitle", "LMNavigation"))) {
2356  $types[] = "page";
2357  }
2358  break;
2359 
2360  case "td":
2361  $types[] = "table_cell";
2362  break;
2363 
2364  case "a":
2365  if (in_array($rec["class"], array("ExtLink", "IntLink", "FootnoteLink"))) {
2366  $types[] = "link";
2367  }
2368  break;
2369 
2370  case "span":
2371  $types[] = "text_inline";
2372  break;
2373 
2374  case "table":
2375  $types[] = "table";
2376  break;
2377  }
2378 
2379  // check if style_char set exists
2380  foreach ($types as $t) {
2381  // check if second type already exists
2382  $set4 = $ilDB->queryF(
2383  "SELECT * FROM style_char " .
2384  " WHERE style_id = %s AND type = %s AND characteristic = %s",
2385  array("integer", "text", "text"),
2386  array($rec["style_id"], $t, $rec["class"])
2387  );
2388  if ($rec4 = $ilDB->fetchAssoc($set4)) {
2389  // ok
2390  } else {
2391  //echo "<br>1-".$rec["style_id"]."-".$t."-".$rec["class"]."-";
2392  $ilDB->manipulateF(
2393  "INSERT INTO style_char " .
2394  " (style_id, type, characteristic) VALUES " .
2395  " (%s,%s,%s) ",
2396  array("integer", "text", "text"),
2397  array($rec["style_id"], $t, $rec["class"])
2398  );
2399  }
2400  }
2401 
2402  // update types
2403  if ($rec["type"] == "") {
2404  if (count($types) > 0) {
2405  $ilDB->manipulateF(
2406  "UPDATE style_parameter SET type = %s " .
2407  " WHERE style_id = %s AND class = %s AND " . $ilDB->equals("type", "", "text", true),
2408  array("text", "integer", "text"),
2409  array($types[0], $rec["style_id"], $rec["class"])
2410  );
2411  //echo "<br>3-".$types[0]."-".$rec["style_id"]."-".$rec["class"]."-";
2412 
2413  // links extra handling
2414  if ($types[0] == "link") {
2415  $ilDB->manipulateF(
2416  "UPDATE style_parameter SET type = %s " .
2417  " WHERE style_id = %s AND (class = %s OR class = %s) AND " . $ilDB->equals("type", "", "text", true),
2418  array("text", "integer", "text", "text"),
2419  array($types[0], $rec["style_id"], $rec["class"] . ":visited",
2420  $rec["class"] . ":hover")
2421  );
2422  }
2423  }
2424 
2425  if (count($types) == 2) {
2426  // select all records of first type and add second type
2427  // records if necessary.
2428  $set2 = $ilDB->queryF(
2429  "SELECT * FROM style_parameter " .
2430  " WHERE style_id = %s AND class = %s AND type = %s",
2431  array("integer", "text", "text"),
2432  array($rec["style_id"], $rec["class"], $types[0])
2433  );
2434  while ($rec2 = $ilDB->fetchAssoc($set2)) {
2435  // check if second type already exists
2436  $set3 = $ilDB->queryF(
2437  "SELECT * FROM style_parameter " .
2438  " WHERE style_id = %s AND tag = %s AND class = %s AND type = %s AND parameter = %s",
2439  array("integer", "text", "text", "text", "text"),
2440  array($rec["style_id"], $rec["tag"], $rec["class"], $types[1], $rec["parameter"])
2441  );
2442  if ($rec3 = $ilDB->fetchAssoc($set3)) {
2443  // ok
2444  } else {
2445  $nid = $ilDB->nextId("style_parameter");
2446  $ilDB->manipulateF(
2447  "INSERT INTO style_parameter " .
2448  " (id, style_id, tag, class, parameter, value, type) VALUES " .
2449  " (%s, %s,%s,%s,%s,%s,%s) ",
2450  array("integer", "integer", "text", "text", "text", "text", "text"),
2451  array($nid, $rec2["style_id"], $rec2["tag"], $rec2["class"],
2452  $rec2["parameter"], $rec2["value"], $types[1])
2453  );
2454  }
2455  }
2456  }
2457  }
2458  }
2459  }
2460 
2464  public function do_3_9_Migration(int $a_id): void
2465  {
2466  $ilDB = $this->db;
2467 
2468  $classes = array("Example", "Additional", "Citation", "Mnemonic", "Remark");
2469  $pars = array("margin-top", "margin-bottom");
2470 
2471  foreach ($classes as $curr_class) {
2472  foreach ($pars as $curr_par) {
2473  $res2 = $ilDB->queryF(
2474  "SELECT id FROM style_parameter WHERE style_id = %s" .
2475  " AND tag = %s AND class= %s AND parameter = %s",
2476  array("integer", "text", "text", "text"),
2477  array($a_id, "p", $curr_class, $curr_par)
2478  );
2479  if ($row2 = $ilDB->fetchAssoc($res2)) {
2480  $ilDB->manipulateF(
2481  "UPDATE style_parameter SET value= %s WHERE id = %s",
2482  array("text", "integer"),
2483  array("10px", $row2["id"])
2484  );
2485  } else {
2486  $nid = $ilDB->nextId("style_parameter");
2487  $ilDB->manipulateF(
2488  "INSERT INTO style_parameter " .
2489  "(id, style_id, tag, class, parameter,value) VALUES (%s,%s,%s,%s,%s,%s)",
2490  array("integer", "integer", "text", "text", "text", "text"),
2491  array($nid, $a_id, "div", $curr_class, $curr_par, "10px")
2492  );
2493  }
2494  }
2495  }
2496 
2497  $ilDB->manipulateF(
2498  "UPDATE style_parameter SET tag = %s WHERE tag = %s and style_id = %s",
2499  array("text", "text", "integer"),
2500  array("div", "p", $a_id)
2501  );
2502  }
2503 
2507 
2511  public function getColors(): array
2512  {
2513  $ilDB = $this->db;
2514 
2515  $set = $ilDB->query("SELECT * FROM style_color WHERE " .
2516  "style_id = " . $ilDB->quote($this->getId(), "integer") . " " .
2517  "ORDER BY color_name");
2518 
2519  $colors = array();
2520  while ($rec = $ilDB->fetchAssoc($set)) {
2521  $colors[] = array(
2522  "name" => $rec["color_name"],
2523  "code" => $rec["color_code"]
2524  );
2525  }
2526 
2527  return $colors;
2528  }
2529 
2533  public function removeColor(string $a_name): void
2534  {
2535  $ilDB = $this->db;
2536 
2537  $ilDB->manipulate("DELETE FROM style_color WHERE " .
2538  " style_id = " . $ilDB->quote($this->getId(), "integer") . " AND " .
2539  " color_name = " . $ilDB->quote($a_name, "text"));
2540  }
2541 
2542  public function getColorCodeForName(string $a_name): string
2543  {
2544  $ilDB = $this->db;
2545  $a_i = "";
2546  $pos = strpos($a_name, "(");
2547  if ($pos > 0) {
2548  $a_i = substr($a_name, $pos + 1);
2549  $a_i = str_replace(")", "", $a_i);
2550  $a_name = substr($a_name, 0, $pos);
2551  }
2552 
2553  $set = $ilDB->query("SELECT color_code FROM style_color WHERE " .
2554  " style_id = " . $ilDB->quote($this->getId(), "integer") . " AND " .
2555  " color_name = " . $ilDB->quote($a_name, "text"));
2556  if ($rec = $ilDB->fetchAssoc($set)) {
2557  if ($a_i == "") {
2558  return "#" . $rec["color_code"];
2559  } else {
2560  return "#" . ilObjStyleSheet::_getColorFlavor(
2561  $rec["color_code"],
2562  (int) $a_i
2563  );
2564  }
2565  }
2566  return "";
2567  }
2568 
2572  public static function _getColorFlavor(
2573  string $a_rgb,
2574  int $a_i
2575  ): string {
2576  $rgb = ilObjStyleSheet::_explodeRGB($a_rgb, true);
2577  $hls = ilObjStyleSheet::_RGBToHLS($rgb);
2578 
2579  if ($a_i > 0) {
2580  $hls["l"] = $hls["l"] + ((255 - $hls["l"]) * ($a_i / 100));
2581  }
2582  if ($a_i < 0) {
2583  $hls["l"] = $hls["l"] - (($hls["l"]) * (-$a_i / 100));
2584  }
2585 
2586  $rgb = ilObjStyleSheet::_HLSToRGB($hls);
2587 
2588  foreach ($rgb as $k => $v) {
2589  $rgb[$k] = str_pad(dechex((int) $v), 2, "0", STR_PAD_LEFT);
2590  }
2591 
2592  return $rgb["r"] . $rgb["g"] . $rgb["b"];
2593  }
2594 
2598  public static function _explodeRGB(
2599  string $a_rgb,
2600  bool $as_dec = false
2601  ): array {
2602  $r["r"] = substr($a_rgb, 0, 2);
2603  $r["g"] = substr($a_rgb, 2, 2);
2604  $r["b"] = substr($a_rgb, 4, 2);
2605  if ($as_dec) {
2606  $r["r"] = self::hexdec($r["r"]);
2607  $r["g"] = self::hexdec($r["g"]);
2608  $r["b"] = self::hexdec($r["b"]);
2609  }
2610 
2611  return $r;
2612  }
2613 
2614  protected static function hexdec(string $hex): int
2615  {
2616  $hex = preg_replace("/[^a-fA-F0-9]+/", "", $hex);
2617  if ($hex === "") {
2618  $hex = "0";
2619  }
2620  return (int) hexdec($hex);
2621  }
2622 
2626  public static function _RGBToHLS(array $a_rgb): array
2627  {
2628  $r = $a_rgb["r"] / 255;
2629  $g = $a_rgb["g"] / 255;
2630  $b = $a_rgb["b"] / 255;
2631  $h = 0;
2632 
2633  // max / min
2634  $max = max($r, $g, $b);
2635  $min = min($r, $g, $b);
2636 
2637  //lightness
2638  $l = ($max + $min) / 2;
2639 
2640  if ($max == $min) {
2641  $s = 0;
2642  } else {
2643  if ($l < 0.5) {
2644  $s = ($max - $min) / ($max + $min);
2645  } else {
2646  $s = ($max - $min) / (2.0 - $max - $min);
2647  }
2648 
2649  if ($r == $max) {
2650  $h = ($g - $b) / ($max - $min);
2651  } elseif ($g == $max) {
2652  $h = 2.0 + ($b - $r) / ($max - $min);
2653  } elseif ($b == $max) {
2654  $h = 4.0 + ($r - $g) / ($max - $min);
2655  }
2656  }
2657 
2658  $hls["h"] = round(($h / 6) * 255);
2659  $hls["l"] = round($l * 255);
2660  $hls["s"] = round($s * 255);
2661 
2662  return $hls;
2663  }
2664 
2668  public static function _HLSToRGB(array $a_hls): array
2669  {
2670  $h = $a_hls["h"] / 255;
2671  $l = $a_hls["l"] / 255;
2672  $s = $a_hls["s"] / 255;
2673  $temp3 = 0;
2674 
2675  $rgb["r"] = $rgb["g"] = $rgb["b"] = 0;
2676 
2677  // If S=0, define R, G, and B all to L
2678  if ($s == 0) {
2679  $rgb["r"] = $rgb["g"] = $rgb["b"] = $l;
2680  } else {
2681  if ($l < 0.5) {
2682  $temp2 = $l * (1.0 + $s);
2683  } else {
2684  $temp2 = $l + $s - $l * $s;
2685  }
2686 
2687  $temp1 = 2.0 * $l - $temp2;
2688 
2689 
2690  # For each of R, G, B, compute another temporary value, temp3, as follows:
2691  foreach ($rgb as $k => $v) {
2692  switch ($k) {
2693  case "r":
2694  $temp3 = $h + 1.0 / 3.0;
2695  break;
2696 
2697  case "g":
2698  $temp3 = $h;
2699  break;
2700 
2701  case "b":
2702  $temp3 = $h - 1.0 / 3.0;
2703  break;
2704  }
2705  if ($temp3 < 0) {
2706  $temp3 = $temp3 + 1.0;
2707  }
2708  if ($temp3 > 1) {
2709  $temp3 = $temp3 - 1.0;
2710  }
2711 
2712  if (6.0 * $temp3 < 1) {
2713  $rgb[$k] = $temp1 + ($temp2 - $temp1) * 6.0 * $temp3;
2714  } elseif (2.0 * $temp3 < 1) {
2715  $rgb[$k] = $temp2;
2716  } elseif (3.0 * $temp3 < 2) {
2717  $rgb[$k] = $temp1 + ($temp2 - $temp1) * ((2.0 / 3.0) - $temp3) * 6.0;
2718  } else {
2719  $rgb[$k] = $temp1;
2720  }
2721  }
2722  }
2723 
2724  $rgb["r"] = round($rgb["r"] * 255);
2725  $rgb["g"] = round($rgb["g"] * 255);
2726  $rgb["b"] = round($rgb["b"] * 255);
2727 
2728  return $rgb;
2729  }
2730 
2731  //
2732  // Media queries
2733  //
2734 
2738 
2739  public function getMediaQueries(): array
2740  {
2741  $ilDB = $this->db;
2742 
2743  $set = $ilDB->query("SELECT * FROM sty_media_query WHERE " .
2744  "style_id = " . $ilDB->quote($this->getId(), "integer") . " " .
2745  "ORDER BY order_nr");
2746 
2747  $mq = array();
2748  while ($rec = $ilDB->fetchAssoc($set)) {
2749  $mq[] = $rec;
2750  }
2751 
2752  return $mq;
2753  }
2754 
2755  public function addMediaQuery(
2756  string $a_mquery,
2757  int $order_nr = 0
2758  ): int {
2759  $ilDB = $this->db;
2760 
2761  $id = $ilDB->nextId("sty_media_query");
2762  if ($order_nr == 0) {
2763  $order_nr = $this->getMaxMQueryOrderNr() + 10;
2764  }
2765 
2766  $ilDB->manipulate("INSERT INTO sty_media_query (id, style_id, mquery, order_nr)" .
2767  " VALUES (" .
2768  $ilDB->quote($id, "integer") . "," .
2769  $ilDB->quote($this->getId(), "integer") . "," .
2770  $ilDB->quote($a_mquery, "text") . "," .
2771  $ilDB->quote($order_nr, "integer") .
2772  ")");
2773 
2774  return $id;
2775  }
2776 
2780  public function getMaxMQueryOrderNr(): int
2781  {
2782  $ilDB = $this->db;
2783 
2784  $set = $ilDB->query(
2785  "SELECT max(order_nr) mnr FROM sty_media_query " .
2786  " WHERE style_id = " . $ilDB->quote($this->getId(), "integer")
2787  );
2788  $rec = $ilDB->fetchAssoc($set);
2789 
2790  return (int) $rec["mnr"];
2791  }
2792 
2793  public function updateMediaQuery(
2794  int $a_id,
2795  string $a_mquery
2796  ): void {
2797  $ilDB = $this->db;
2798 
2799  $ilDB->manipulate(
2800  "UPDATE sty_media_query SET " .
2801  " mquery = " . $ilDB->quote($a_mquery, "text") .
2802  " WHERE id = " . $ilDB->quote($a_id, "integer")
2803  );
2804  }
2805 
2812  public function getMediaQueryForId(
2813  int $a_id
2814  ): array {
2815  $ilDB = $this->db;
2816 
2817  $set = $ilDB->query(
2818  "SELECT * FROM sty_media_query " .
2819  " WHERE id = " . $ilDB->quote($a_id, "integer")
2820  );
2821  return $ilDB->fetchAssoc($set);
2822  }
2823 
2829  public function deleteMediaQuery(
2830  int $a_id
2831  ): void {
2832  $ilDB = $this->db;
2833 
2834  $ilDB->manipulate(
2835  "DELETE FROM sty_media_query WHERE " .
2836  " style_id = " . $ilDB->quote($this->getId(), "integer") .
2837  " AND id = " . $ilDB->quote($a_id, "integer")
2838  );
2839  $this->saveMediaQueryOrder();
2840  }
2841 
2845  public function saveMediaQueryOrder(
2846  ?array $a_order_nr = null
2847  ): void {
2848  $ilDB = $this->db;
2849 
2850  $mqueries = $this->getMediaQueries();
2851  if (is_array($a_order_nr)) {
2852  foreach ($mqueries as $k => $mq) {
2853  $mqueries[$k]["order_nr"] = $a_order_nr[$mq["id"]];
2854  }
2855  $mqueries = ilArrayUtil::sortArray($mqueries, "order_nr", "", true);
2856  }
2857  $cnt = 10;
2858  foreach ($mqueries as $mq) {
2859  $ilDB->manipulate(
2860  "UPDATE sty_media_query SET " .
2861  " order_nr = " . $ilDB->quote($cnt, "integer") .
2862  " WHERE id = " . $ilDB->quote($mq["id"], "integer")
2863  );
2864  $cnt += 10;
2865  }
2866  }
2867 
2868 
2869  //
2870  // Table template management
2871  //
2872 
2876  public function getTemplates(
2877  string $a_type
2878  ): array {
2879  $ilDB = $this->db;
2880 
2881  $set = $ilDB->query("SELECT * FROM style_template WHERE " .
2882  "style_id = " . $ilDB->quote($this->getId(), "integer") . " AND " .
2883  "temp_type = " . $ilDB->quote($a_type, "text") . " " .
2884  "ORDER BY name");
2885 
2886  $templates = array();
2887  while ($rec = $ilDB->fetchAssoc($set)) {
2888  $rec["classes"] = $this->getTemplateClasses((int) $rec["id"]);
2889  $templates[] = $rec;
2890  }
2891 
2892  return $templates;
2893  }
2894 
2898  public function getTemplateClasses(
2899  int $a_tid
2900  ): array {
2901  $ilDB = $this->db;
2902  $set = $ilDB->query("SELECT * FROM style_template_class WHERE " .
2903  "template_id = " . $ilDB->quote($a_tid, "integer"));
2904 
2905  $class = array();
2906  while ($rec = $ilDB->fetchAssoc($set)) {
2907  $key = $rec["class_type"];
2908  $class[$key] = $rec["class"];
2909  }
2910 
2911  return $class;
2912  }
2913 
2914 
2918  public function addTemplate(
2919  string $a_type,
2920  string $a_name,
2921  array $a_classes
2922  ): int {
2923  $ilDB = $this->db;
2924 
2925  $tid = $ilDB->nextId("style_template");
2926  $ilDB->manipulate("INSERT INTO style_template " .
2927  "(id, style_id, name, temp_type)" .
2928  " VALUES (" .
2929  $ilDB->quote($tid, "integer") . "," .
2930  $ilDB->quote($this->getId(), "integer") . "," .
2931  $ilDB->quote($a_name, "text") . "," .
2932  $ilDB->quote($a_type, "text") .
2933  ")");
2934 
2935  foreach ($a_classes as $t => $c) {
2936  $ilDB->manipulate("INSERT INTO style_template_class " .
2937  "(template_id, class_type, class)" .
2938  " VALUES (" .
2939  $ilDB->quote($tid, "integer") . "," .
2940  $ilDB->quote($t, "text") . "," .
2941  $ilDB->quote($c, "text") .
2942  ")");
2943  }
2944 
2945  $this->writeTemplatePreview(
2946  $tid,
2947  ilObjStyleSheetGUI::_getTemplatePreview($this, $a_type, $tid, true)
2948  );
2949 
2950  return $tid;
2951  }
2952 
2956  public function updateTemplate(
2957  int $a_t_id,
2958  string $a_name,
2959  array $a_classes
2960  ): void {
2961  $ilDB = $this->db;
2962 
2963  $ilDB->manipulate("UPDATE style_template SET " .
2964  "name = " . $ilDB->quote($a_name, "text") .
2965  " WHERE id = " . $ilDB->quote($a_t_id, "integer"));
2966 
2967  $ilDB->manipulate(
2968  "DELETE FROM style_template_class WHERE " .
2969  "template_id = " . $ilDB->quote($a_t_id, "integer")
2970  );
2971  foreach ($a_classes as $t => $c) {
2972  $ilDB->manipulate("INSERT INTO style_template_class " .
2973  "(template_id, class_type, class)" .
2974  " VALUES (" .
2975  $ilDB->quote($a_t_id, "integer") . "," .
2976  $ilDB->quote($t, "text") . "," .
2977  $ilDB->quote($c, "text") .
2978  ")");
2979  }
2980  }
2981 
2982  public function addTemplateClass(
2983  int $a_t_id,
2984  string $a_type,
2985  string $a_class
2986  ): void {
2987  $ilDB = $this->db;
2988 
2989  $ilDB->manipulate("INSERT INTO style_template_class " .
2990  "(template_id, class_type, class)" .
2991  " VALUES (" .
2992  $ilDB->quote($a_t_id, "integer") . "," .
2993  $ilDB->quote($a_type, "text") . "," .
2994  $ilDB->quote($a_class, "text") .
2995  ")");
2996  }
2997 
3001  public function templateExists(
3002  string $a_template_name
3003  ): bool {
3004  $ilDB = $this->db;
3005 
3006  $set = $ilDB->query("SELECT * FROM style_template WHERE " .
3007  "style_id = " . $ilDB->quote($this->getId(), "integer") . " AND " .
3008  "name = " . $ilDB->quote($a_template_name, "text"));
3009  if ($ilDB->fetchAssoc($set)) {
3010  return true;
3011  }
3012  return false;
3013  }
3014 
3018  public function getTemplate(int $a_t_id): array
3019  {
3020  $ilDB = $this->db;
3021 
3022  $set = $ilDB->query("SELECT * FROM style_template WHERE " .
3023  "style_id = " . $ilDB->quote($this->getId(), "integer") . " " .
3024  " AND id = " . $ilDB->quote($a_t_id, "integer"));
3025 
3026  if ($rec = $ilDB->fetchAssoc($set)) {
3027  $rec["classes"] = $this->getTemplateClasses((int) $rec["id"]);
3028 
3029  $template = $rec;
3030  return $template;
3031  }
3032  return array();
3033  }
3034 
3038  public function lookupTemplateName(int $a_t_id): string
3039  {
3040  return self::_lookupTemplateName($a_t_id);
3041  }
3042 
3046  public static function _lookupTemplateName(int $a_t_id): ?string
3047  {
3048  global $DIC;
3049 
3050  $ilDB = $DIC->database();
3051 
3052  $set = $ilDB->query("SELECT name FROM style_template WHERE " .
3053  " id = " . $ilDB->quote($a_t_id, "integer"));
3054 
3055  if ($rec = $ilDB->fetchAssoc($set)) {
3056  return $rec["name"];
3057  }
3058 
3059  return null;
3060  }
3061 
3065  public function getTemplateXML(): string
3066  {
3067  $ilDB = $this->db;
3068 
3069  $tag = "<StyleTemplates>";
3070 
3071  $ttypes = array("table", "vaccordion", "haccordion", "carousel");
3072 
3073  foreach ($ttypes as $ttype) {
3074  $ts = $this->getTemplates($ttype);
3075 
3076  foreach ($ts as $t) {
3078  /*$atts = array("table" => "TableClass",
3079  "caption" => "CaptionClass",
3080  "row_head" => "RowHeadClass",
3081  "row_foot" => "RowFootClass",
3082  "col_head" => "ColHeadClass",
3083  "col_foot" => "ColFootClass",
3084  "odd_row" => "OddRowClass",
3085  "even_row" => "EvenRowClass",
3086  "odd_col" => "OddColClass",
3087  "even_col" => "EvenColClass");*/
3088  $c = $t["classes"];
3089 
3090  $tag .= '<StyleTemplate Name="' . $t["name"] . '">';
3091 
3092  foreach ($atts as $type => $t2) {
3093  if (($c[$type] ?? "") != "") {
3094  $tag .= '<StyleClass Type="' . $type . '" Value="' . $c[$type] . '" />';
3095  }
3096  }
3097 
3098  $tag .= "</StyleTemplate>";
3099  }
3100  }
3101 
3102  $tag .= "</StyleTemplates>";
3103 
3104  //echo htmlentities($tag);
3105  return $tag;
3106  }
3107 
3111  public function writeTemplatePreview(
3112  int $a_t_id,
3113  string $a_preview_html
3114  ): void {
3115  $ilDB = $this->db;
3116  $a_preview_html = str_replace(' width=""', "", $a_preview_html);
3117  $a_preview_html = str_replace(' valign="top"', "", $a_preview_html);
3118  $a_preview_html = str_replace('<div class="ilc_text_block_TableContent">', "<div>", $a_preview_html);
3119  //echo "1-".strlen($a_preview_html)."-";
3120  //echo htmlentities($a_preview_html);
3121  if (strlen($a_preview_html) > 4000) {
3122  //echo "2";
3123  $a_preview_html = "";
3124  }
3125  $ilDB->manipulate("UPDATE style_template SET " .
3126  "preview = " . $ilDB->quote($a_preview_html, "text") .
3127  " WHERE id = " . $ilDB->quote($a_t_id, "integer"));
3128  }
3129 
3133  public function lookupTemplatePreview(int $a_t_id): string
3134  {
3135  $ilDB = $this->db;
3136 
3137  $set = $ilDB->query("SELECT preview FROM style_template " .
3138  " WHERE id = " . $ilDB->quote($a_t_id, "integer"));
3139  if ($rec = $ilDB->fetchAssoc($set)) {
3140  return $rec["preview"] ?? "";
3141  }
3142 
3143  return "";
3144  }
3145 
3149  public static function _lookupTemplateIdByName(
3150  int $a_style_id,
3151  string $a_name
3152  ): ?int {
3153  global $DIC;
3154 
3155  $ilDB = $DIC->database();
3156 
3157  $set = $ilDB->query("SELECT id FROM style_template " .
3158  " WHERE style_id = " . $ilDB->quote($a_style_id, "integer") .
3159  " AND name = " . $ilDB->quote($a_name, "text"));
3160  if ($rec = $ilDB->fetchAssoc($set)) {
3161  return (int) $rec["id"];
3162  }
3163 
3164  return null;
3165  }
3166 
3170  public function removeTemplate(int $a_t_id): void
3171  {
3172  $ilDB = $this->db;
3173 
3174  $ilDB->manipulate("DELETE FROM style_template WHERE " .
3175  " style_id = " . $ilDB->quote($this->getId(), "integer") . " AND " .
3176  " id = " . $ilDB->quote($a_t_id, "integer"));
3177 
3178  $ilDB->manipulate(
3179  "DELETE FROM style_template_class WHERE " .
3180  "template_id = " . $ilDB->quote($a_t_id, "integer")
3181  );
3182  }
3183 
3184  public function writeStyleSetting(
3185  string $a_name,
3186  string $a_value
3187  ): void {
3188  $ilDB = $this->db;
3189 
3190  $ilDB->manipulate(
3191  "DELETE FROM style_setting WHERE " .
3192  " style_id = " . $ilDB->quote($this->getId(), "integer") .
3193  " AND name = " . $ilDB->quote($a_name, "text")
3194  );
3195 
3196  $ilDB->manipulate("INSERT INTO style_setting " .
3197  "(style_id, name, value) VALUES (" .
3198  $ilDB->quote($this->getId(), "integer") . "," .
3199  $ilDB->quote($a_name, "text") . "," .
3200  $ilDB->quote($a_value, "text") .
3201  ")");
3202  }
3203 
3207  public function lookupStyleSetting(string $a_name): string
3208  {
3209  $ilDB = $this->db;
3210 
3211  $set = $ilDB->query(
3212  "SELECT value FROM style_setting " .
3213  " WHERE style_id = " . $ilDB->quote($this->getId(), "integer") .
3214  " AND name = " . $ilDB->quote($a_name, "text")
3215  );
3216  $rec = $ilDB->fetchAssoc($set);
3217 
3218  return $rec["value"] ?? '';
3219  }
3220 
3224  public static function writeStyleUsage(
3225  int $a_obj_id,
3226  int $a_style_id
3227  ): void {
3228  global $DIC;
3229 
3230  $ilDB = $DIC->database();
3231 
3232  $ilDB->replace(
3233  "style_usage",
3234  array(
3235  "obj_id" => array("integer", $a_obj_id)),
3236  array(
3237  "style_id" => array("integer", $a_style_id))
3238  );
3239  }
3240 
3244  public static function lookupObjectStyle(
3245  int $a_obj_id
3246  ): int {
3247  global $DIC;
3248 
3249  $ilDB = $DIC->database();
3250 
3251  $set = $ilDB->query(
3252  "SELECT style_id FROM style_usage " .
3253  " WHERE obj_id = " . $ilDB->quote($a_obj_id, "integer")
3254  );
3255  $rec = $ilDB->fetchAssoc($set);
3256  if (!is_array($rec)) {
3257  return 0;
3258  }
3259 
3260  if (ilObject::_lookupType((int) $rec["style_id"]) == "sty") {
3261  return (int) $rec["style_id"];
3262  }
3263 
3264  return 0;
3265  }
3266 
3271  public static function lookupObjectForStyle(
3272  int $a_style_id
3273  ): array {
3274  global $DIC;
3275 
3276  $ilDB = $DIC->database();
3277 
3278  $obj_ids = array();
3279  if (ilObject::_lookupType($a_style_id) == "sty") {
3280  $set = $ilDB->query(
3281  "SELECT DISTINCT obj_id FROM style_usage " .
3282  " WHERE style_id = " . $ilDB->quote($a_style_id, "integer")
3283  );
3284 
3285  while ($rec = $ilDB->fetchAssoc($set)) {
3286  $obj_ids[] = (int) $rec["obj_id"];
3287  }
3288  }
3289  return $obj_ids;
3290  }
3291 }
static getWebspaceDir(string $mode="filesystem")
get webspace directory
templateExists(string $a_template_name)
Check whether template exists.
getXML()
get xml representation of style object todo: add mq_id
$res
Definition: ltiservices.php:66
string $type
static getEffectiveContentStyleId(int $a_style_id)
Get effective Style Id.
static _writeActive(int $a_id, bool $a_active)
updateMediaQuery(int $a_id, string $a_mquery)
static string $basic_style_image_dir
static _explodeRGB(string $a_rgb, bool $as_dec=false)
Explode an RGB string into an array.
static _isExpandable(string $a_type)
do_3_10_Migration()
Migrates 3.10 style to 3.11 style.
static _lookupTemplateIdByName(int $a_style_id, string $a_name)
Lookup table template preview.
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
static _getStandardStyles(bool $a_exclude_default_style=false, bool $a_include_deactivated=false, int $a_scope=0)
Get standard styles.
ILIAS Style Content InternalRepoService $repo
static _addMissingStyleClassesToAllStyles(?array $a_styles=null)
Add missing style classes to all styles todo: add mq_id and custom handling.
characteristicExists(string $a_char, string $a_style_type)
Check whether characteristic exists.
getColors()
Get colors of style.
read()
read style properties
static _getImagesDirectory(int $a_style_id)
static _writeScope(int $a_id, int $a_scope)
static _getStyleParameterNumericUnits(bool $a_no_percentage=false)
getMediaQueryForId(int $a_id)
Get media query for id.
exportXML(string $a_dir)
export style xml file to directory
addParameter(string $a_tag, string $a_par, string $a_type, int $a_mq_id=0, bool $a_custom=false)
write style parameter to db
InternalDomainService $domain
static _getAllReferences(int $id)
get all reference ids for object ID
writeStyleSetting(string $a_name, string $a_value)
static array $pseudo_classes
getTemplateClasses(int $a_tid)
Get template classes.
ilTree $tree
isInTree(?int $a_node_id)
get all information of a node.
static _lookupContObjIdByStyleId(int $a_style_id)
handleXmlString(string $a_str)
static rCopy(string $a_sdir, string $a_tdir, bool $preserveTimeAttributes=false)
Copies content of a directory $a_sdir recursively to a directory $a_tdir.
setCharacteristics(array $a_chars)
static array $expandable_types
lookupTemplateName(int $a_t_id)
Lookup table template name for template ID.
static _getStyleParameterSubPar(string $par)
static _getObjectsDataForType(string $type, bool $omit_trash=false)
get all objects of a certain type
static _getStyleParameters(string $a_tag="")
loadLanguageModule(string $a_module)
Load language module.
static subStr(string $a_str, int $a_start, ?int $a_length=null)
Definition: class.ilStr.php:24
static _getClonableContentStyles()
Get all clonable styles (active standard styles and individual learning module styles with write perm...
static array $style_super_types
static _getTemplatePreview(ilObjStyleSheet $a_style, string $a_type, int $a_t_id, bool $a_small_mode=false)
Get table template preview.
$c
Definition: deliver.php:25
static _RGBToHLS(array $a_rgb)
RGB to HLS (both arrays, 0..255)
static _getPseudoClasses(string $tag)
static _writeStandard(int $a_id, bool $a_std)
Write standard flag.
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
static DOMDocument $basic_style_dom
addTemplateClass(int $a_t_id, string $a_type, string $a_class)
addTemplate(string $a_type, string $a_name, array $a_classes)
Add table template.
removeColor(string $a_name)
Remove a color.
$ilErr
Definition: raiseError.php:33
$path
Definition: ltiservices.php:29
setExportSubDir(string $a_dir)
Set local directory, that will be included within the zip file.
static isCoreStyle(string $a_type, string $a_class)
static _getStyleSuperTypeForType(string $a_type)
static writeOwner($obj_id, $style_id)
lookupStyleSetting(string $a_name)
Lookup style setting.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
deleteStyleParOfChar(string $a_type, string $a_class)
Delete style parameters of characteristic.
static _exists(int $id, bool $reference=false, ?string $type=null)
checks if an object exists in object_data
updateTemplate(int $a_t_id, string $a_name, array $a_classes)
Update table template.
static _lookupTitle(int $obj_id)
static _lookupUpToDate(int $a_id)
ilLanguage $lng
getHideStatus(string $a_type, string $a_char)
Get characteristic hidden status.
getTemplateXML()
Get table template xml.
static _writeUpToDate(int $a_id, bool $a_up_to_date)
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
ilDBInterface $db
static _createImagesDirectory(int $a_style_id)
Create images directory <data_dir>/sty/sty_<id>/images.
getTemplates(string $a_type)
Get table templates of style.
global $DIC
Definition: shib_login.php:22
static _lookupStandard(int $a_id)
Lookup standard flag.
Class ilObjForumAdministration.
do_3_9_Migration(int $a_id)
Migrate old 3.9 styles.
deleteParameter(int $a_id)
delete style parameter
static string $basic_style_file
setStyle(array $a_style)
saveHideStatus(string $a_type, string $a_char, bool $a_hide)
Save characteristic hidden status.
writeTemplatePreview(int $a_t_id, string $a_preview_html)
Write table template preview.
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
saveMediaQueryOrder(?array $a_order_nr=null)
Save media query order.
static _lookupActive(int $a_id)
Lookup active flag.
static getDataDir()
get data directory (outside webspace)
static _deleteStyleAssignments(int $a_style_id)
delete all style references to style
copyImagesToDir(string $a_target)
Copy images to directory.
static getContentStylePath(int $a_style_id, bool $add_random=true, bool $add_token=true)
get content style path static (to avoid full reading)
getStyleParameterGroups()
Get grouped parameter.
static _getColorFlavor(string $a_rgb, int $a_i)
Get color flavor.
static array $hideable_types
getColorCodeForName(string $a_name)
writeCSSFile(string $a_target_file="", string $a_image_dir="")
write css file to webspace directory
static _lookupTemplateName(int $a_t_id)
Lookup table template name for template ID.
getMaxMQueryOrderNr()
Get maximum media query order nr.
getCharacteristics(string $a_type="", bool $a_no_hidden=false, bool $a_include_core=true)
Get characteristics.
getPathId(int $a_endnode_id, int $a_startnode_id=0)
get path from a given startnode to a given endnode if startnode is not given the rootnode is startnod...
static array $num_unit_no_perc
static writeStyleUsage(int $a_obj_id, int $a_style_id)
Write style usage.
static _addMissingStyleClassesToStyle(int $a_id)
Add missing style classes to all styles.
__construct(int $a_id=0, bool $a_call_by_reference=false)
getExportSubDir()
The local directory, that will be included within the zip file.
global $ilSetting
Definition: privfeed.php:31
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
__construct(Container $dic, ilPlugin $plugin)
static _getStyleParameterValues(string $par)
static lookupObjectStyle(int $a_obj_id)
Lookup object style.
determineTemplateStyleClassType(string $t, string $k)
static zip(string $a_dir, string $a_file, bool $compress_content=false)
$q
Definition: shib_logout.php:21
static lookupObjectForStyle(int $a_style_id)
Lookup objects for style.
lookupTemplatePreview(int $a_t_id)
Lookup table template preview.
create(int $a_from_style=0, bool $a_import_mode=false)
Create a new style.
static string $basic_style_zip
static _HLSToRGB(array $a_hls)
HLS to RGB (both arrays, 0..255)
setUpToDate(bool $a_up_to_date=true)
Set style up to date (false + update will trigger css generation next time)
addCharacteristic(string $a_type, string $a_char, bool $a_hidden=false, int $order_nr=0, bool $outdated=false)
static array $filtered_groups
static _isHideable(string $a_type)
static _determineTag(string $a_type)
static _lookupType(int $id, bool $reference=false)
static _getTemplateClassTypes(string $a_template_type="")
Get template class types.
deleteMediaQuery(int $a_id)
Delete media query.
$service
Definition: ltiservices.php:40
deleteCustomStylePars(string $a_tag, string $a_class, string $a_type, int $a_mq_id=0)
Delete style parameter by tag/class/parameter.
removeTemplate(int $a_t_id)
Remove table template.
static hexdec(string $hex)
do_3_10_CharMigration(int $a_id=0)
This is more or less a copy of Services/Migration/DBUpdate_1385/classes ilStyleMigration->addMissingS...
createImagesDirectory()
Create images directory <data_dir>/sty/sty_<id>/images.
getParametersOfClass(string $a_type, string $a_class, int $a_mq_id=0)
static makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
createFromXMLFile(string $a_file, bool $a_skip_parent_create=false)
create style from xml file todo: add mq_id and custom
ilClone()
clone style sheet (note: styles have no ref ids and return an object id)
updateStyleParameter(int $a_id, string $a_value)
update style parameter per id
static _getStyleParameterInputType(string $par)
addMediaQuery(string $a_mquery, int $order_nr=0)
static sortArray(array $array, string $a_array_sortby_key, string $a_array_sortorder="asc", bool $a_numeric=false, bool $a_keep_keys=false)
$r