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