5 class Html extends \Rsi\Fred\Controller\View{
46 protected function addResource(&$resource,$id,$value,$options = null){
47 if(!$id) $id = count($resource);
48 if($options & self::RESOURCE_PROXY) $this->_noPush[] = $value = $this->
component(
'proxy')->add($value);
49 elseif($options & self::RESOURCE_NO_PUSH) $this->_noPush[] = $value;
50 if($options & self::RESOURCE_ASYNC) $id = $this->asyncPrefix . $id;
51 elseif($options & self::RESOURCE_DEFER) $id = $this->deferPrefix . $id;
52 $resource[$id] = $value;
59 public function addStyleSrc($source,$id = null,$options = null){
60 $this->
addResource($this->_styleSrc,$id,$source,$options);
72 $this->
addResource($this->_scriptSrc,$id,$source,$options);
75 protected function integrity($resource,$hash = null){
76 if($this->_integrityHashes === null){
77 $this->_integrityHashes = [];
78 if($this->_integrityCacheFile){
80 $this->_integrityHashes = include($this->_integrityCacheFile);
86 $this->_integrityHashes[$resource] = $this->integrityAlgo .
'-' . base64_encode($hash);
87 file_put_contents($this->_integrityCacheFile,
'<?php return ' . var_export($this->_integrityHashes,
true) .
';');
91 return $this->_integrityHashes[$resource] ??
false;
94 public function minifyFiles($type,$sources,$target = null,$id = null,$options = null){
95 $target = $this->minifiedPath . $target;
96 $root = \Rsi\Http::docRoot();
97 $resource = substr($target,strlen($root));
98 $func = [$this,
'add' . ucfirst($type) .
'Src'];
99 if(!$this->_fred->debug || !rand(0,$this->debugMinifyProbability))
return call_user_func($func,$resource,$id,$options);
100 $this->
component(
'minify')->handler($type)->files(\
Rsi\Record::prefix($sources,$root),$target);
101 if($this->integrityAlgo) $this->
integrity($resource,hash_file($this->integrityAlgo,$target,
true));
102 foreach($sources as $source) call_user_func($func,$source,null,$options);
105 public function minifyScripts($sources,$target = null,$id = null,$options = null){
106 $this->
minifyFiles(
'script',$sources,$target,$id,$options);
109 public function minifyStyles($sources,$target = null,$id = null,$options = null){
110 $this->
minifyFiles(
'style',$sources,$target,$id,$options);
115 $location = $this->
component(
'location');
116 $head = $this->title ? $html->_title($this->title) : null;
117 foreach($this->_styleSrc as $source){
118 $url = $location->rewrite($source);
119 $push = !in_array($source,$this->_noPush) && \Rsi\Http::pushHeader($url,
'style');
120 $head .= $html->style(null,[
121 'integrity' => $push ?
false : $this->
integrity($url)
124 if($this->_style) $head .= $html->style(implode(
"\n",$this->_style));
125 foreach($this->_scriptSrc as $id => $source){
126 $url = $location->rewrite($source);
127 $push = !in_array($source,$this->_noPush) && \Rsi\Http::pushHeader($url,
'script');
128 $head .= $html->script(null,[
129 'async' => \
Rsi\Str::startsWith($id,$this->asyncPrefix),
130 'defer' => \
Rsi\Str::startsWith($id,$this->deferPrefix),
131 'integrity' => $push ?
false : $this->
integrity($url)
138 $client_config = array_merge($this->_fred->clientConfig(),$extra_config = [
139 'controller' => $this->_controller->clientConfig()
141 $session = new \Rsi\Fred\Component\Session(get_class());
142 $local_config = $session->localConfig ?: [];
143 $session->localConfig = array_merge($local_config,$client_config);
144 if($session->configCheck && ($session->configCheck == \
Rsi\Http::getCookie(
'fred-configCheck'))){
145 foreach($client_config as $name => &$config)
if(
146 ($this->_fred->has($name) || array_key_exists($name,$extra_config)) &&
147 ($config === \
Rsi\Record::get($local_config,$name))
151 $client_config[
'check'] = $session->configCheck = \Rsi\Str::random(8);
152 if($this->mobile) $client_config[
'mobile'] =
true;
153 return ($this->_fred->debug ?
'"use strict";' :
'') .
' 155 document.addEventListener("DOMContentLoaded",function(){' .
156 implode(
"\n",$this->_script) .
' 157 fred = new rsi.Fred(' . $this->
jsonEncode($client_config) .
');' .
158 ($this->_scriptInit ?
' 159 $(document).on("init.fred",function(){ 160 ' . implode(
"\n",$this->_scriptInit) .
' 175 $widget_class_name = get_class($widget);
177 array_key_exists($widget_class_name,$this->widgetClassNames) ||
178 array_key_exists($widget_class_name = \
Rsi\File::basename($widget_class_name),$this->widgetClassNames)
179 ) $class_name = $this->widgetClassNames[$widget_class_name];
181 !class_exists($class_name = $this->defaultWidgetNamespace .
'\\' . $widget_class_name) &&
182 !class_exists($class_name = $this->defaultWidgetNamespace .
'\\' . str_replace($this->_controller->defaultWidgetNamespace .
'\\',
'',\
Rsi\Record::get($widget->clientConfig(),\Rsi\Fred\Controller\Widget::CLASS_NAME)))
184 return new $class_name($id,$this,$widget);
188 if(!array_key_exists($id,$this->_widgets)) $this->_widgets[$id] = $this->
createWidget($id,$this->_controller->widgets[$id]);
189 return $this->_widgets[$id];
193 return array_diff(is_array($ids) ? $ids : array_keys($this->_controller->widgets),$this->renderedWidgetIds);
197 $this->renderedWidgetIds[] = $id;
200 $request = $this->_fred->request;
201 if(array_key_exists($id,$request->data))
202 $value = $request->data[$id];
203 elseif($raw = array_key_exists($id,$request->errors))
204 $value = $request->get($id);
206 $value = $this->_controller->widgets[$id]->defaultValue;
207 return $this->
widget($id)->render($value,$raw);
217 if(!$ids)
return null;
219 $class_name = array_key_exists($type = $this->_fred->client->type ?: null,$this->builderClassNames)
220 ? $this->builderClassNames[$type]
221 : $this->builderClassNames[null];
222 $builder =
new $class_name($this);
224 return $builder->build($ids);
229 $this->
component(
'trans')->
id($this->actionCaptionPrefix . $action,null,$action),
230 [
'type' =>
'submit',
'id' =>
'action' . ucfirst($action),
'name' =>
'action',
'value' => $action,
'class' =>
'action']
236 foreach($this->_controller->actions(
'form') as $action) $content .= $this->
renderFormAction($action);
237 return $this->
component(
'html')->div($content,null,
'fred-actions');
246 return $this->
component(
'html')->form($content,[
'class' => $this->formClass],$this->_controller->route());
250 if($fragment = $this->_controller->fragmentId){
251 if(($str = $this->
component(
'trans')->fragment($fragment)) !==
false) print($str);
252 elseif(method_exists($this,$method =
'fragment' . ucfirst($fragment))) print(call_user_func([$this,$method]));
253 else $this->_fred->externalError(
'Unknown fragment',[
'class' => get_called_class(),
'fragment' => $fragment]);
255 elseif($redir = $this->_fred->request->redir) \Rsi\Http::redirHeader($redir);
256 else require($this->
template ?: $this->defaultTemplatePath . \
Rsi\File::basename(strtolower(get_called_class())) .
'.php');
260 return $this->_fred->client->mobile;
addScriptInit($script, $id=null)
renderFormAction($action)
renderForm($content=null)
Render the form.
const RESOURCE_DEFER
Serve the resource with the deferred attribute.
$asyncPrefix
Resource ID prefix to indicate asynchronous loading.
notRenderedWidgetIds($ids=null)
minifyStyles($sources, $target=null, $id=null, $options=null)
$actionCaptionPrefix
Prefix to prepend to the action name to get a translation ID.
addScript($script, $id=null)
const RESOURCE_PROXY
Serve the resource through the proxy component.
$widgetClassNames
View widget class name (value) per widget class name (key).
addResource(&$resource, $id, $value, $options=null)
createWidget($id, $widget)
Create a view widget.
addStyle($style, $id=null)
minifyScripts($sources, $target=null, $id=null, $options=null)
publish($property, $visibility=self::READABLE)
Publish a property (or hide it again).
integrity($resource, $hash=null)
$deferPrefix
Resource ID prefix to indicate deferred loading.
$builderClassNames
Default builder class name per client type (null =.
const RESOURCE_NO_PUSH
Do not add a push header for the resource.
const RESOURCE_ASYNC
Serve the resource with the asynchronous attribute.
addStyleSrc($source, $id=null, $options=null)
component($name)
Get a component (local or default).
minifyFiles($type, $sources, $target=null, $id=null, $options=null)
addScriptSrc($source, $id=null, $options=null)
$debugMinifyProbability
Chance (1 in x) for using minified file in debug mode.
$integrityAlgo
Hashing algorithm to use for subresource integrity (empty = do not use).
renderWidgets($ids=null, $builder=null)
Render the widgets.