1: <?php
2:
3: /**
4: * This file is part of the Nette Framework (https://nette.org)
5: * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6: */
7:
8: namespace Nette\Application\UI;
9:
10: use Nette;
11:
12:
13: /**
14: * Control is renderable Presenter component.
15: *
16: * @property-read ITemplate|Nette\Bridges\ApplicationLatte\Template|\stdClass $template
17: */
18: abstract class Control extends Component implements IRenderable
19: {
20: /** @var bool */
21: public $snippetMode;
22:
23: /** @var ITemplateFactory */
24: private $templateFactory;
25:
26: /** @var ITemplate */
27: private $template;
28:
29: /** @var array */
30: private $invalidSnippets = [];
31:
32:
33: /********************* template factory ****************d*g**/
34:
35:
36: public function setTemplateFactory(ITemplateFactory $templateFactory)
37: {
38: $this->templateFactory = $templateFactory;
39: }
40:
41:
42: /**
43: * @return ITemplate
44: */
45: public function getTemplate()
46: {
47: if ($this->template === null) {
48: $value = $this->createTemplate();
49: if (!$value instanceof ITemplate && $value !== null) {
50: $class2 = get_class($value);
51: $class = get_class($this);
52: throw new Nette\UnexpectedValueException("Object returned by $class::createTemplate() must be instance of Nette\\Application\\UI\\ITemplate, '$class2' given.");
53: }
54: $this->template = $value;
55: }
56: return $this->template;
57: }
58:
59:
60: /**
61: * @return ITemplate
62: */
63: protected function createTemplate()
64: {
65: $templateFactory = $this->templateFactory ?: $this->getPresenter()->getTemplateFactory();
66: return $templateFactory->createTemplate($this);
67: }
68:
69:
70: /**
71: * Descendant can override this method to customize template compile-time filters.
72: * @param ITemplate
73: * @return void
74: */
75: public function templatePrepareFilters($template)
76: {
77: }
78:
79:
80: /**
81: * Saves the message to template, that can be displayed after redirect.
82: * @param string
83: * @param string
84: * @return \stdClass
85: */
86: public function flashMessage($message, $type = 'info')
87: {
88: $id = $this->getParameterId('flash');
89: $messages = $this->getPresenter()->getFlashSession()->$id;
90: $messages[] = $flash = (object) [
91: 'message' => $message,
92: 'type' => $type,
93: ];
94: $this->getTemplate()->flashes = $messages;
95: $this->getPresenter()->getFlashSession()->$id = $messages;
96: return $flash;
97: }
98:
99:
100: /********************* rendering ****************d*g**/
101:
102:
103: /**
104: * Forces control or its snippet to repaint.
105: * @return void
106: */
107: public function redrawControl($snippet = null, $redraw = true)
108: {
109: if ($redraw) {
110: $this->invalidSnippets[$snippet === null ? "\0" : $snippet] = true;
111:
112: } elseif ($snippet === null) {
113: $this->invalidSnippets = [];
114:
115: } else {
116: $this->invalidSnippets[$snippet] = false;
117: }
118: }
119:
120:
121: /** @deprecated */
122: public function invalidateControl($snippet = null)
123: {
124: trigger_error(__METHOD__ . '() is deprecated; use $this->redrawControl($snippet) instead.', E_USER_DEPRECATED);
125: $this->redrawControl($snippet);
126: }
127:
128:
129: /** @deprecated */
130: public function validateControl($snippet = null)
131: {
132: trigger_error(__METHOD__ . '() is deprecated; use $this->redrawControl($snippet, false) instead.', E_USER_DEPRECATED);
133: $this->redrawControl($snippet, false);
134: }
135:
136:
137: /**
138: * Is required to repaint the control or its snippet?
139: * @param string snippet name
140: * @return bool
141: */
142: public function isControlInvalid($snippet = null)
143: {
144: if ($snippet === null) {
145: if (count($this->invalidSnippets) > 0) {
146: return true;
147:
148: } else {
149: $queue = [$this];
150: do {
151: foreach (array_shift($queue)->getComponents() as $component) {
152: if ($component instanceof IRenderable) {
153: if ($component->isControlInvalid()) {
154: // $this->invalidSnippets['__child'] = true; // as cache
155: return true;
156: }
157:
158: } elseif ($component instanceof Nette\ComponentModel\IContainer) {
159: $queue[] = $component;
160: }
161: }
162: } while ($queue);
163:
164: return false;
165: }
166:
167: } elseif (isset($this->invalidSnippets[$snippet])) {
168: return $this->invalidSnippets[$snippet];
169: } else {
170: return isset($this->invalidSnippets["\0"]);
171: }
172: }
173:
174:
175: /**
176: * Returns snippet HTML ID.
177: * @param string snippet name
178: * @return string
179: */
180: public function getSnippetId($name = null)
181: {
182: // HTML 4 ID & NAME: [A-Za-z][A-Za-z0-9:_.-]*
183: return 'snippet-' . $this->getUniqueId() . '-' . $name;
184: }
185: }
186: