PluginProbe
Depicter — Popup & Slider Builder / 1.5.2
Depicter — Popup & Slider Builder v1.5.2
4.8.1 trunk 1.0.0 1.1.0 1.1.2 1.1.4 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.3.0 1.3.1 1.3.2 1.3.3 1.3.5 1.3.8 1.5.0 1.5.1 1.5.2 1.5.5 1.6.0 1.6.1 1.6.2 1.7.0 All 76 releases
depicter / app / src / Document / Models / Document.php

Document.php in Depicter — Popup & Slider Builder 1.5.2, at app/src/Document/Models/Document.php

675 lines 15.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Depicter\Document\Models;
3
4
5 use Averta\Core\Hydrate\HydratableInterface;
6 use Averta\Core\Utility\Arr;
7 use Averta\WordPress\Utility\Sanitize;
8 use Depicter\Document\CSS\Selector;
9 use Depicter\Document\Models\Options\Loading;
10 use Depicter\Document\Models\Options\Script;
11 use Depicter\Document\Models\Traits\UnPublishedNoticeTrait;
12 use Depicter\Html\Html;
13 use Depicter\Services\StyleGeneratorService;
14
15 class Document implements HydratableInterface
16 {
17 use UnPublishedNoticeTrait;
18
19
20 /**
21 * @var array
22 */
23 public $sectionsList;
24
25 /**
26 * @var Section[]
27 */
28 public $sections;
29
30 /**
31 * @var Element[]
32 */
33 public $elements;
34
35 /**
36 * @var array
37 */
38 public $foregroundElements;
39
40 /**
41 * @var array
42 */
43 public $foregroundElementObjects = [];
44
45 /**
46 * @var Options\All
47 */
48 public $options;
49
50 /**
51 * @var array
52 */
53 public $meta;
54
55 /**
56 * Start from which section
57 *
58 * @var int
59 */
60 public $startSection = 0;
61
62 /**
63 * Document markup
64 *
65 * @var string
66 */
67 protected $html;
68
69 /**
70 * Style generator class instance
71 *
72 * @var StyleGeneratorService
73 */
74 protected $styleGenerator;
75
76 /**
77 * Collected styles in a list
78 *
79 * @var array
80 */
81 protected $stylesList = [];
82
83 /**
84 * Collected fonts from belonging elements
85 *
86 * @var array
87 */
88 private $fontsList = [];
89
90 /**
91 * Link to download all used fonts in this document
92 *
93 * @var string|null
94 */
95 private $fontLink;
96
97 /**
98 * Extra document args
99 *
100 * @var array
101 */
102 private $args = [];
103
104 /**
105 * Extract values for this class
106 *
107 * @return array
108 */
109 public function getProperties()
110 {
111 return [
112 'name' => $this->getName(),
113 'slug' => $this->getSlug(),
114 'sections_count' => $this->getSectionsCount(),
115 'content' => $this->get(),
116 'status' => 'published'
117 ];
118 }
119
120 /**
121 * Extract values for this class
122 *
123 * @return array
124 */
125 public function extract()
126 {
127 // TODO: Implement extract() method.
128 }
129
130 /**
131 * Hydrate the class with the provided $data.
132 *
133 * @param array|object $data
134 */
135 public function hydrate($data)
136 {
137 // TODO: Implement hydrate() method.
138 }
139
140 /**
141 * Prepare document for generating markup
142 *
143 * @return $this
144 */
145 public function prepare()
146 {
147 $this->reorderSections();
148 $this->setElementsForObjects();
149 $this->setForegroundElementObjects();
150
151 return $this;
152 }
153
154 public function render()
155 {
156 $this->html = Html::div([
157 'id' => $this->getCssId(),
158 'class' => $this->getClassNames()
159 ]);
160
161 $this->renderNotice();
162 $this->renderLoadingSymbol();
163 $this->renderForegroundElements();
164 $this->renderSectionsAndElements();
165 $this->collectAndSetFontsData();
166 $this->getSelectorAndCssList();
167 $this->renderSymbols();
168
169 return $this->html . $this->getInitScriptTag();
170 }
171
172 /**
173 * Render markup for possible notices
174 *
175 * @return void
176 */
177 protected function renderNotice(){
178 $notice = $this->getUnpublishedChangesNotice();
179 $this->html->nest( "\n" . $notice );
180 }
181
182 /**
183 * Render markup for loading symbols
184 */
185 protected function renderLoadingSymbol() {
186 if ( empty( $this->options->loading ) ) {
187 $this->options->loading = new Loading();
188 }
189 $this->html->nest( "\n" . $this->options->loading->render() );
190 }
191
192 /**
193 * Render symbols markup
194 */
195 protected function renderSymbols() {
196 $symbolsContent = \Depicter::symbolsProvider()->render();
197 if ( !empty( $symbolsContent ) ) {
198 $this->html->nest( "\n" . $symbolsContent );
199 }
200 }
201
202 /**
203 * Render markup and collect styles of foreground elements.
204 */
205 protected function renderForegroundElements(){
206
207 $foregroundAttributes = [ 'class' => Selector::prefixify('overlay-layers') ];
208 $elementsMarkup = "";
209
210 foreach ( $this->foregroundElementObjects as $element ) {
211 $this->stylesList = array_merge( $this->stylesList, $element->prepare()->getSelectorAndCssList() );
212 $elementsMarkup .= $element->prepare()->render() . "\n";
213 }
214
215 if( $elementsMarkup ){
216 $foregroundDiv = Html::div( $foregroundAttributes, "\n" . $elementsMarkup );
217 $this->html->nest( "\n\n" . $foregroundDiv . "\n" );
218 }
219 }
220
221 /**
222 * Get the font link for loading document fonts
223 *
224 * @return string|null
225 */
226 public function getFontsLink()
227 {
228 if( is_null( $this->fontLink ) ){
229 $this->collectAndSetFontsData();
230 }
231 return $this->fontLink;
232 }
233
234 /**
235 * Render markup and collect styles of sections and nested elements.
236 */
237 protected function renderSectionsAndElements(){
238 foreach ( $this->sections as $section ) {
239 $this->html->nest( $section->render() . "\n" );
240 $this->stylesList = array_merge( $this->stylesList, $section->getCss() );
241 }
242 }
243
244 /**
245 * Collects fonts and generates a link for loading document fonts
246 */
247 protected function collectAndSetFontsData()
248 {
249 foreach ( $this->sections as $section ) {
250 // this method adds element fonts to documentFonts service
251 $section->collectElementFonts();
252 }
253 $this->fontLink = \Depicter::app()->documentFonts()->getFontsLink( $this->getDocumentID() );
254 }
255
256 /**
257 * Render document custom styles
258 */
259 /**
260 * Get list of selector and CSS for section
261 *
262 * @return array
263 */
264 protected function getSelectorAndCssList(){
265 if( ! isset( $this->stylesList[ '.'. $this->getSelector() ] ) ){
266 $this->stylesList[ '.'. $this->getSelector() ] = [];
267 }
268
269 $documentStyles = [
270 '.'. $this->getStyleSelector() . ' .depicter-section' => $this->options->getSectionGeneralStyles(),
271 '.'. $this->getStyleSelector() . ' .depicter-layers-wrapper' => $this->options->getLayersWrapperStyles()
272 ];
273 // prepend document styles at the beginning of the styles
274 $this->stylesList = $documentStyles + $this->stylesList;
275
276 $this->stylesList[ '.'. $this->getStyleSelector() ]['customStyle'] = $this->getCustomStyles();
277
278 // add before init styles separately to style list as well
279 $this->stylesList[ '.'. $this->getStyleSelector() ]['beforeInitStyle'] = [
280 '.'. $this->getStyleSelector() => $this->options->getStyles(),
281 '.'. $this->getStyleSelector( true ) . ':not(.depicter-ready)' => $this->options->getBeforeInitStyles(), // styles to prevent FOUC. It should not have depicter-revert class in selector
282 ];
283
284 return $this->stylesList;
285 }
286
287 /**
288 * Retrieves StyleGeneratorService
289 *
290 * @param bool $args
291 *
292 * @return StyleGeneratorService
293 */
294 public function styleGenerator( $args = [] ){
295 $args = Arr::merge( $args, [
296 'forceRegenerateStyles' => false
297 ]);
298
299 if( ! $this->styleGenerator ){
300 $this->styleGenerator = new StyleGeneratorService( $this->stylesList, $this->getDocumentID(), $args );
301 }
302 if( $args['forceRegenerateStyles'] ){
303 $this->styleGenerator->setStylesList( $this->stylesList );
304 }
305
306 return $this->styleGenerator;
307 }
308
309 /**
310 * Saves generated css in file
311 *
312 * @param bool $forceRegenerateStyles Whether regenerate styles or not
313 */
314 public function saveCss( $forceRegenerateStyles = false ){
315 $this->styleGenerator( ['forceRegenerateStyles' => $forceRegenerateStyles] )->saveCss( $forceRegenerateStyles = false );
316 }
317
318 /**
319 * Retrieves generated css
320 *
321 * @param bool $forceRegenerateStyles Whether regenerate styles or not
322 *
323 * @return string css styles
324 */
325 public function getCss( $forceRegenerateStyles = false ){
326 return $this->styleGenerator( ['forceRegenerateStyles' => $forceRegenerateStyles] )->getCss( $forceRegenerateStyles = false );
327 }
328
329 /**
330 * Retrieves before init CSS
331 *
332 * @param bool $forceRegenerateStyles Whether regenerate before init styles or not
333 *
334 * @return string css styles
335 */
336 public function getBeforeInitCssAndTag( $forceRegenerateStyles = false ){
337 return $this->styleGenerator( ['forceRegenerateStyles' => $forceRegenerateStyles] )->getBeforeInitCssAndTag( $forceRegenerateStyles = false );
338 }
339
340 /**
341 * Retrieves generated css wrapper in a style tag
342 *
343 * @param bool $forceRegenerateStyles Whether regenerate styles or not
344 *
345 * @return string css styles and style tag
346 */
347 public function getInlineCssTag( $forceRegenerateStyles = false ){
348 return $this->styleGenerator( ['forceRegenerateStyles' => $forceRegenerateStyles] )->getCssAndTag( $forceRegenerateStyles = false );
349 }
350
351 /**
352 * Retrieves custom css file of a document if exists
353 *
354 * @param bool $forceRegenerateStyles Whether regenerate styles or not
355 *
356 * @return bool|string
357 */
358 public function getCssFileUrl( $forceRegenerateStyles = false ){
359 if( $forceRegenerateStyles ){
360 $this->saveCss( $forceRegenerateStyles );
361 }
362 if( $cssFile = $this->styleGenerator()->getCssFileUrl() ){
363 return $cssFile;
364 }
365
366 return false;
367 }
368
369 /**
370 * Generates all CSS classes of document wrapper tag
371 *
372 * @return string
373 */
374 protected function getClassNames() {
375 $classes = [ Selector::PREFIX_NAME, Selector::prefixify( Selector::DOCUMENT_PREFIX ), Selector::prefixify( 'revert' ) ];
376 $classes[] = $this->getSelector();
377
378 if ( $this->options->sectionLayout == 'fullscreen' ) {
379 $classes[] = 'depicter-layout-fullscreen';
380 }
381
382 if ( $this->options->sectionLayout == 'fullwidth' ) {
383 $classes[] = 'depicter-layout-fullwidth';
384 }
385
386 if ( $this->getCustomClassName() ) {
387 $classes[] = $this->getCustomClassName();
388 }
389
390 if ( isset( $this->options->general->visible->default ) && $this->options->general->visible->default === false ) {
391 $classes[] = 'depicter-hide-on-desktop';
392 }
393
394 if ( isset( $this->options->general->visible->tablet ) && $this->options->general->visible->tablet === false ) {
395 $classes[] = 'depicter-hide-on-tablet';
396 }
397
398 if ( isset( $this->options->general->visible->mobile ) && $this->options->general->visible->mobile === false ) {
399 $classes[] = 'depicter-hide-on-mobile';
400 }
401
402 return implode( ' ', $classes );
403 }
404
405 protected function getCssId(){
406 return Selector::getFullSelectorPath( $this->getDocumentID() );
407 }
408
409 /**
410 * Retrieves custom class name of document
411 *
412 * @return string
413 */
414 protected function getCustomClassName(){
415 if ( ! empty( $this->options->advanced->className ) ) {
416 return $this->options->advanced->className;
417 }
418 return '';
419 }
420
421 /**
422 * Retrieves custom styles of document
423 *
424 * @return string
425 */
426 protected function getCustomStyles(){
427 if ( ! empty( $this->options->advanced->customStyle ) ) {
428 $customStyles = $this->options->advanced->customStyle;
429 // replace "selector" with unique selector of document
430 return str_replace('selector', '.'.$this->getStyleSelector(), $customStyles );
431 }
432 return '';
433 }
434
435 /**
436 * Retrieves list of all generated custom css files
437 *
438 * @param array|string $fileKeysToInclude Array of file keys or 'all', '*' to retrieve all
439 *
440 * @return array
441 */
442 public function getCustomCssFiles( $fileKeysToInclude = 'all' )
443 {
444 $documentCustomStyles = [];
445
446 if( is_string( $fileKeysToInclude ) && in_array( $fileKeysToInclude, [ 'all', '*'] ) ){
447 $fileKeysToInclude = ['google-font', 'custom'];
448 }
449
450 if( in_array('google-font', $fileKeysToInclude) && $fontLink = $this->getFontsLink() ){
451 $documentCustomStyles[ "depicter-{$this->getDocumentID()}-google-font" ] = $fontLink;
452 }
453 if( in_array('custom', $fileKeysToInclude) && $customCssFileUrl = $this->getCssFileUrl() ){
454 $documentCustomStyles[ "depicter--{$this->getDocumentID()}-custom" ] = $customCssFileUrl;
455 }
456
457 return $documentCustomStyles;
458 }
459
460 /**
461 * Retrieves unique selector of document
462 *
463 * @return string
464 */
465 public function getSelector(){
466 return Selector::getUniqueSelector( $this->getDocumentID() );
467 }
468
469 /**
470 * Get style selector
471 *
472 * @param bool $excludePrefix Whether to exclude selector prefix or not
473 *
474 * @return string
475 */
476 public function getStyleSelector( $excludePrefix = false ) {
477 return ( $excludePrefix ? '' : Selector::PREFIX_CSS . "." ) . $this->getSelector();
478 }
479
480 /**
481 * Order sections based on sectionsList
482 */
483 protected function reorderSections(){
484 $ordered_sections = [];
485 foreach ( $this->sectionsList as $section_id ) {
486 if( isset( $this->sections[ $section_id ] ) ){
487 $ordered_sections[ $section_id ] = $this->sections[ $section_id ];
488 }
489 }
490 $this->sections = $ordered_sections;
491 }
492
493 /**
494 * Assigns belonging elements of all section
495 * Here Objects can be element or section
496 */
497 protected function setElementsForObjects(){
498 foreach ( $this->sections as $section ){
499 // Assign document ID to all sections
500 $section->setDocumentID( $this->getDocumentID() );
501 $this->setElementsForOneObjects( $section );
502 }
503
504 foreach ( $this->elements as $element ){
505 // Assign document ID to all elements
506 $element->setDocumentID( $this->getDocumentID() );
507 $this->setElementsForOneObjects( $element );
508 }
509 }
510
511 /**
512 * Assigns belonging elements of a section
513 *
514 * @param $object
515 */
516 protected function setElementsForOneObjects( &$object ){
517 if ( $elementIds = $object->getElementIds() ) {
518 $elements = $this->sortElementsByDepth( $elementIds );
519 $object->setElementObjects( $elements );
520 }
521 }
522
523 /**
524 * Assigns belonging elements of a section
525 */
526 protected function setForegroundElementObjects(){
527 if ( $elementIds = $this->foregroundElements ) {
528 $this->foregroundElementObjects = $this->sortElementsByDepth( $elementIds );
529 }
530 }
531
532 /**
533 * Sorts elements by depth
534 *
535 * @param array $elementIds
536 *
537 * @return array|Element[]
538 */
539 protected function sortElementsByDepth( $elementIds ){
540 if( empty( $elementIds ) ){
541 return [];
542 }
543
544 $elementsByDepth = [];
545 $elements = [];
546
547 // sort this group of elements in depth
548 foreach ( $elementIds as $elementId ) {
549 $element = $this->elements[ $elementId ];
550 $elementsByDepth[ $element->depth ][] = $element;
551 }
552
553 // sort by ascending depth
554 ksort( $elementsByDepth );
555
556 // collect these elements by depth
557 foreach ( $elementsByDepth as $elementsInADepth ){
558 foreach ( $elementsInADepth as $element ){
559 $elements[] = $element;
560 }
561 }
562
563 return $elements;
564 }
565
566 /**
567 * @return array
568 */
569 public function getMeta()
570 {
571 return $this->meta ?? [];
572 }
573
574 /**
575 * @return Options
576 */
577 public function getOptions()
578 {
579 return $this->options ?? [];
580 }
581
582 /**
583 * Get teh name of document
584 *
585 * @return string
586 */
587 public function getName()
588 {
589 return isset( $this->meta['name'] ) ? $this->meta['name'] : '';
590 }
591
592 /**
593 * Get document slug
594 *
595 * @return mixed|string
596 */
597 public function getSlug()
598 {
599 return isset( $this->meta['slug'] ) ? $this->meta['slug'] : '';
600 }
601
602 /**
603 * Get sections count
604 *
605 * @return int|void
606 */
607 public function getSectionsCount()
608 {
609 return is_array( $this->sectionsList ) ? count( $this->sectionsList ) : 0;
610 }
611
612 /**
613 * Gel list of section objects
614 *
615 * @return Section[]
616 */
617 public function getSections()
618 {
619 return $this->sections ?? [];
620 }
621
622 /**
623 * Get a section object by section ID
624 *
625 * @param string $sectionId The section ID
626 *
627 * @return Section|null
628 */
629 public function getSectionById( $sectionId )
630 {
631 return $this->sections[ $sectionId ] ?? null;
632 }
633
634 /**
635 * Get a section by section number. starts from 1
636 *
637 * @param int $sectionNumber The section number
638 *
639 * @return Section|null
640 */
641 public function getSectionNth( $sectionNumber )
642 {
643 if( ! $this->getSections() ){
644 return null;
645 }
646
647 $sectionIndex = $sectionNumber > 0 ? $sectionNumber - 1 : 1;
648 return array_values( $this->getSections() )[ $sectionIndex ] ?? null;
649 }
650
651 /**
652 * Get init script
653 *
654 * @return string
655 */
656 public function getInitScript() {
657 return (new Script())->getDocumentInitScript( $this );
658 }
659
660 /**
661 * Get init script tag
662 */
663 public function getInitScriptTag() {
664 return "\n" . Html::script( [], $this->getInitScript() );
665 }
666
667 /**
668 * Print init script tag
669 */
670 public function printInitScriptTag() {
671 echo Sanitize::html( $this->getInitScriptTag() );
672 }
673
674 }
675