new pisilinux web sites
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\IS;
|
||||
use ZN\Request;
|
||||
use ZN\Buffering;
|
||||
|
||||
class AjaxBuilder extends BuilderExtends
|
||||
{
|
||||
/**
|
||||
* Protected keeps queue builder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $queueBuilder = NULL;
|
||||
|
||||
/**
|
||||
* Protected keeps ajax functions
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $functions =
|
||||
[
|
||||
'beforeSend',
|
||||
'complete',
|
||||
'dataFilter',
|
||||
'error',
|
||||
'success',
|
||||
'xhr'
|
||||
];
|
||||
|
||||
/**
|
||||
* Protected keeps ajax queue method
|
||||
*/
|
||||
protected $queues =
|
||||
[
|
||||
'done',
|
||||
'then',
|
||||
'fail',
|
||||
'always'
|
||||
];
|
||||
|
||||
/**
|
||||
* Magic call
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameter
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function __call($method, $parameter)
|
||||
{
|
||||
$value = $parameter[0] ?? '';
|
||||
|
||||
if( $method === 'url' )
|
||||
{
|
||||
$value = $this->getSiteURL($value);
|
||||
}
|
||||
|
||||
if( in_array($method, $this->queues) )
|
||||
{
|
||||
$this->queueBuilder .= $this->queue($method, $value, $parameter[1] ?? 'data');
|
||||
}
|
||||
else
|
||||
{
|
||||
if( in_array($method, $this->functions) )
|
||||
{
|
||||
$option = $this->isCallableOption($value, $parameter[1] ?? 'data');
|
||||
}
|
||||
else
|
||||
{
|
||||
if( $method === 'data' && is_callable($value) )
|
||||
{
|
||||
$option = Buffering\Callback::do($value);
|
||||
}
|
||||
else
|
||||
{
|
||||
$option = json_encode($value);
|
||||
}
|
||||
}
|
||||
|
||||
$this->builder .= HT . $method . ':' . $option . ',' . PHP_EOL;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected build
|
||||
*/
|
||||
protected function build(string $content)
|
||||
{
|
||||
$string = '$.ajax({' . PHP_EOL;
|
||||
$string .= rtrim($content, ',' . PHP_EOL) . PHP_EOL;
|
||||
$string .= '})'.$this->queueBuilder.';' . PHP_EOL;
|
||||
|
||||
$this->builder = NULL;
|
||||
$this->queueBuilder = NULL;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected queue
|
||||
*/
|
||||
protected function queue($type, $callback, $parameter)
|
||||
{
|
||||
$string = PHP_EOL . '.' . $type . '(function(' . $parameter . '){' . PHP_EOL;
|
||||
$string .= HT . Buffering\Callback::do($callback);
|
||||
$string .= '})' . PHP_EOL;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get site url
|
||||
*/
|
||||
protected function getSiteURL($value)
|
||||
{
|
||||
if( ! IS::url($value) )
|
||||
{
|
||||
$value = Request::getSiteURL($value);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Base;
|
||||
|
||||
trait BootstrapAttributes
|
||||
{
|
||||
/**
|
||||
* Protected use property options
|
||||
*/
|
||||
protected function usePropertyOptions($selector, $content, $type)
|
||||
{
|
||||
$this->isBootstrapAttribute('on', function($return) use($type)
|
||||
{
|
||||
$this->settings['attr']['on'] = Base::suffix($return, '.bs.' . $type);
|
||||
});
|
||||
|
||||
return $this->bootstrapObjectOptions($selector === 'all' ? '[data-toggle="'.$type.'"]' : $selector, $content ?? [], $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected use property scripts
|
||||
*/
|
||||
protected function usePropertyScripts($selector, $content, $type)
|
||||
{
|
||||
$this->isBootstrapAttribute('on', function($return) use($type)
|
||||
{
|
||||
$this->settings['attr']['on'] = Base::suffix($return, '.bs.' . $type);
|
||||
});
|
||||
|
||||
return $this->bootstrapObjectOptions((ctype_alpha($selector[0]) ? '#' : '') . $selector, $this->stringOrCallback($content), $type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,906 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Base;
|
||||
use ZN\Config;
|
||||
use ZN\Datatype;
|
||||
use ZN\Buffering;
|
||||
use ZN\Request\URI;
|
||||
|
||||
trait BootstrapComponents
|
||||
{
|
||||
/**
|
||||
* Keeps callable group
|
||||
*/
|
||||
protected $callableGroup;
|
||||
|
||||
/**
|
||||
* Use of bootstrap group
|
||||
*
|
||||
* @param string|callable $code = ''
|
||||
* @param string $class = ''
|
||||
*
|
||||
* @return string|this
|
||||
*/
|
||||
public function group($code = '', string $class = '')
|
||||
{
|
||||
if( is_string($code) )
|
||||
{
|
||||
$this->settings['group']['class'] = $this->bootstrapClassResolution('form-group', $code);
|
||||
}
|
||||
else if( is_callable($code) )
|
||||
{
|
||||
$this->callableGroup = true;
|
||||
|
||||
$result = $this->getHTMLClass()
|
||||
->class('form-group row' . Base::prefix($class, ' '))
|
||||
->div(EOL . Buffering\Callback::do($code));
|
||||
|
||||
$this->callableGroup = NULL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use of bootstrap label
|
||||
*
|
||||
* @param string $for = NULL
|
||||
* @param string $value = NULL
|
||||
* @param string $class = NULL
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function label(?string $for = NULL, ?string $value = NULL, ?string $class = NULL)
|
||||
{
|
||||
$this->settings['label']['for' ] = $for;
|
||||
$this->settings['label']['value'] = $value;
|
||||
$this->settings['label']['class'] = $class;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap col size
|
||||
*
|
||||
* @param string $size
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function col(string $size)
|
||||
{
|
||||
$this->settings['col']['size'] = $size;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected getHTMLClass
|
||||
*/
|
||||
protected function getHTMLClass()
|
||||
{
|
||||
return new Html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Help text
|
||||
*
|
||||
* @param string $content
|
||||
* @param string $class = NULL
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function helptext(string $content, string $class = '')
|
||||
{
|
||||
$this->settings['help']['text'] = $this->getHTMLClass()
|
||||
->class('help-block' . Base::prefix($class, ' '))
|
||||
->span($content);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Help text
|
||||
*
|
||||
* @param string $content
|
||||
* @param string $class = NULL
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function helptext4(string $content, string $class = '')
|
||||
{
|
||||
$this->settings['help']['text'] = $this->getHTMLClass()
|
||||
->class('form-text text-muted' . Base::prefix($class, ' '))
|
||||
->span($content);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open modal
|
||||
*
|
||||
* @param string $selector
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function modal(string $selector)
|
||||
{
|
||||
$this->settings['attr']['data-toggle'] = 'modal';
|
||||
$this->settings['attr']['data-target'] = Base::prefix($selector, '#');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate modal box
|
||||
*
|
||||
* @param string $id
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function modalbox(string $id, array $data = [], $template = 'standart')
|
||||
{
|
||||
$attr = $this->settings['attr'] ?? [];
|
||||
|
||||
$this->settings['attr'] = [];
|
||||
|
||||
$data =
|
||||
[
|
||||
'modalId' => $id,
|
||||
'modalHeader' => $this->stringOrCallback($attr['modal-header'] ?? ''),
|
||||
'modalBody' => $this->stringOrCallback($attr['modal-body'] ?? ''),
|
||||
'modalFooter' => $this->stringOrCallback($attr['modal-footer'] ?? ''),
|
||||
'modalSize' => $attr['modal-size'] ?? '',
|
||||
'modalDismissButton' => $attr['modal-dismiss-button'] ?? ''
|
||||
];
|
||||
|
||||
return $this->getModalResource($template, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate modal box bootstrap 4
|
||||
*
|
||||
* @param string $id
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function modalbox4(string $id, array $data = [])
|
||||
{
|
||||
return $this->modalbox($id, $data, 'standart4');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate toast bootstrap 4
|
||||
*
|
||||
* @param string $id
|
||||
* @param array $data
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toast(string $id, array $data = [], $template = 'standart')
|
||||
{
|
||||
$attr = $this->settings['attr'] ?? [];
|
||||
|
||||
$this->settings['attr'] = [];
|
||||
|
||||
$data =
|
||||
[
|
||||
'toastId' => $id,
|
||||
'toastHeader' => $this->stringOrCallback($attr['toast-header'] ?? ''),
|
||||
'toastBody' => $this->stringOrCallback($attr['toast-body'] ?? ''),
|
||||
'toastDismissButton' => $attr['toast-dismiss-button'] ?? '',
|
||||
'toastAutoHide' => $attr['toast-auto-hide'] ?? 'true'
|
||||
];
|
||||
|
||||
return $this->getToastResource($template, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toast event
|
||||
*
|
||||
* @param string $selector
|
||||
* @param string|callback $content = ''
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function toastEvent(string $selector, $content = '')
|
||||
{
|
||||
return $this->usePropertyScripts($selector, $content, 'toast');
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap opover attribute
|
||||
*
|
||||
* @param string $placement
|
||||
* @param string $content
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function popover(string $placement, $content = NULL)
|
||||
{
|
||||
if( is_string($content) )
|
||||
{
|
||||
return $this->dataContainer('body')->dataToggle('popover')->dataPlacement($placement)->dataContent($content);
|
||||
}
|
||||
|
||||
return $this->usePropertyOptions($placement, $content, __FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Popover event
|
||||
*
|
||||
* @param string $selector
|
||||
* @param string|callback $content = ''
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function popoverEvent(string $selector, $content = NULL)
|
||||
{
|
||||
return $this->usePropertyOptions($selector, $content, 'popover');
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap opover attribute
|
||||
*
|
||||
* @param string $placement
|
||||
* @param string $content
|
||||
* @param bool $html = NULL
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function tooltip(string $placement, $content = NULL, ?bool $html = NULL)
|
||||
{
|
||||
if( is_string($content) )
|
||||
{
|
||||
return $this->title($content)->dataHtml($html === true ? 'true' : $html)->dataToggle('tooltip')->dataPlacement($placement);
|
||||
}
|
||||
|
||||
return $this->usePropertyOptions($placement, $content, __FUNCTION__);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tooltip event
|
||||
*
|
||||
* @param string $selector
|
||||
* @param string|callback $content = ''
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function tooltipEvent(string $selector, $content = NULL)
|
||||
{
|
||||
return $this->usePropertyOptions($selector, $content, 'tooltip');
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap carousel
|
||||
*
|
||||
* @param string ...$images
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function carousel(?string $id = NULL, array $images = [], $view = 'standart')
|
||||
{
|
||||
$images = $this->transferAttributesAndUnset('attr', 'item') ?: $images;
|
||||
|
||||
$data =
|
||||
[
|
||||
'carouselId' => $id ?? ('Carousel' . md5(uniqid())),
|
||||
'carouselImages' => $images,
|
||||
'carouseIndicators' => $this->transferAttributesAndUnset('attr', 'indicators'),
|
||||
'carouselPrevName' => $this->transferAttributesAndUnset('attr', 'prev') ?: 'Previous',
|
||||
'carouselNextName' => $this->transferAttributesAndUnset('attr', 'next') ?: 'Next'
|
||||
];
|
||||
|
||||
foreach( ['interval', 'keyboard', 'ride', 'pause', 'wrap'] as $opt )
|
||||
{
|
||||
$this->addBootstrapOption($opt, $this->transferAttributesAndUnset('attr', $opt), $options);
|
||||
}
|
||||
|
||||
$transition = $this->transferAttributesAndUnset('attr', 'transition');
|
||||
|
||||
$this->isBootstrapAttribute('on', function($return)
|
||||
{
|
||||
$this->settings['attr']['on'] = Base::suffix($return, '.bs.carousel');
|
||||
});
|
||||
|
||||
$this->bootstrapObjectOptions(Base::prefix($id, '#'), $transition ?? $options, 'carousel');
|
||||
|
||||
return $this->getCarouselResource($view, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap carousel 4
|
||||
*
|
||||
* @param string ...$images
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function carousel4(?string $id = NULL, array $images = [])
|
||||
{
|
||||
return $this->carousel($id, $images, 'standart4');
|
||||
}
|
||||
|
||||
/**
|
||||
* Active caroseul options
|
||||
*/
|
||||
public function activeCarouselOptions(string $id)
|
||||
{
|
||||
return $this->bootstrapOptions['carousel'][Base::prefix($id, '#')] ?? NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Item
|
||||
*
|
||||
* @param string $file
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function item(string $file, array $attributes = [])
|
||||
{
|
||||
if( empty($attributes) )
|
||||
{
|
||||
$this->settings['attr']['item'][] = $file;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->settings['attr']['item'][$file] = $attributes;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap alert component
|
||||
*
|
||||
* @param string $type
|
||||
* @param string|callback $content
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function alert(string $type, $content)
|
||||
{
|
||||
$content = $this->stringOrCallback($content);
|
||||
|
||||
$this->isBootstrapAttribute('dismiss-fade', function() use(&$type)
|
||||
{
|
||||
$type .= ' alert-dismissible fade show';
|
||||
});
|
||||
|
||||
$this->isBootstrapAttribute('dismiss-button', function($attribute) use(&$content)
|
||||
{
|
||||
$content .= $this->buttonDismissButton((string) $this->spanDismissButton($attribute));
|
||||
});
|
||||
|
||||
return $this->role('alert')->class('alert alert-' . $type)->div($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap 4 badge component
|
||||
*
|
||||
* @param string $type
|
||||
* @param string|callback $content
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function badge4(string $type, $content)
|
||||
{
|
||||
$content = $this->stringOrCallback($content);
|
||||
|
||||
return $this->class('badge badge-' . $type)->span($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap badge component
|
||||
*
|
||||
* @param string $type
|
||||
* @param string|callback $content
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function badge(string $type, $content)
|
||||
{
|
||||
$content = $this->stringOrCallback($content);
|
||||
|
||||
return $this->class('label label-' . $type)->span($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap progress bar animated attribute
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function progressbarAnimated()
|
||||
{
|
||||
$this->settings['progressbarAnimated'] = ' progress-bar-striped progress-bar-animated';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap progress bar striped attribute
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function progressbarStriped()
|
||||
{
|
||||
$this->settings['progressbarStriped'] = ' progress-bar-striped';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap progress bar text attribute
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function progressbarText(string $text)
|
||||
{
|
||||
$this->settings['progressbarText'] = ' ' . $text;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap 4 progress bar component
|
||||
*
|
||||
* @param string $type
|
||||
* @param float $percent
|
||||
* @param float $height = NULL
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function progressbar4(string $type, Float $percent, ?float $height = NULL)
|
||||
{
|
||||
$attr = '';
|
||||
|
||||
if( isset($this->settings['progressbarAnimated']) )
|
||||
{
|
||||
$attr = $this->settings['progressbarAnimated']; unset($this->settings['progressbarAnimated']);
|
||||
}
|
||||
|
||||
if( isset($this->settings['progressbarStriped']) )
|
||||
{
|
||||
$attr = $this->settings['progressbarStriped']; unset($this->settings['progressbarStriped']);
|
||||
}
|
||||
|
||||
if( isset($this->settings['progressbarText']) )
|
||||
{
|
||||
$text = $this->settings['progressbarText']; unset($this->settings['progressbarText']);
|
||||
}
|
||||
|
||||
|
||||
$content = (string) $this->class('progress-bar bg-' . $type . $attr)->style('width:' . $percent . '%')->div('%' . $percent . ($text ?? ''));
|
||||
|
||||
if( $height )
|
||||
{
|
||||
$this->style('height:' . $height . 'px');
|
||||
}
|
||||
|
||||
return $this->class('progress')->div($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap 4 progress bar component
|
||||
*
|
||||
* @param string $type
|
||||
* @param float $percent
|
||||
* @param float $height = NULL
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function progressbar(string $type, Float $percent, ?float $height = NULL)
|
||||
{
|
||||
$attr = '';
|
||||
|
||||
if( isset($this->settings['progressbarAnimated']) )
|
||||
{
|
||||
$attr = $this->settings['progressbarAnimated']; unset($this->settings['progressbarAnimated']);
|
||||
}
|
||||
|
||||
if( isset($this->settings['progressbarStriped']) )
|
||||
{
|
||||
$attr = $this->settings['progressbarStriped']; unset($this->settings['progressbarStriped']);
|
||||
}
|
||||
|
||||
if( isset($this->settings['progressbarText']) )
|
||||
{
|
||||
$text = $this->settings['progressbarText']; unset($this->settings['progressbarText']);
|
||||
}
|
||||
|
||||
$content = (string) $this->class('progress-bar progress-bar-' . $type . $attr)->style('width:' . $percent . '%')->div('%' . $percent . ($text ?? ''));
|
||||
|
||||
if( $height )
|
||||
{
|
||||
$this->style('height:' . $height . 'px');
|
||||
}
|
||||
|
||||
return $this->class('progress')->div($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate bootstrap filter
|
||||
*
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @param string $event = NULL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function filterEvent(string $source, string $target, ?string $event = NULL, $template = 'standart')
|
||||
{
|
||||
$data =
|
||||
[
|
||||
'filterSource' => $source,
|
||||
'filterTarget' => $target,
|
||||
'filterEvent' => $event
|
||||
];
|
||||
|
||||
return $this->getResource($template, $data, 'Filters');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate bootstrap media object reply
|
||||
*
|
||||
* @param string|callback $content
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function mediaObjectReply($content)
|
||||
{
|
||||
$this->settings['mediaObjectReply'] = $this->stringOrCallback($content);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate bootstrap 4 media object
|
||||
*
|
||||
* @param string $avatar
|
||||
* @param string $name
|
||||
* @param string $content
|
||||
* @param string $date = NULL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mediaObject4(string $avatar, string $name, string $content, string $date, $template = 'standart')
|
||||
{
|
||||
$attr = $this->settings['attr'] ?? [];
|
||||
|
||||
$this->settings['attr'] = [];
|
||||
|
||||
$data =
|
||||
[
|
||||
'mediaObjectAvatar' => $avatar,
|
||||
'mediaObjectName' => $name,
|
||||
'mediaObjectContent' => $content,
|
||||
'mediaObjectDate' => $date,
|
||||
'mediaObjectPadding' => $attr['media-object-padding'] ?? NULL,
|
||||
'mediaObjectAvatarMargin' => $attr['media-object-avatar-margin'] ?? NULL,
|
||||
'mediaObjectAvatarSize' => $attr['media-object-avatar-size'] ?? NULL,
|
||||
'mediObjectAvatarType' => $attr['media-object-avatar-type'] ?? NULL,
|
||||
'mediaObjectReply' => $this->settings['mediaObjectReply'] ?? NULL
|
||||
];
|
||||
|
||||
unset($this->settings['mediaObjectAnswer']);
|
||||
|
||||
return $this->getResource($template, $data, 'MediaObjects');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fontawesome Icon
|
||||
*
|
||||
* @param string $icon
|
||||
* @param string $size = NULL
|
||||
* @param string $type = '
|
||||
*/
|
||||
public function faIcon(string $icon, ?string $size = NULL, $type = '')
|
||||
{
|
||||
return '<i class="fa' . $type . ' fa-' . $icon . ($size ? ' fa-' . $size : NULL) . '"></i>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Fontawesome Icon
|
||||
*
|
||||
* @param string $icon
|
||||
* @param string $size = NULL
|
||||
* @param string $type = '
|
||||
*/
|
||||
public function falIcon(string $icon, ?string $size = NULL)
|
||||
{
|
||||
return $this->faIcon($icon, $size, 'l');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fontawesome Icon
|
||||
*
|
||||
* @param string $icon
|
||||
* @param string $size = NULL
|
||||
* @param string $type = '
|
||||
*/
|
||||
public function fasIcon(string $icon, ?string $size = NULL)
|
||||
{
|
||||
return $this->faIcon($icon, $size, 's');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fontawesome Icon
|
||||
*
|
||||
* @param string $icon
|
||||
* @param string $size = NULL
|
||||
* @param string $type = '
|
||||
*/
|
||||
public function fadIcon(string $icon, ?string $size = NULL)
|
||||
{
|
||||
return $this->faIcon($icon, $size, 'd');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fontawesome Icon
|
||||
*
|
||||
* @param string $icon
|
||||
* @param string $size = NULL
|
||||
* @param string $type = '
|
||||
*/
|
||||
public function farIcon(string $icon, ?string $size = NULL)
|
||||
{
|
||||
return $this->faIcon($icon, $size, 'r');
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap flex
|
||||
*
|
||||
* @param string|callback $content
|
||||
* @param string $class = NULL
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function flex($content, ?string $class = NULL)
|
||||
{
|
||||
$attr = $this->settings['attr'] ?? [];
|
||||
|
||||
$this->settings['attr'] = [];
|
||||
|
||||
$content = $this->stringOrCallback($content);
|
||||
|
||||
$size = isset($attr['flex-size']) ? $attr['flex-size'] . '-' : NULL;
|
||||
|
||||
$type = (isset($attr['flex-inline']) ? 'd-' . $size . 'inline-flex' : 'd-' . $size . 'flex') . ' ';
|
||||
|
||||
if( isset($attr['flex-wrap']) )
|
||||
{
|
||||
$param = $this->getFlexParameters($attr['flex-wrap'], 'object');
|
||||
|
||||
switch($param->param)
|
||||
{
|
||||
case 'reverse' : $class .= ' flex-' . $param->size . 'wrap-reverse'; break;
|
||||
case 'no' : $class .= ' flex-' . $param->size . 'nowrap' ; break;
|
||||
|
||||
default : $class .= ' flex-' . ($param->param ? $param->param . '-' : NULL) . 'wrap';
|
||||
}
|
||||
}
|
||||
|
||||
if( isset($attr['flex-direction']) ) $class .= ' flex-' . $this->getFlexParameters($attr['flex-direction']);
|
||||
if( isset($attr['flex-justify']) ) $class .= ' justify-content-' . $this->getFlexParameters($attr['flex-justify']);
|
||||
if( isset($attr['flex-align']) ) $class .= ' align-content-' . $this->getFlexParameters($attr['flex-align']);
|
||||
if( isset($attr['flex-align-items']) ) $class .= ' align-items-' . $this->getFlexParameters($attr['flex-align-items']);
|
||||
|
||||
return $this->class($type . $class)->div($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap flex item
|
||||
*
|
||||
* @param string|callback $content
|
||||
* @param string $class = NULL
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function flexItem($content, ?string $class = NULL)
|
||||
{
|
||||
$attr = $this->settings['attr'] ?? [];
|
||||
|
||||
$this->settings['attr'] = [];
|
||||
|
||||
$content = $this->stringOrCallback($content);
|
||||
|
||||
if( isset($attr['flex-fill']) ) $class .= ' flex-' . ($attr['flex-fill'] === 'flexfill' ? NULL : $attr['flex-fill'] . '-') . 'fill';
|
||||
if( isset($attr['flex-grow']) ) $class .= ' flex-' . $this->getFlexParameters($attr['flex-grow'], 'grow-');
|
||||
if( isset($attr['flex-shrink']) ) $class .= ' flex-' . $this->getFlexParameters($attr['flex-shrink'], 'shrink-');
|
||||
if( isset($attr['flex-order']) ) $class .= ' order-' . $this->getFlexParameters($attr['flex-order']);
|
||||
if( isset($attr['flex-align-self']) ) $class .= ' align-self-' . $this->getFlexParameters($attr['flex-align-self']);
|
||||
|
||||
switch($attr['flex-push'] ?? NULL)
|
||||
{
|
||||
case 'right' : $class .= ' ml-auto'; break;
|
||||
case 'left' : $class .= ' mr-auto'; break;
|
||||
}
|
||||
|
||||
return $this->class($class)->div($content);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap spinner component
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $color
|
||||
* @param string $size
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function spinner(string $type = 'border', ?string $color = NULL, ?string $size = NULL)
|
||||
{
|
||||
return $this->class('spinner-' . $type . ($color ? ' text-' . $color : NULL) . ($size ? ' spinner-' . $type . '-' . $size : NULL) )->div();
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap spinner border component
|
||||
*
|
||||
* @param string $color
|
||||
* @param string $size
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function spinnerBorder(?string $color = NULL, ?string $size = NULL)
|
||||
{
|
||||
return $this->spinner('border', $color, $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap spinner grow component
|
||||
*
|
||||
* @param string $color
|
||||
* @param string $size
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
*/
|
||||
public function spinnerGrow(?string $color = NULL, ?string $size = NULL)
|
||||
{
|
||||
return $this->spinner('grow', $color, $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap breadcrumb
|
||||
*
|
||||
* @param string $uri = NULL
|
||||
*/
|
||||
public function breadcrumb(?string $uri = NULL, int $segmentCount = -1)
|
||||
{
|
||||
$uris = $this->getURIsegments($uri, $segmentCount);
|
||||
$list = $this->breadcrumbOlList($uris);
|
||||
|
||||
return $this->breadcrumbNav($list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get flex parameters
|
||||
*/
|
||||
protected function getFlexParameters($param, $fix = NULL)
|
||||
{
|
||||
$paramEx = explode(',', $param);
|
||||
$param = $paramEx[0];
|
||||
$size = trim($paramEx[1] ?? '');
|
||||
$size = ($size ? $size . '-' : '');
|
||||
|
||||
if( $fix === 'object' )
|
||||
{
|
||||
return (object)['size' => $size, 'param' => $param];
|
||||
}
|
||||
|
||||
return $size . $fix . $param;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected add bootstrap option
|
||||
*/
|
||||
protected function addBootstrapOption($key, $value, &$options)
|
||||
{
|
||||
if( isset($value) )
|
||||
{
|
||||
$options[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get uri segments
|
||||
*/
|
||||
protected function getURIsegments($uri, $segmentCount)
|
||||
{
|
||||
if( $uri === NULL)
|
||||
{
|
||||
$uri = URI::active();
|
||||
}
|
||||
|
||||
|
||||
return explode('/' , rtrim(Datatype::divide($uri, '/', 0, $segmentCount), '/'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected breadcrumb ol list
|
||||
*/
|
||||
protected function breadcrumbOlList($options)
|
||||
{
|
||||
return $this->ol(function($option) use($options)
|
||||
{
|
||||
$link = '';
|
||||
$count = count($options);
|
||||
|
||||
if( $count === 2 && $options[1] === CURRENT_COPEN_PAGE )
|
||||
{
|
||||
unset($options[1]);
|
||||
|
||||
$count--;
|
||||
}
|
||||
|
||||
foreach( $options as $key => $val )
|
||||
{
|
||||
$link .= Base::suffix($val);
|
||||
|
||||
if( $key < $count - 1 )
|
||||
{
|
||||
$item = $this->breadcrumbItem($link, $val);
|
||||
|
||||
echo $option->class('breadcrumb-item active')->ariaCurrent('page')->li($item);
|
||||
}
|
||||
else
|
||||
{
|
||||
echo $option->class('breadcrumb-item')->li(ucfirst($val));
|
||||
}
|
||||
}
|
||||
}, ['class' => 'breadcrumb']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected breadcrumb nav
|
||||
*/
|
||||
protected function breadcrumbNav($content)
|
||||
{
|
||||
return '<nav aria-label="breadcrumb">' . $content . '</nav>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected breadcrumb item
|
||||
*/
|
||||
protected function breadcrumbItem($link, $content)
|
||||
{
|
||||
return $this->anchor($link, ucfirst($content));
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected close button
|
||||
*/
|
||||
protected function spanDismissButton($attribute)
|
||||
{
|
||||
return $this->ariaHidden('true')->span($attribute ?? '×');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected button dismiss button
|
||||
*/
|
||||
protected function buttonDismissButton($content)
|
||||
{
|
||||
return $this->class('close')->dataDismiss('alert')->ariaLabel('Close')->button($content);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,176 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
trait BootstrapLayouts
|
||||
{
|
||||
/**
|
||||
* Protected bootstrap grid system column
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $bootstrapGridsystemCol = NULL;
|
||||
|
||||
/**
|
||||
* Protected bootstrap grid system row
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $bootstrapGridsystemRow = NULL;
|
||||
|
||||
/**
|
||||
* Protected bootstrap grid sytem column count
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $bootstrapGridsystemColumnCount = 0;
|
||||
|
||||
/**
|
||||
* Protected bootstrap container div element attributes
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $bootstrapContainerDivElementAttributes = 'container';
|
||||
|
||||
/**
|
||||
* Container fluid
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function fluid()
|
||||
{
|
||||
$this->bootstrapContainerDivElementAttributes = 'container-fluid';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start container div
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function startContainerDiv()
|
||||
{
|
||||
return $this->createStartDivElement('container');
|
||||
}
|
||||
|
||||
/**
|
||||
* Start fluid container div
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function startFluidContainerDiv()
|
||||
{
|
||||
return $this->createStartDivElement('container-fluid');
|
||||
}
|
||||
|
||||
/**
|
||||
* Start row div
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function startRowDiv()
|
||||
{
|
||||
return $this->createStartDivElement('row');
|
||||
}
|
||||
|
||||
/**
|
||||
* Start column div
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function startColumnDiv($size)
|
||||
{
|
||||
return $this->createStartDivElement('col-' . $size);
|
||||
}
|
||||
|
||||
/**
|
||||
* End div
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function endDiv()
|
||||
{
|
||||
return '</div>' . PHP_EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected bootstrap column
|
||||
*/
|
||||
protected function bootstrapColumn($content, $match)
|
||||
{
|
||||
$parts = $this->getGridsystemColumMethodParts($match);
|
||||
|
||||
$this->bootstrapGridsystemCol .= $this->class($this->getGridsytemColumnClass($parts))->div($content);
|
||||
|
||||
$this->bootstrapGridsystemColumnCount += (int) $parts['number'];
|
||||
|
||||
if( $this->bootstrapGridsystemColumnCount === 12 )
|
||||
{
|
||||
$this->bootstrapGridsystemRow .= $this->class('row')->div($this->bootstrapGridsystemCol ?: '');
|
||||
|
||||
$this->bootstrapGridsystemCol = '';
|
||||
|
||||
$this->bootstrapGridsystemColumnCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is bootstrap column
|
||||
*/
|
||||
protected function isBootstrapColumn($method, &$match)
|
||||
{
|
||||
return preg_match('/col(?<type>[a-z][a-z])(?<number>[0-9]{1,})*/', $method ?? '', $match);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get grid system column method parts
|
||||
*/
|
||||
protected function getGridsystemColumMethodParts($match)
|
||||
{
|
||||
return ['name' => 'col', 'type' => $match['type'], 'number' => $match['number'] ?? 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get grid system column class
|
||||
*/
|
||||
protected function getGridsytemColumnClass($parts)
|
||||
{
|
||||
return implode('-', $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get bootstrap grid system
|
||||
*/
|
||||
protected function getBootstrapGridsystem()
|
||||
{
|
||||
return $this->bootstrapGridsystemRow ?: $this->bootstrapGridsystemCol ?: '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create bootstrap grid system
|
||||
*/
|
||||
protected function createBootstrapGridsystem()
|
||||
{
|
||||
$return = (string) $this->class($this->bootstrapContainerDivElementAttributes)->div($this->getBootstrapGridsystem());
|
||||
|
||||
$this->bootstrapGridsystemRow = '';
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create start div element
|
||||
*/
|
||||
protected function createStartDivElement($class)
|
||||
{
|
||||
return '<div class="' . $class . '">' . PHP_EOL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Singleton;
|
||||
use ZN\Buffering;
|
||||
|
||||
class BuilderExtends
|
||||
{
|
||||
/**
|
||||
* Protected keeps builder
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $builder = NULL;
|
||||
|
||||
/**
|
||||
* Protected script open tag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $tag = false;
|
||||
|
||||
/**
|
||||
* Magic to string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return $this->openCloseTag($this->build($this->builder));
|
||||
}
|
||||
|
||||
/**
|
||||
* Open script tag
|
||||
*
|
||||
* @param bool $status
|
||||
*/
|
||||
public function tag(bool $status)
|
||||
{
|
||||
$this->tag = $status;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get script class
|
||||
*/
|
||||
protected function getScriptClass()
|
||||
{
|
||||
return Singleton::class('ZN\Hypertext\Script');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected script open close tag
|
||||
*/
|
||||
protected function openCloseTag($string)
|
||||
{
|
||||
if( $this->tag === true )
|
||||
{
|
||||
$script = $this->getScriptClass();
|
||||
|
||||
$string = $script->open() . $string . $script->close();
|
||||
}
|
||||
|
||||
$this->tag = false;
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is callable option
|
||||
*/
|
||||
protected function isCallableOption($callback, $parameter)
|
||||
{
|
||||
$option = 'function(' . $parameter . '){' . PHP_EOL;
|
||||
$option .= Buffering\Callback::do($callback);
|
||||
$option .= '}';
|
||||
|
||||
return $option;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Base;
|
||||
use ZN\Classes;
|
||||
use ZN\Datatype;
|
||||
use ZN\DataTypes\Arrays;
|
||||
|
||||
trait CallableElements
|
||||
{
|
||||
protected $useElements =
|
||||
[
|
||||
'addclass' => 'class'
|
||||
];
|
||||
|
||||
/**
|
||||
* Magic Call
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
$realMethod = $method;
|
||||
$method = strtolower($method);
|
||||
$className = Classes::onlyName(__CLASS__);
|
||||
|
||||
if( $className === 'Html')
|
||||
{
|
||||
$multiElement = $this->elements['multiElement'];
|
||||
|
||||
# Bootstrap Gridsystem
|
||||
if( $this->isBootstrapColumn($method, $match) )
|
||||
{
|
||||
$this->bootstrapColumn($parameters[0] ?? '', $match);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
# Bootstrap Alert
|
||||
elseif( strpos($method, 'alert') === 0 )
|
||||
{
|
||||
return $this->alert(Base::removePrefix($method, 'alert'), $parameters[0] ?? '');
|
||||
}
|
||||
|
||||
# Bootstrap Badge
|
||||
elseif( preg_match('/^(?<method>badge[0-9]*)/i', $method, $match) )
|
||||
{
|
||||
return $this->{$match['method']}(Base::removePrefix($method, $match['method']), $parameters[0] ?? '');
|
||||
}
|
||||
|
||||
# Bootstrap progress bar
|
||||
elseif(preg_match('/^(?<method>progressbar[0-9]*)/i', $method, $match) )
|
||||
{
|
||||
return $this->{$match['method']}(Base::removePrefix($method, $match['method']), $parameters[0] ?? NULL, $parameters[1] ?? NULL);
|
||||
}
|
||||
|
||||
# Multiple Element
|
||||
elseif( isset($multiElement[$method]) )
|
||||
{
|
||||
$realMethod = $multiElement[$method];
|
||||
|
||||
return $this->_multiElement($realMethod, ...$parameters);
|
||||
}
|
||||
elseif( in_array($method, $multiElement) )
|
||||
{
|
||||
return $this->_multiElement($realMethod, ...$parameters);
|
||||
}
|
||||
|
||||
# Single Element
|
||||
elseif( in_array($method, $this->elements['singleElement']) )
|
||||
{
|
||||
return $this->_singleElement($realMethod, ...$parameters);
|
||||
}
|
||||
|
||||
# Media Content
|
||||
elseif( in_array($method, $this->elements['mediaContent']) )
|
||||
{
|
||||
return $this->_mediaContent($parameters[0] ?? '', $parameters[1] ?? NULL, $parameters[2] ?? [], $realMethod);
|
||||
}
|
||||
|
||||
# Media
|
||||
elseif( in_array($method, $this->elements['media']) )
|
||||
{
|
||||
return $this->_media($parameters[0] ?? '', $parameters[1] ?? [], $realMethod);
|
||||
}
|
||||
|
||||
# Content Attribute
|
||||
elseif( in_array($method, $this->elements['contentAttribute']) )
|
||||
{
|
||||
return $this->_contentAttribute($parameters[0] ?? '', $parameters[1] ?? [], $realMethod);
|
||||
}
|
||||
|
||||
# Content
|
||||
elseif( in_array($method, $this->elements['content']) )
|
||||
{
|
||||
return $this->_content($parameters[0] ?? '', $realMethod);
|
||||
}
|
||||
}
|
||||
elseif( $className === 'Form' )
|
||||
{
|
||||
if( in_array($method, $this->elements['input']) )
|
||||
{
|
||||
return $this->_input($parameters[0] ?? '', $parameters[1] ?? '', $parameters[2] ?? [], $realMethod);
|
||||
}
|
||||
}
|
||||
|
||||
if( empty($parameters) )
|
||||
{
|
||||
$parameters[0] = $method;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( $parameters[0] === NULL )
|
||||
{
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
if( isset($this->useElements[$method]) )
|
||||
{
|
||||
$method = $this->useElements[$method];
|
||||
}
|
||||
|
||||
# Convert exampleData to example-data [4.6.1]
|
||||
if( ! ctype_lower($realMethod) )
|
||||
{
|
||||
$split = Datatype::splitUpperCase($realMethod);
|
||||
$method = implode('-', Arrays\Casing::lower($split));
|
||||
}
|
||||
|
||||
$this->_element($method, ...$parameters);
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php namespace ZN\Hypertext\Exception;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Exception;
|
||||
|
||||
class InvalidArgumentException extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php namespace ZN\Hypertext\Exception;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Exception;
|
||||
|
||||
class PermissionRoleIdException extends Exception
|
||||
{
|
||||
const lang =
|
||||
[
|
||||
'tr' => 'Bu kullanım için # tanımlaması yapınız!',
|
||||
'en' => 'Do the # definition for this use!',
|
||||
'placement' =>
|
||||
[
|
||||
'#' => 'Permission::roleId()'
|
||||
]
|
||||
];
|
||||
}
|
||||
@@ -0,0 +1,833 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Hypertext\Exception\InvalidArgumentException;
|
||||
use ZN\DataTypes\Arrays;
|
||||
use ZN\Protection\Json;
|
||||
use ZN\Request\Method;
|
||||
use ZN\Buffering;
|
||||
use ZN\Singleton;
|
||||
use ZN\Inclusion;
|
||||
use ZN\Base;
|
||||
use ZN\IS;
|
||||
|
||||
class Form
|
||||
{
|
||||
use ViewCommonTrait;
|
||||
|
||||
/**
|
||||
* Keeps validation usage this form info.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $validateUsageThisForm = false;
|
||||
|
||||
/**
|
||||
* Keeps validation form name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $getValidationFormName = NULL;
|
||||
|
||||
/**
|
||||
* Keeps real form name.
|
||||
*/
|
||||
protected $getFormName = NULL;
|
||||
|
||||
/**
|
||||
* Keeps form input objects.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $elements =
|
||||
[
|
||||
'input' =>
|
||||
[
|
||||
'button', 'reset' , 'submit' , 'radio', 'checkbox',
|
||||
'date' , 'time' , 'datetime', 'week' , 'month' ,
|
||||
'text' , 'search', 'password', 'email', 'tel' ,
|
||||
'number', 'url' , 'range' , 'image', 'color'
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* Keeps validation rules.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $validate = [];
|
||||
|
||||
/**
|
||||
* Keeps method type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $method;
|
||||
|
||||
/**
|
||||
* Keeps update process row
|
||||
*
|
||||
* @var object
|
||||
*/
|
||||
protected $getUpdateRow;
|
||||
|
||||
/**
|
||||
* Gets update process row
|
||||
*/
|
||||
public function getUpdateRow()
|
||||
{
|
||||
return $this->getUpdateRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Open form tag.
|
||||
*
|
||||
* @param string $name = NULL
|
||||
* @param array $_attributes = []
|
||||
*
|
||||
* Available Enctype Options
|
||||
*
|
||||
* 1. multipart => multipart/form-data
|
||||
* 2. application => application/x-www-form-urlencoded
|
||||
* 3. text => text/plain
|
||||
*
|
||||
* @return string|object
|
||||
*/
|
||||
public function open(?string $name = NULL, array $_attributes = [])
|
||||
{
|
||||
$this->setFormName($name, $_attributes);
|
||||
|
||||
$this->isEnctypeAttribute($_attributes);
|
||||
|
||||
$this->isWhereAttribute($name);
|
||||
|
||||
$this->isQueryAttribute();
|
||||
|
||||
$this->isPreventAttribute();
|
||||
|
||||
$this->setMethodType($_attributes);
|
||||
|
||||
$this->createFormElementByAttributes($_attributes, $return);
|
||||
|
||||
$this->isDatabaseProcessWithName($name, $return);
|
||||
|
||||
$this->isCSRFAttribute($return);
|
||||
|
||||
$this->_unsetopen();
|
||||
|
||||
$this->outputElement .= $return;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get form name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->getFormName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate error message.
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function validateErrorMessage()
|
||||
{
|
||||
return Singleton::class('ZN\Validation\Data')->error('string');
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate error array.
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function validateErrorArray()
|
||||
{
|
||||
return Singleton::class('ZN\Validation\Data')->error('array');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset validation rules
|
||||
*
|
||||
* @param string $formName
|
||||
*/
|
||||
public function resetValidationRules(string $formName)
|
||||
{
|
||||
$session = Singleton::class('ZN\Storage\Session');
|
||||
|
||||
$session->delete('FormValidationRules' . $formName);
|
||||
$session->delete('FormValidationMethod' . $formName);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes form object.
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return string|object
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
unset($this->settings['getrow']);
|
||||
|
||||
$this->getFormName = NULL;
|
||||
|
||||
if( isset($this->getJavascriptValidationFunction) )
|
||||
{
|
||||
$this->outputElement .= Inclusion\View::use('JavascriptValidationFunctions', $this->getJavascriptValidationFunction, true, __DIR__ . '/');
|
||||
|
||||
$this->getJavascriptValidationFunction = NULL;
|
||||
}
|
||||
|
||||
if( $this->validateUsageThisForm === true )
|
||||
{
|
||||
$this->outputElement .= '<input type="hidden" name="ValidationFormName" value="' . $this->getValidationFormName . '">';
|
||||
|
||||
$this->getValidationFormName = NULL;
|
||||
|
||||
$this->validateUsageThisForm = false;
|
||||
}
|
||||
|
||||
$this->outputElement .= '</form>' . EOL;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* datetime-local form object.
|
||||
*
|
||||
* @param string $name = NULL
|
||||
* @param string $value = NULL
|
||||
* @param array $_attributes = []
|
||||
*
|
||||
* @return string|object
|
||||
*/
|
||||
public function datetimeLocal(?string $name = NULL, ?string $value = NULL, array $_attributes = [])
|
||||
{
|
||||
return $this->_input($name, $value, $_attributes, 'datetime-local');
|
||||
}
|
||||
|
||||
/**
|
||||
* textarea form object.
|
||||
*
|
||||
* @param string $name = NULL
|
||||
* @param string $value = NULL
|
||||
* @param array $_attributes = []
|
||||
*
|
||||
* @return string|object
|
||||
*/
|
||||
public function textarea(?string $name = NULL, ?string $value = NULL, array $_attributes = [])
|
||||
{
|
||||
$this->setNameAttribute($name);
|
||||
|
||||
$this->setValueAttribute($value);
|
||||
|
||||
if( ! empty($this->settings['attr']['name']) )
|
||||
{
|
||||
$this->_postback($this->settings['attr']['name'], $value);
|
||||
|
||||
# 5.8.2.8[added]
|
||||
$this->getVMethodMessages();
|
||||
|
||||
# 5.4.2[added]
|
||||
$this->_validate($this->settings['attr']['name'], $this->settings['attr']['name']);
|
||||
|
||||
# 5.4.2[added]|5.4.5|5.4.6[edited]
|
||||
$value = $this->_getrow('textarea', $value, $this->settings['attr']);
|
||||
}
|
||||
|
||||
$this->commonMethodsForInputElements('textarea');
|
||||
|
||||
$this->getPermAttribute($perm);
|
||||
|
||||
$this->createTextareaElementByValueAndAttributes($value, $_attributes, $return);
|
||||
|
||||
$this->createBootstrapFormInputElementByType('textarea', $return, $_attributes, $return);
|
||||
|
||||
$this->outputElement .= $this->_perm($perm, $return);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* select form object.
|
||||
*
|
||||
* @param string $name = NULL
|
||||
* @param string $optios = []
|
||||
* @param mixed $selected = NULL
|
||||
* @param array $_attributes = []
|
||||
* @param bool $multiple = false
|
||||
*
|
||||
* @return string|object
|
||||
*/
|
||||
public function select(?string $name = NULL, array $options = [], $selected = NULL, array $_attributes = [], bool $multiple = false)
|
||||
{
|
||||
$this->isRepeatData($options);
|
||||
|
||||
$this->isTableOrQueryData($options);
|
||||
|
||||
$this->setOptionAttribute($options);
|
||||
|
||||
$this->isExcludeAttribute($options);
|
||||
|
||||
$this->isIncludeAttribute($options);
|
||||
|
||||
$this->isOrderAttribute($options);
|
||||
|
||||
$this->setSelectedAttribute($selected, $options);
|
||||
|
||||
$this->setMultipleAttribute($multiple, $_attributes);
|
||||
|
||||
$this->setNameAttributeWithReference($name, $_attributes);
|
||||
|
||||
if( ! empty($_attributes['name']) )
|
||||
{
|
||||
$this->_postback($_attributes['name'], $selected);
|
||||
|
||||
# 5.8.2.8[added]
|
||||
$this->getVMethodMessages();
|
||||
|
||||
# 5.4.2[added]
|
||||
$this->_validate($_attributes['name'], $_attributes['name']);
|
||||
|
||||
# 5.4.2[added]|5.4.5|5.4.6[edited]
|
||||
$selected = $this->_getrow('select', $selected, $_attributes);
|
||||
}
|
||||
|
||||
$this->commonMethodsForInputElements('select');
|
||||
|
||||
$this->getPermAttribute($perm);
|
||||
|
||||
$this->createSelectElement($options, $selected, $_attributes, $return);
|
||||
|
||||
$this->createBootstrapFormInputElementByType('select', $return, $_attributes, $return);
|
||||
|
||||
$this->_unsetselect();
|
||||
|
||||
$this->outputElement .= $this->_perm($perm, $return);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* select type multiselect form object.
|
||||
*
|
||||
* @param string $name = NULL
|
||||
* @param string $optios = []
|
||||
* @param mixed $selected = NULL
|
||||
* @param array $_attributes = []
|
||||
*
|
||||
* @return string|object
|
||||
*/
|
||||
public function multiselect(?string $name = NULL, array $options = [], $selected = NULL, array $_attributes = [])
|
||||
{
|
||||
return $this->select($name, $options, $selected, $_attributes, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* hidden form object.
|
||||
*
|
||||
* @param string $name = NULL
|
||||
* @param string $value = NULL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function hidden($name = NULL, ?string $value = NULL)
|
||||
{
|
||||
$name = $this->settings['attr']['name' ] ?? $name ;
|
||||
$value = $this->settings['attr']['value'] ?? $value;
|
||||
|
||||
$this->settings['attr'] = [];
|
||||
|
||||
$hiddens = '';
|
||||
|
||||
if( is_array($name) ) foreach( $name as $key => $val )
|
||||
{
|
||||
$hiddens .= $this->createHiddenElement($key, $val);
|
||||
}
|
||||
else
|
||||
{
|
||||
$hiddens = $this->createHiddenElement($name, $value);
|
||||
}
|
||||
|
||||
$this->outputElement .= $hiddens;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* file form object.
|
||||
*
|
||||
* @param string $name = NULL
|
||||
* @param string $value = NULL
|
||||
* @param array $_attributes = []
|
||||
*
|
||||
* @return string|object
|
||||
*/
|
||||
public function file(?string $name = NULL, bool $multiple = false, array $_attributes = [])
|
||||
{
|
||||
if( ! empty($this->settings['attr']['multiple']) )
|
||||
{
|
||||
$multiple = true;
|
||||
}
|
||||
|
||||
$name = $this->settings['attr']['name'] ?? $name;
|
||||
|
||||
if( $multiple === true )
|
||||
{
|
||||
$this->settings['attr']['multiple'] = 'multiple';
|
||||
$name = Base::suffix($name, '[]');
|
||||
}
|
||||
|
||||
$this->commonMethodsForInputElements('file');
|
||||
|
||||
return $this->_input($name, '', $_attributes, 'file');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create hidden element
|
||||
*/
|
||||
protected function createHiddenElement($key, $value)
|
||||
{
|
||||
return '<input type="hidden" name="' . $key . '" id="' . $key . '" value="' . $value . '">' . EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create select element
|
||||
*/
|
||||
protected function createSelectElement($options, $selected, $_attributes, &$return)
|
||||
{
|
||||
$option = '';
|
||||
|
||||
if( is_string($selected) && Json::check($selected) )
|
||||
{
|
||||
$selected = Json::decodeArray($selected);
|
||||
}
|
||||
|
||||
if( is_array($options) ) foreach( $options as $key => $value )
|
||||
{
|
||||
if( is_array($selected) )
|
||||
{
|
||||
if( in_array($key, $selected) )
|
||||
{
|
||||
$select = ' selected="selected"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$select = "";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( $selected === $key || ( is_numeric($selected) && $selected == $key ) )
|
||||
{
|
||||
$select = ' selected="selected"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$select = "";
|
||||
}
|
||||
}
|
||||
|
||||
if( is_numeric($value) || ! empty($value) )
|
||||
{
|
||||
$option .= '<option value="'.$key.'"'.$select.'>'.$value.'</option>'.EOL;
|
||||
}
|
||||
}
|
||||
|
||||
if( isset($this->settings['attr']['only-options']) )
|
||||
{
|
||||
unset($this->settings['attr']['only-options']);
|
||||
|
||||
$return = $option;
|
||||
}
|
||||
else
|
||||
{
|
||||
$return = '<select'.$this->attributes($_attributes).'>' . $option . '</select>'.EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set multiple attribute
|
||||
*/
|
||||
protected function setMultipleAttribute($multiple, &$_attributes)
|
||||
{
|
||||
if( $multiple === true )
|
||||
{
|
||||
$_attributes['multiple'] = 'multiple';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set selected attribute
|
||||
*/
|
||||
protected function setSelectedAttribute(&$selected, $options)
|
||||
{
|
||||
$selected = $this->settings['selectedKey'] ?? $selected;
|
||||
|
||||
if( isset($this->settings['selectedValue']) )
|
||||
{
|
||||
$flip = array_flip($options);
|
||||
$selected = $flip[$this->settings['selectedValue']];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is order attribute
|
||||
*/
|
||||
protected function isOrderAttribute(&$options)
|
||||
{
|
||||
if( isset($this->settings['order']['type']) )
|
||||
{
|
||||
$options = Arrays\Sort::order($options, $this->settings['order']['type'], $this->settings['order']['flags']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is exclude attribute
|
||||
*/
|
||||
protected function isExcludeAttribute(&$options)
|
||||
{
|
||||
if( isset($this->settings['exclude']) )
|
||||
{
|
||||
$options = Arrays\Excluding::use($options, $this->settings['exclude']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is include attribute
|
||||
*/
|
||||
protected function isIncludeAttribute(&$options)
|
||||
{
|
||||
if( isset($this->settings['include']) )
|
||||
{
|
||||
$options = Arrays\Including::use($options, $this->settings['include']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set option attribute
|
||||
*/
|
||||
protected function setOptionAttribute(&$options)
|
||||
{
|
||||
$options = $this->settings['option'] ?? $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is repeat data
|
||||
*/
|
||||
protected function isRepeatData(&$options)
|
||||
{
|
||||
if( ! empty($this->settings['attr']['repeat']) )
|
||||
{
|
||||
$key = key($options); $current = current($options);
|
||||
|
||||
if( $key > $current )
|
||||
{
|
||||
$ocurrent = $current;
|
||||
$current = $key;
|
||||
$key = $ocurrent;
|
||||
}
|
||||
|
||||
for( $i = $key; $i <= $current; $i++ )
|
||||
{
|
||||
$options[$i] = $i;
|
||||
}
|
||||
|
||||
unset($this->settings['attr']['repeat']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is table or query data
|
||||
*/
|
||||
protected function isTableOrQueryData(&$options)
|
||||
{
|
||||
if( ! empty($this->settings['table']) || ! empty($this->settings['query']) )
|
||||
{
|
||||
$key = key($options);
|
||||
$current = current($options);
|
||||
|
||||
if( IS::closure($current) )
|
||||
{
|
||||
$selectedColumns = ['*'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$selectedColumns = [$key, $current];
|
||||
}
|
||||
|
||||
array_shift($options);
|
||||
|
||||
$dbClass = Singleton::class('ZN\Database\DB');
|
||||
|
||||
if( ! empty($this->settings['table']) )
|
||||
{
|
||||
$table = $this->settings['table'];
|
||||
|
||||
if( strstr($table, ':') )
|
||||
{
|
||||
$tableEx = explode(':', $table);
|
||||
$table = $tableEx[1];
|
||||
$db = $tableEx[0];
|
||||
|
||||
$db = $dbClass->differentConnection($db);
|
||||
$result = $db->select(...$selectedColumns)->get($table)->result();
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = $dbClass->select(...$selectedColumns)->get($table)->result();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$result = $dbClass->query($this->settings['query'])->result();
|
||||
}
|
||||
|
||||
foreach( $result as $row )
|
||||
{
|
||||
if( IS::closure($current) )
|
||||
{
|
||||
$options[$row->$key] = $current($row);
|
||||
}
|
||||
else
|
||||
{
|
||||
$options[$row->$key] = $row->$current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create textarea element by value and attributes
|
||||
*/
|
||||
protected function createTextareaElementByValueAndAttributes($value, $_attributes, &$return)
|
||||
{
|
||||
$return = '<textarea'.$this->attributes($_attributes).'>'.$value.'</textarea>' . EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set textarea name attribute
|
||||
*/
|
||||
protected function setNameAttribute($name)
|
||||
{
|
||||
if( ! isset($this->settings['attr']['name']) && ! empty($name) )
|
||||
{
|
||||
$this->settings['attr']['name'] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set value attribute
|
||||
*/
|
||||
protected function setValueAttribute(&$value)
|
||||
{
|
||||
$value = $this->settings['attr']['value'] ?? $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set form name
|
||||
*/
|
||||
protected function setFormName(&$name, &$_attributes)
|
||||
{
|
||||
$this->getFormName = $this->getValidationFormName = $name = $this->settings['attr']['name'] ?? $name;
|
||||
|
||||
$_attributes['name'] = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create form element by attributes
|
||||
*/
|
||||
protected function createFormElementByAttributes($_attributes, &$return)
|
||||
{
|
||||
$this->changeFormAttributes
|
||||
([
|
||||
'inline' => 'class:form-inline',
|
||||
'horizontal' => 'class:form-horizontal'
|
||||
]);
|
||||
|
||||
$return = '<form'.$this->attributes($_attributes).'>' . EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is database process with name
|
||||
*/
|
||||
protected function isDatabaseProcessWithName($name, &$return)
|
||||
{
|
||||
$return .= $this->_process($name, $this->method);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is csrf attribute
|
||||
*/
|
||||
protected function isCSRFAttribute(&$return)
|
||||
{
|
||||
if( isset($this->settings['token']) )
|
||||
{
|
||||
$return .= CSRFInput();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set method type
|
||||
*/
|
||||
protected function setMethodType(&$_attributes)
|
||||
{
|
||||
$this->method = ($_attributes['method'] = $_attributes['method'] ?? $this->settings['attr']['method'] ?? 'post');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is enctype attribute
|
||||
*/
|
||||
protected function isEnctypeAttribute(&$_attributes)
|
||||
{
|
||||
if( isset($_attributes['enctype']) )
|
||||
{
|
||||
$enctype = $_attributes['enctype'];
|
||||
|
||||
if( isset($this->enctypes[$enctype]) )
|
||||
{
|
||||
$_attributes['enctype'] = $this->enctypes[$enctype];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is where attribute
|
||||
*/
|
||||
protected function isWhereAttribute($name)
|
||||
{
|
||||
if( isset($this->settings['where']) )
|
||||
{
|
||||
$this->settings['getrow'] = Singleton::class('ZN\Database\DB')->get($name)->row();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is query attribute
|
||||
*/
|
||||
protected function isQueryAttribute()
|
||||
{
|
||||
if( $query = ($this->settings['query'] ?? NULL) )
|
||||
{
|
||||
$this->settings['getrow'] = Singleton::class('ZN\Database\DB')->query($query)->row();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is prevent attribute
|
||||
*/
|
||||
protected function isPreventAttribute()
|
||||
{
|
||||
if( isset($this->settings['attr']['prevent']) )
|
||||
{
|
||||
unset($this->settings['attr']['prevent']);
|
||||
|
||||
$this->settings['attr']['onsubmit'] = 'event.preventDefault()';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* protected process
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $method
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function _process($name, $method)
|
||||
{
|
||||
if( $process = ($this->settings['process'] ?? NULL) )
|
||||
{
|
||||
if( Method::$method('FormProcessValue') )
|
||||
{
|
||||
if( Singleton::class('ZN\Validation\Data')->check() )
|
||||
{
|
||||
$dbClass = Singleton::class('ZN\Database\DB');
|
||||
|
||||
if( $process === 'update' )
|
||||
{
|
||||
$dbClass->where
|
||||
(
|
||||
$whereColumn = $this->settings['whereColumn'],
|
||||
$whereValue = $this->settings['whereValue']
|
||||
)
|
||||
->update(strtolower($method).':'.$name);
|
||||
|
||||
$this->getUpdateRow = $this->settings['getrow'] = $dbClass->where($whereColumn, $whereValue)->get($name)->row();
|
||||
}
|
||||
elseif( $process === 'insert' )
|
||||
{
|
||||
if( isset($this->settings['duplicateCheck']) )
|
||||
{
|
||||
$dbClass->duplicateCheck();
|
||||
}
|
||||
|
||||
$dbClass->insert(strtolower($method).':'.$name);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidArgumentException('[Form::process()] method can take one of the values [update or insert].');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (string) $this->hidden('FormProcessValue', 'FormProcessValue');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* protected unset select variables
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _unsetselect()
|
||||
{
|
||||
unset($this->settings['table']);
|
||||
unset($this->settings['query']);
|
||||
unset($this->settings['option']);
|
||||
unset($this->settings['exclude']);
|
||||
unset($this->settings['include']);
|
||||
unset($this->settings['order']);
|
||||
unset($this->settings['selectedKey']);
|
||||
unset($this->settings['selectedValue']);
|
||||
}
|
||||
|
||||
/**
|
||||
* protected unset open variables
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function _unsetopen()
|
||||
{
|
||||
unset($this->settings['where']);
|
||||
unset($this->settings['whereValue']);
|
||||
unset($this->settings['whereColumn']);
|
||||
unset($this->settings['query']);
|
||||
unset($this->settings['token']);
|
||||
unset($this->settings['process']);
|
||||
unset($this->settings['duplicateCheck']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,711 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\IS;
|
||||
use ZN\Base;
|
||||
use ZN\Lang;
|
||||
use ZN\Request;
|
||||
use ZN\Singleton;
|
||||
use ZN\Protection\Json;
|
||||
|
||||
trait FormElementsTrait
|
||||
{
|
||||
/**
|
||||
* Keeps Enctypes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $enctypes =
|
||||
[
|
||||
'multipart' => 'multipart/form-data',
|
||||
'application' => 'application/x-www-form-urlencoded',
|
||||
'text' => 'text/plain'
|
||||
];
|
||||
|
||||
/**
|
||||
* Keeps Postback Data
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $postback = [];
|
||||
|
||||
/**
|
||||
* Keeps Validate Rules
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $validate = [];
|
||||
|
||||
/**
|
||||
* Keeps validation method messages
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $vMethodMessages = NULL;
|
||||
|
||||
/**
|
||||
* Keeps javascript validation function
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $getJavascriptValidationFunction;
|
||||
|
||||
/**
|
||||
* Email control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vEmail()
|
||||
{
|
||||
return $this->onInvalidEventPattern('^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$', 'email');
|
||||
}
|
||||
|
||||
/**
|
||||
* URL control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vUrl()
|
||||
{
|
||||
return $this->onInvalidEventPattern('^(\w+:)?//.*', 'url');
|
||||
}
|
||||
|
||||
/**
|
||||
* Numeric control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vNumeric()
|
||||
{
|
||||
return $this->onInvalidEventPattern('^[0-9]+$', 'numeric');
|
||||
}
|
||||
|
||||
/**
|
||||
* Alpha control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vAlpha()
|
||||
{
|
||||
return $this->onInvalidEventPattern('^[a-zA-Z]+$', 'alpha');
|
||||
}
|
||||
|
||||
/**
|
||||
* Alnum control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vAlnum()
|
||||
{
|
||||
return $this->onInvalidEventPattern('^([a-zA-Z]|[0-9])+$', 'alnum');
|
||||
}
|
||||
|
||||
/**
|
||||
* Required control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vRequired()
|
||||
{
|
||||
return $this->onInvalidEventPattern('^.+$', 'required');
|
||||
}
|
||||
|
||||
/**
|
||||
* Message control
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function vMessage(string $message)
|
||||
{
|
||||
$this->vMethodMessages = $message;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Between control
|
||||
*
|
||||
* @param int $min = 0
|
||||
* @param int $max = 0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vBetween(int $min = 0, int $max = 0)
|
||||
{
|
||||
return $this->setJavascriptValidation
|
||||
(
|
||||
'ZNValidationBetween',
|
||||
['betweenBoth' => [':p1' => $min, ':p2' => $max]],
|
||||
['betweenBoth' => [$min, $max]],
|
||||
[$min, $max]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Captcha control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vCaptcha()
|
||||
{
|
||||
return $this->setJavascriptValidation('ZNValidationCaptcha', 'captcha');
|
||||
}
|
||||
|
||||
/**
|
||||
* Captcha control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vAnswer()
|
||||
{
|
||||
return $this->setJavascriptValidation('ZNValidationAnswer', 'answer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Match control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vMatch(string $selector)
|
||||
{
|
||||
return $this->setJavascriptValidation('ZNValidationMatch', 'match', ['match' => $selector], [Base::presuffix($selector, '\'')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match password control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vMatchPassword(string $selector)
|
||||
{
|
||||
return $this->setJavascriptValidation('ZNValidationMatch', 'matchPassword', ['matchPassword' => $selector], [Base::presuffix($selector, '\'')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Phone control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vPhone(?string $pattern = NULL)
|
||||
{
|
||||
return $this->setJavascriptValidation('ZNValidationPhone', 'phone', ['phone' => $pattern], [Base::presuffix($pattern, '\'')]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pattern control
|
||||
*
|
||||
* @param string $pattern
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vPattern(string $pattern)
|
||||
{
|
||||
return $this->onInvalidEventPatternWithoutValidate($pattern, 'pattern');
|
||||
}
|
||||
|
||||
/**
|
||||
* Identity control
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vIdentity()
|
||||
{
|
||||
return $this->setJavascriptValidation('ZNValidationIdentity', 'identity');
|
||||
}
|
||||
|
||||
/**
|
||||
* Numeric control
|
||||
*
|
||||
* @param int $min = 0
|
||||
* @param int $max = NULL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vLimit(int $min = 0, ?int $max = NULL)
|
||||
{
|
||||
$key['minchar'] = [':p1' => $min];
|
||||
$typ['minchar'] = $min;
|
||||
|
||||
if( $max !== NULL )
|
||||
{
|
||||
$key['maxchar'] = [':p1' => $max];
|
||||
$typ['maxchar'] = $max;
|
||||
}
|
||||
|
||||
return $this->onInvalidEventPattern('.{' . $min . ',' . $max . '}', $key, [], $typ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Minchar control
|
||||
*
|
||||
* @param int $min = 0
|
||||
* @param int $max = NULL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vMinchar(int $min = 0)
|
||||
{
|
||||
return $this->minlength($min)->onInvalidEventAttributeValidate('minchar', [':p1' => $min], ['minchar' => $min]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maxchar control
|
||||
*
|
||||
* @param int $max = 0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function vMaxchar(int $max = 0)
|
||||
{
|
||||
return $this->maxlength($max)->onInvalidEventAttributeValidate('maxchar', [':p1' => $max], ['maxchar' => $max]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines validate rules.
|
||||
*
|
||||
* @param mixed ...$validate
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function validate(...$validate)
|
||||
{
|
||||
if( $this->validate === [] )
|
||||
{
|
||||
$this->validate = $validate;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->validate = array_merge($this->validate, $validate);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets postback
|
||||
*
|
||||
* @param bool $postback = true
|
||||
* @param string $type = 'post' - options[post|get]
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function postBack(bool $postback = true, string $type = 'post')
|
||||
{
|
||||
$this->postback['bool'] = $postback;
|
||||
$this->postback['type'] = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls CSRF
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function csrf()
|
||||
{
|
||||
$this->settings['token'] = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exluding data
|
||||
*
|
||||
* @param mixed $exclude
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function excluding($exclude)
|
||||
{
|
||||
$this->settings['exclude'] = (array) $exclude;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Including data
|
||||
*
|
||||
* @param mixed $include
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function including($include)
|
||||
{
|
||||
$this->settings['include'] = (array) $include;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets process type.
|
||||
*
|
||||
* @param string $type - [insert|update]
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function process(string $type)
|
||||
{
|
||||
$this->settings['process'] = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicate check with insert process
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function duplicateCheck()
|
||||
{
|
||||
$this->settings['duplicateCheck'] = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Database Where Clause
|
||||
*
|
||||
* @param mixed $column
|
||||
* @param string $value = NULL
|
||||
* @param string $logical = 'and'
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function where($column, ?string $value = NULL, string $logical = 'and')
|
||||
{
|
||||
$this->settings['where'] = true;
|
||||
$this->settings['whereValue'] = $value;
|
||||
$this->settings['whereColumn'] = $column;
|
||||
|
||||
Singleton::class('ZN\Database\DB')->where($column, $value, $logical);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines SQL Query
|
||||
*
|
||||
* @param string $query
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function query(string $query)
|
||||
{
|
||||
$this->settings['query'] = $query;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets table
|
||||
*
|
||||
* @param string $table
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function table(string $table)
|
||||
{
|
||||
$this->settings['table'] = $table;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Order
|
||||
*
|
||||
* @param string $type = 'desc'
|
||||
* @param string $flags = 'regular'
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function order(string $type = 'desc', string $flags = 'regular')
|
||||
{
|
||||
$this->settings['order']['type'] = $type;
|
||||
$this->settings['order']['flags'] = $flags;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets attributes
|
||||
*
|
||||
* @param array $attr = []
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function attr(array $attr = [])
|
||||
{
|
||||
$settings = [];
|
||||
|
||||
if( isset($this->settings['attr']) && is_array($this->settings['attr']) )
|
||||
{
|
||||
$settings = $this->settings['attr'];
|
||||
}
|
||||
|
||||
$this->settings['attr'] = array_merge($settings, $attr);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Form Action
|
||||
*
|
||||
* @param string $url = NULL
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function action(?string $url = NULL)
|
||||
{
|
||||
$this->settings['attr']['action'] = IS::url($url) ? $url : Request::getSiteURL($url);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets Form Enctype
|
||||
*
|
||||
* @param string $enctype
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function enctype(string $enctype)
|
||||
{
|
||||
if( isset($this->enctypes[$enctype]) )
|
||||
{
|
||||
$enctype = $this->enctypes[$enctype];
|
||||
}
|
||||
|
||||
$this->_element(__FUNCTION__, $enctype);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets select options
|
||||
*
|
||||
* @param mixed $key
|
||||
* @param string $value = NULL
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function option($key, ?string $value = NULL)
|
||||
{
|
||||
if( is_array($key) )
|
||||
{
|
||||
$this->settings['option'] = $key;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->settings['option'][$key] = $value;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set javascript validation
|
||||
*/
|
||||
protected function setJavascriptValidation($name, $lang, $rule = NULL, $param = [])
|
||||
{
|
||||
$this->getJavascriptValidationFunction[$name] = $function = $name . md5($name);
|
||||
|
||||
$this->validate[] = $rule ?: $lang;
|
||||
|
||||
return $this->onkeyup($function . '(this, ' . Base::suffix(implode(', ', $param), ', ') . '\''.$this->setCustomValidity($lang).'\')')
|
||||
->required();
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected on invalid event pattern
|
||||
*/
|
||||
protected function onInvalidEventPattern($pattern, $key, $check = [], $type = NULL)
|
||||
{
|
||||
$this->validate[] = $type ?: $key;
|
||||
|
||||
return $this->onInvalidEventPatternWithoutValidate($pattern, $key, $check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected on invalid event pattern without validate
|
||||
*/
|
||||
protected function onInvalidEventPatternWithoutValidate($pattern, $key, $check = [])
|
||||
{
|
||||
return $this->required()->pattern($pattern)->onInvalidEventCustomValidity($key, $check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected on invalid event attribute validate
|
||||
*/
|
||||
protected function onInvalidEventAttributeValidate($key, $check = [], $rule = NULL)
|
||||
{
|
||||
$this->validate[] = $rule ?: $key;
|
||||
|
||||
return $this->required()->onInvalidEventCustomValidity($key, $check);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected on invalid event custom validity
|
||||
*/
|
||||
protected function onInvalidEventCustomValidity($key, $check = [])
|
||||
{
|
||||
$this->vMethodMessages .= $this->setCustomValidity($key, $check) . ' ';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get validate method messages
|
||||
*/
|
||||
protected function getVMethodMessages()
|
||||
{
|
||||
if( $this->vMethodMessages !== NULL )
|
||||
{
|
||||
$this->oninvalid('setCustomValidity(\'' . rtrim($this->vMethodMessages) . '\')')->oninput('setCustomValidity(\'\')')->validate(...$this->validate);
|
||||
|
||||
$this->vMethodMessages = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set custom validity
|
||||
*/
|
||||
protected function setCustomValidity($key, $check = [])
|
||||
{
|
||||
$message = '';
|
||||
|
||||
if( is_scalar($key) )
|
||||
{
|
||||
$message = $this->getValidationLangValue($key, $check);
|
||||
}
|
||||
else foreach( $key as $k => $c )
|
||||
{
|
||||
$message .= $this->getValidationLangValue($k, $c) . ' ';
|
||||
}
|
||||
|
||||
return rtrim($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get validation lang value
|
||||
*/
|
||||
protected function getValidationLangValue($key, $check)
|
||||
{
|
||||
$check[':name'] = 'Input';
|
||||
|
||||
return Lang::default('ZN\Validation\ValidationDefaultLanguage')::select('ViewObjects', 'validation:'.$key, $check) ?: $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Postback
|
||||
*/
|
||||
protected function _postback($name, &$default, $type = NULL)
|
||||
{
|
||||
if( isset($this->postback['bool']) && $this->postback['bool'] === true )
|
||||
{
|
||||
$method = ! empty($this->method) ? $this->method : $this->postback['type'];
|
||||
|
||||
$this->postback = [];
|
||||
|
||||
if( $type === 'checkbox' || $type === 'radio' )
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if( $method::$name() === $default )
|
||||
{
|
||||
$this->checked();
|
||||
}
|
||||
else if( $method::all() )
|
||||
{
|
||||
unset($this->settings['attr']['checked']);
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
else
|
||||
{
|
||||
$default = Singleton::class('ZN\Validation\Data')->postBack($name, $method) ?: $default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Validate
|
||||
*/
|
||||
protected function _validate($name, $attrName)
|
||||
{
|
||||
if( ! empty($this->validate) )
|
||||
{
|
||||
$this->validateUsageThisForm = true;
|
||||
|
||||
$session = Singleton::class('ZN\Storage\Session');
|
||||
|
||||
$validate[$name] = $this->validate;
|
||||
$validate[$name]['value'] = $this->settings['attr']['alias'] ?? $attrName;
|
||||
|
||||
$rules = array_merge($session->select('FormValidationRules' . $this->getValidationFormName) ?: [], $validate);
|
||||
|
||||
$session->insert('FormValidationMethod' . $this->getValidationFormName, $this->method);
|
||||
$session->insert('FormValidationRules' . $this->getValidationFormName, $rules);
|
||||
|
||||
$this->validate = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Get Row
|
||||
*/
|
||||
protected function _getrow($type, $value, &$attributes)
|
||||
{
|
||||
if( $row = ($this->settings['getrow'] ?? NULL) )
|
||||
{
|
||||
$rowval = $row->{$attributes['name']} ?? NULL;
|
||||
|
||||
if( $type === 'textarea' || $type === 'select' )
|
||||
{
|
||||
return $value ?: $rowval; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$attributes['value'] = $value ?: $rowval;
|
||||
|
||||
// For radio
|
||||
if( $type === 'radio' && $value == $rowval )
|
||||
{
|
||||
$attributes['checked'] = 'checked'; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
// For checkbox
|
||||
if( $type === 'checkbox' )
|
||||
{
|
||||
// @codeCoverageIgnoreStart
|
||||
if( Json::check($rowval) )
|
||||
{
|
||||
$rowval = json_decode($rowval, true);
|
||||
|
||||
if( in_array($value, $rowval) )
|
||||
{
|
||||
$attributes['checked'] = 'checked';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ! empty($rowval) )
|
||||
{
|
||||
$attributes['checked'] = 'checked';
|
||||
}
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,555 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\IS;
|
||||
use ZN\Base;
|
||||
use ZN\Request;
|
||||
use ZN\Buffering;
|
||||
use ZN\Hypertext\Exception\InvalidArgumentException;
|
||||
|
||||
class Html
|
||||
{
|
||||
use ViewCommonTrait;
|
||||
|
||||
protected $elements =
|
||||
[
|
||||
'multiElement' =>
|
||||
[
|
||||
'html' , 'body', 'head' , 'title' , 'pre' ,
|
||||
'iframe', 'li' , 'strong', 'span',
|
||||
|
||||
'bold' => 'b' , 'italic' => 'em' , 'parag' => 'p',
|
||||
'overline' => 'del', 'overtext' => 'sup', 'underline' => 'u',
|
||||
'undertext' => 'sub'
|
||||
],
|
||||
|
||||
'singleElement' =>
|
||||
[
|
||||
'hr', 'keygen'
|
||||
],
|
||||
|
||||
'mediaContent' =>
|
||||
[
|
||||
'audio', 'video'
|
||||
],
|
||||
|
||||
'media' =>
|
||||
[
|
||||
'embed', 'source'
|
||||
],
|
||||
|
||||
'contentAttribute' =>
|
||||
[
|
||||
'div' , 'canvas' , 'command' , 'datalist', 'details',
|
||||
'dialog', 'figcaption', 'figure' , 'mark' , 'meter' ,
|
||||
'time' , 'summary' , 'progress', 'output' ,
|
||||
],
|
||||
|
||||
'content' =>
|
||||
[
|
||||
'aside' , 'article', 'footer', 'header', 'nav',
|
||||
'section', 'hgroup'
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* Sets ul attributes [5.0.0]
|
||||
*
|
||||
* @param callable $list
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function ul(callable $list, array $attributes = [], $type = 'ul') : string
|
||||
{
|
||||
return $this->_multiElement($type, Buffering\Callback::do($list, [new $this]), $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets ol attributes [5.0.0]
|
||||
*
|
||||
* @param callable $list
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function ol(callable $list, array $attributes = []) : string
|
||||
{
|
||||
return $this->ul($list, $attributes, 'ol');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates form input
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
public function form() : Form
|
||||
{
|
||||
return new Form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates table
|
||||
*
|
||||
* @return Table
|
||||
*/
|
||||
public function table() : Table
|
||||
{
|
||||
return new Table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates list
|
||||
*
|
||||
* @return Lists
|
||||
*/
|
||||
public function list() : Lists
|
||||
{
|
||||
return new Lists;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates image element
|
||||
*
|
||||
* @param string $src
|
||||
* @param int $width
|
||||
* @param int $height = NULL
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function image(string $src, ?int $width = NULL, ?int $height = NULL, array $attributes = []) : string
|
||||
{
|
||||
if( ! IS::url($src) )
|
||||
{
|
||||
$src = Request::getBaseURL($src);
|
||||
}
|
||||
|
||||
$attributes['src'] = $src;
|
||||
|
||||
if( ! empty($width) )
|
||||
{
|
||||
$attributes['width'] = $width;
|
||||
}
|
||||
|
||||
if( ! empty($height) )
|
||||
{
|
||||
$attributes['height'] = $height;
|
||||
}
|
||||
|
||||
if( ! isset($attributes['title']) )
|
||||
{
|
||||
$attributes['title'] = '';
|
||||
}
|
||||
|
||||
if( ! isset($attributes['alt']) )
|
||||
{
|
||||
$attributes['alt'] = '';
|
||||
}
|
||||
|
||||
return $this->_singleElement('img', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates label element
|
||||
*
|
||||
* @param string $for
|
||||
* @param mixed $value = NULL
|
||||
* @param string $form = NULL
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function label(string $for, $value = NULL, ?string $form = NULL, array $attributes = []) : string
|
||||
{
|
||||
if( ! empty($for) )
|
||||
{
|
||||
$attributes['for'] = $for;
|
||||
}
|
||||
|
||||
if( ! empty($form) )
|
||||
{
|
||||
$attributes['form'] = $form;
|
||||
}
|
||||
|
||||
return $this->_multiElement(__FUNCTION__, $value, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates anchor
|
||||
*
|
||||
* @param string $url
|
||||
* @param mixed $value = NULL
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function anchor(string $url, $value = NULL, array $attributes = []) : string
|
||||
{
|
||||
if( $url === ':void' )
|
||||
{
|
||||
$url = 'javascript:void(0);';
|
||||
}
|
||||
elseif( ! IS::url($url) && strpos($url, '#') !== 0 )
|
||||
{
|
||||
$url = Request::getSiteURL($url);
|
||||
}
|
||||
|
||||
$attributes['href'] = $url;
|
||||
|
||||
return $this->_multiElement('a', $value ?? $url, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates button
|
||||
*
|
||||
* @param mixed $value = NULL
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function button($value = NULL, array $attributes = []) : string
|
||||
{
|
||||
$this->settings['attr']['type'] = $this->settings['attr']['type'] ?? 'button';
|
||||
|
||||
return $this->_multiElement('button', $value ?? $url, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates mail to element
|
||||
*
|
||||
* @param string $mail
|
||||
* @param string $value = NULL
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function mailTo(string $mail, ?string $value = NULL, array $attributes = []) : string
|
||||
{
|
||||
if( ! IS::email($mail) )
|
||||
{
|
||||
throw new InvalidArgumentException('Error', 'emailParameter', '1.($mail)');
|
||||
}
|
||||
|
||||
$attributes['href'] = 'mailto:' . $mail;
|
||||
|
||||
return $this->_multiElement('a', $value ?? $mail, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates font elements
|
||||
*
|
||||
* @param mixed $str
|
||||
* @param string $size = NULL
|
||||
* @param string $color = NULL
|
||||
* @param string $face = NULL
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function font($str, ?string $size = NULL, ?string $color = NULL, ?string $face = NULL, array $attributes = []) : string
|
||||
{
|
||||
if( ! empty($size) )
|
||||
{
|
||||
$attributes['size'] = $size;
|
||||
}
|
||||
|
||||
if( ! empty($color) )
|
||||
{
|
||||
$attributes['color'] = $color;
|
||||
}
|
||||
|
||||
if( ! empty($face) )
|
||||
{
|
||||
$attributes['face'] = $face;
|
||||
}
|
||||
|
||||
return $this->_multiElement('font', $str, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates br element
|
||||
*
|
||||
* @param int $count = 1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function br(int $count = 1) : string
|
||||
{
|
||||
return str_repeat($this->_singleElement(__FUNCTION__), $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates script element
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function script(string $path) : string
|
||||
{
|
||||
if( ! IS::url($path) )
|
||||
{
|
||||
$path = Request::getBaseURL(Base::suffix($path, '.js'));
|
||||
}
|
||||
|
||||
$attributes['href'] = $path;
|
||||
$attributes['type'] = 'text/javascript';
|
||||
|
||||
return $this->_singleElement(__FUNCTION__, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates link
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function link(string $path) : string
|
||||
{
|
||||
if( ! IS::url($path) )
|
||||
{
|
||||
$path = Request::getBaseURL(Base::suffix($path, '.css'));
|
||||
}
|
||||
|
||||
$attributes['href'] = $path;
|
||||
$attributes['rel'] = 'stylesheet';
|
||||
$attributes['type'] = 'text/css';
|
||||
|
||||
return $this->_singleElement('link', $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates space
|
||||
*
|
||||
* @param int $count = 4
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function space(int $count = 4) : string
|
||||
{
|
||||
return str_repeat(" ", $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets head element
|
||||
*
|
||||
* @param mixed $str
|
||||
* @param int $type = 3
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function heading($str, int $type = 3, array $attributes = []) : string
|
||||
{
|
||||
return $this->_multiElement('h'.$type, $str, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets multiple element
|
||||
*
|
||||
* @param string $element
|
||||
* @param mixed $str = NULL
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function element(string $element, $str = NULL, array $attributes = []) : string
|
||||
{
|
||||
return $this->_multiElement($element, $str, $attributes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets multiple attributes
|
||||
*
|
||||
* @param mixed $str
|
||||
* @param array $array = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function multiAttr($str, array $array = []) : string
|
||||
{
|
||||
$perm = $this->settings['attr']['perm'] ?? NULL;
|
||||
|
||||
$open = '';
|
||||
$close = '';
|
||||
$att = '';
|
||||
|
||||
|
||||
foreach( $array as $k => $v )
|
||||
{
|
||||
if( ! is_numeric($k) )
|
||||
{
|
||||
$element = $k;
|
||||
|
||||
if( ! is_array($v) )
|
||||
{
|
||||
$att = ' '.$v;
|
||||
}
|
||||
else
|
||||
{
|
||||
$att = $this->attributes($v);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$element = $v;
|
||||
}
|
||||
|
||||
$open .= '<'.$element.$att.'>';
|
||||
$close = '</'.$element.'>'.$close;
|
||||
}
|
||||
|
||||
return $this->_perm($perm, $open.$str.$close);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets meta tag
|
||||
*
|
||||
* @param mixed $name
|
||||
* @param string $content = NULL
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function meta($name, ?string $content = NULL)
|
||||
{
|
||||
if( ! is_array($name) )
|
||||
{
|
||||
$this->outputElement .= $this->_singleMeta($name, $content);
|
||||
}
|
||||
else
|
||||
{
|
||||
$metas = '';
|
||||
|
||||
foreach( $name as $key => $val )
|
||||
{
|
||||
$metas .= $this->_singleMeta($key, $val);
|
||||
}
|
||||
|
||||
$this->outputElement .= $metas;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Content
|
||||
*/
|
||||
protected function _content($html, $type)
|
||||
{
|
||||
$type = strtolower($type ?? '');
|
||||
|
||||
$perm = $this->settings['attr']['perm'] ?? NULL;
|
||||
|
||||
$this->outputElement .= $this->_perm($perm, "<$type>" . $this->stringOrCallback($html) . "</$type>");
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Content Attribute
|
||||
*/
|
||||
protected function _contentAttribute($content, $_attributes, $type)
|
||||
{
|
||||
$type = strtolower($type ?? '');
|
||||
|
||||
$perm = $this->settings['attr']['perm'] ?? NULL;
|
||||
|
||||
$return = '<'.$type.$this->attributes($_attributes).'>'.$this->stringOrCallback($content)."</$type>".EOL;
|
||||
|
||||
$this->outputElement .= $this->_perm($perm, $return);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Media
|
||||
*/
|
||||
protected function _media($src, $_attributes, $type)
|
||||
{
|
||||
$perm = $this->settings['attr']['perm'] ?? NULL;
|
||||
|
||||
$this->outputElement .= $this->_perm($perm, '<'.strtolower($type).' src="'.$src.'"'.$this->attributes($_attributes).'>'.EOL);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Media Content
|
||||
*/
|
||||
protected function _mediaContent($src, $content, $_attributes, $type)
|
||||
{
|
||||
$type = strtolower($type ?? '');
|
||||
|
||||
$perm = $this->settings['attr']['perm'] ?? NULL;
|
||||
|
||||
$this->outputElement .= $this->_perm($perm, '<'.$type.' src="'.$src.'"'.$this->attributes($_attributes).'>'.$this->stringOrCallback($content)."</$type>".EOL);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Element
|
||||
*/
|
||||
protected function _multiElement($element, $str, $attributes = [])
|
||||
{
|
||||
$element = strtolower($element ?? '');
|
||||
|
||||
$perm = $this->settings['attr']['perm'] ?? NULL;
|
||||
|
||||
$this->outputElement .= $this->_perm($perm, '<'.$element.$this->attributes($attributes).'>'.$this->stringOrCallback($str).'</'.$element.'>');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Single Element
|
||||
*/
|
||||
protected function _singleElement($element, $attributes = [])
|
||||
{
|
||||
$perm = $this->settings['attr']['perm'] ?? NULL;
|
||||
|
||||
$this->outputElement .= $this->_perm($perm, '<'.strtolower($element ?? '').$this->attributes($attributes).'>');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Single Meta
|
||||
*/
|
||||
protected function _singleMeta($name, $content)
|
||||
{
|
||||
if( stripos($name, 'http:') === 0 )
|
||||
{
|
||||
$name = ' http-equiv="'.str_ireplace('http:', '', $name).'"';
|
||||
}
|
||||
elseif( stripos($name, 'property:') === 0 )
|
||||
{
|
||||
$name = ' property="'.str_ireplace('property:', '', $name).'"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$name = ' name="'.str_ireplace('name:', '', $name).'"';
|
||||
}
|
||||
|
||||
if( ! empty($content) )
|
||||
{
|
||||
$content = ' content="'.$content.'"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$content = '';
|
||||
}
|
||||
|
||||
return '<meta' . $name . $content . ' />' . EOL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
trait HtmlElementsTrait
|
||||
{
|
||||
/**
|
||||
* Sets aria attribute
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $element
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function aria(string $type, string $element)
|
||||
{
|
||||
$this->settings['attr']['aria-'.$type] = $element;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets data attribute
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $element
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function data(string $type, string $element)
|
||||
{
|
||||
$this->settings['attr']['data-'.$type] = $element;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets ice:repeating attribute
|
||||
*
|
||||
* @param string $element
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function iceRepeating(string $element)
|
||||
{
|
||||
$this->settings['attr']['ice:repeating'] = $element;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets spry attribute
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $element
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function spry(string $type, string $element)
|
||||
{
|
||||
$this->settings['attr']['spry-'.$type] = $element;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets src attribute
|
||||
*
|
||||
* @param string $element
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function source(string $element)
|
||||
{
|
||||
$this->settings['attr']['src'] = $element;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets title attribute
|
||||
*
|
||||
* @param string $element
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function title(string $element)
|
||||
{
|
||||
$this->settings['attr']['title'] = $element;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
abstract class HtmlHelpersAbstract
|
||||
{
|
||||
/**
|
||||
* abstract create
|
||||
*
|
||||
* @param string ...$elements
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
abstract public function create(...$elements) : string;
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Buffering;
|
||||
|
||||
class JQueryBuilder extends BuilderExtends
|
||||
{
|
||||
/**
|
||||
* Protected keeps selector
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $selector;
|
||||
|
||||
/**
|
||||
* Magic call
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameter
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
$this->builder .= '.' . $method . '(';
|
||||
|
||||
foreach( $parameters as $parameter )
|
||||
{
|
||||
if( is_callable($parameter) )
|
||||
{
|
||||
$option = $this->isCallableOption($parameter, 'data');
|
||||
}
|
||||
else
|
||||
{
|
||||
$option = json_encode($parameter);
|
||||
}
|
||||
|
||||
$this->builder .= $option . ', ';
|
||||
}
|
||||
|
||||
$this->builder = rtrim($this->builder, ', ');
|
||||
|
||||
$this->builder .= ')';
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Keeps jquery selector
|
||||
*
|
||||
* @param string $selector
|
||||
*
|
||||
* @return object
|
||||
*/
|
||||
public function selector($selector)
|
||||
{
|
||||
if( is_scalar($selector) )
|
||||
{
|
||||
$this->selector = json_encode($selector);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->selector = Buffering\Callback::do($selector); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected build
|
||||
*/
|
||||
protected function build(string $content)
|
||||
{
|
||||
$string = '$(' . $this->selector . ')' . $content . ';';
|
||||
|
||||
$this->builder = NULL;
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php if( $ZNValidationBetween ?? NULL ): ?>
|
||||
<script>
|
||||
function <?php echo $ZNValidationBetween ?>(element, min, max, message)
|
||||
{
|
||||
var value = Number(element.value);
|
||||
|
||||
if( value < min || value > max || isNaN(value) )
|
||||
{
|
||||
element.setCustomValidity(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
element.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if( $ZNValidationCaptcha ?? NULL ): ?>
|
||||
<script>
|
||||
function <?php echo $ZNValidationCaptcha ?>(element, message)
|
||||
{
|
||||
var value = element.value;
|
||||
|
||||
if( value !== '<?php echo ZN\Singleton::class('ZN\Captcha\Render')->getCode(); ?>' )
|
||||
{
|
||||
element.setCustomValidity(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
element.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if( $ZNValidationAnswer ?? NULL ): ?>
|
||||
<script>
|
||||
function <?php echo $ZNValidationAnswer ?>(element, message)
|
||||
{
|
||||
var value = element.value;
|
||||
|
||||
if( value !== '<?php echo $_SESSION[md5('answerToQuestion')] ?>' )
|
||||
{
|
||||
element.setCustomValidity(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
element.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if( $ZNValidationMatch ?? NULL ): ?>
|
||||
<script>
|
||||
function <?php echo $ZNValidationMatch ?>(element, matchElementName, message)
|
||||
{
|
||||
var value = element.value;
|
||||
|
||||
var matchElementValue = document.getElementsByName(element.form.name)[0].elements[matchElementName].value;
|
||||
|
||||
if( value != matchElementValue )
|
||||
{
|
||||
element.setCustomValidity(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
element.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if( $ZNValidationPhone ?? NULL ): ?>
|
||||
<script>
|
||||
function <?php echo $ZNValidationPhone ?>(element, pattern, message)
|
||||
{
|
||||
var value = element.value;
|
||||
|
||||
if( pattern )
|
||||
{
|
||||
phoneData = pattern.replace(/([^\*])/g, 'key:$1');
|
||||
phoneData = phoneData.replace(/\*/g, '[0-9]');
|
||||
phoneData = phoneData.replace(/key\:/g, '\\');
|
||||
|
||||
phoneData = new RegExp('^' + phoneData + '$');
|
||||
}
|
||||
else
|
||||
{
|
||||
phoneData = /\+*[0-9]{10,14}$/;
|
||||
}
|
||||
|
||||
if( ! value.match(phoneData) )
|
||||
{
|
||||
element.setCustomValidity(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
element.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if( $ZNValidationIdentity ?? NULL ): ?>
|
||||
<script>
|
||||
function <?php echo $ZNValidationIdentity ?>(element, message)
|
||||
{
|
||||
var value = element.value;
|
||||
|
||||
if( value.length !== 11 )
|
||||
{
|
||||
return element.setCustomValidity(message);
|
||||
}
|
||||
|
||||
v0 = Number(value[0]); v1 = Number(value[1]); v2 = Number(value[2]); v3 = Number(value[3]);
|
||||
v4 = Number(value[4]); v5 = Number(value[5]); v6 = Number(value[6]); v7 = Number(value[7]);
|
||||
v8 = Number(value[8]); v9 = Number(value[9]); v10 = Number(value[10]);
|
||||
|
||||
firstNumbers = v0 + v2 + v4 + v6 + v8;
|
||||
secondNumbers = v1 + v3 + v5 + v7;
|
||||
|
||||
numone = firstNumbers * 7;
|
||||
numtwo = secondNumbers * 9;
|
||||
numthree = firstNumbers * 8;
|
||||
|
||||
totalOneAndTwo = numone + numtwo;
|
||||
|
||||
firstLastChar = String(totalOneAndTwo).substr(-1, 1);
|
||||
secondLastChar = String(numthree).substr(-1, 1);
|
||||
|
||||
if( v0 == 0 )
|
||||
{
|
||||
element.setCustomValidity(message);
|
||||
}
|
||||
else if( v9 != firstLastChar )
|
||||
{
|
||||
element.setCustomValidity(message);
|
||||
}
|
||||
else if( v10 != secondLastChar )
|
||||
{
|
||||
element.setCustomValidity(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
element.setCustomValidity('');
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Hypertext\HtmlHelpersAbstract;
|
||||
use ZN\DataTypes\Arrays;
|
||||
use ZN\Base;
|
||||
use ZN\IS;
|
||||
|
||||
class Lists extends HtmlHelpersAbstract
|
||||
{
|
||||
/**
|
||||
* Create"
|
||||
*
|
||||
* @param array ...$elements
|
||||
*/
|
||||
public function create(...$elements) : string
|
||||
{
|
||||
return $this->_element($elements[0], '', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected element
|
||||
*/
|
||||
protected function _element($data, $tab, $start)
|
||||
{
|
||||
static $start;
|
||||
|
||||
$output = '';
|
||||
$attrs = '';
|
||||
$tab = str_repeat("\t", (int) $start);
|
||||
|
||||
if( ! is_array($data) )
|
||||
{
|
||||
return $data.$eof;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach( $data as $k => $v )
|
||||
{
|
||||
if( IS::realNumeric($k) )
|
||||
{
|
||||
$value = $k;
|
||||
$k = 'li';
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = '';
|
||||
}
|
||||
|
||||
$end = Base::prefix(Arrays\GetElement::first(explode(' ', $k)));
|
||||
|
||||
if( ! is_array($v) )
|
||||
{
|
||||
|
||||
$output .= $tab . '<' . $k . '>' . $v . '<' . $end . '>' . EOL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( stripos($k, 'ul') !== 0 && stripos($k, 'ol') !== 0 && $k !== 'li' )
|
||||
{
|
||||
$value = $k;
|
||||
$k = 'li';
|
||||
$end = Base::prefix($k);
|
||||
}
|
||||
else
|
||||
{
|
||||
$value = '';
|
||||
}
|
||||
|
||||
$output .= $tab . '<' . $k . '>' . $value . EOL . $this->_element($v, $tab, $start++) . $tab . '<' . $end . '>' . $tab . EOL;
|
||||
$start--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
trait OutputElements
|
||||
{
|
||||
/**
|
||||
* Protected output element
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $outputElement = NULL;
|
||||
|
||||
/**
|
||||
* Magic to string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
if( $outputElement = $this->outputElement )
|
||||
{
|
||||
$this->outputElement = NULL;
|
||||
|
||||
return $outputElement;
|
||||
}
|
||||
elseif( $this->getBootstrapGridsystem() )
|
||||
{
|
||||
if( is_string($return = $this->createBootstrapGridsystem()) )
|
||||
{
|
||||
return $return;
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<script>
|
||||
function {{$serializerFunction}}(element)
|
||||
{
|
||||
var form = $(element).closest('form');
|
||||
|
||||
if ( form.is(":valid") )
|
||||
{
|
||||
$.ajax
|
||||
({
|
||||
url : '{{ URL::site($serializerUrl) }}',
|
||||
type : 'post',
|
||||
data : form.serialize(),
|
||||
{{ $serializerProperties}}
|
||||
success:function(data)
|
||||
{
|
||||
@if( is_string($serializerSelector) )
|
||||
$('{{$serializerSelector}}').html(data);
|
||||
@elseif( is_callable($serializerSelector) )
|
||||
{{ $serializerSelector() }}
|
||||
@endif
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,28 @@
|
||||
<script>
|
||||
function {{$serializerFunction}}(element)
|
||||
{
|
||||
var form = $(element).closest('form');
|
||||
|
||||
if ( form.is(":valid") )
|
||||
{
|
||||
var value = $(element).val();
|
||||
var name = $(element).attr('name');
|
||||
|
||||
$.ajax
|
||||
({
|
||||
url : '{{ URL::site($serializerUrl) }}',
|
||||
type : 'post',
|
||||
data : {name : value},
|
||||
{{ $serializerProperties}}
|
||||
success:function(data)
|
||||
{
|
||||
@if( is_string($serializerSelector) )
|
||||
$('{{$serializerSelector}}').html(data);
|
||||
@elseif( is_callable($serializerSelector) )
|
||||
{{ $serializerSelector() }}
|
||||
@endif
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,53 @@
|
||||
|
||||
<div id="{{ $carouselId }}" class="carousel slide" data-ride="carousel">
|
||||
|
||||
|
||||
|
||||
@if( isset($carouseIndicators) )
|
||||
{[ $index = 0 ]}
|
||||
<ol class="carousel-indicators">
|
||||
@foreach( $carouselImages as $key => $image )
|
||||
{[ $active = $index === 0 ? ' class="active"' : NULL ]}
|
||||
<li data-target="#{{ $carouselId }}" data-slide-to="{{ $index }}"{{ $active }}></li>
|
||||
{[ $index++ ]}
|
||||
@endforeach
|
||||
</ol>
|
||||
@endif
|
||||
|
||||
{[ $index = 0 ]}
|
||||
<div class="carousel-inner">
|
||||
@foreach( $carouselImages as $key => $image )
|
||||
{[
|
||||
$active = $index === 0 ? ' active' : NULL;
|
||||
|
||||
if( ! is_numeric($key) )
|
||||
{
|
||||
$attr = $image;
|
||||
$image = $key;
|
||||
}
|
||||
else
|
||||
{
|
||||
$attr = NULL;
|
||||
}
|
||||
]}
|
||||
<div class="item{{ $active }}">
|
||||
<img class="{{ $attr['class'] ?? NULL }}" src="{{ URL::base($image) }}" alt="{{ $attr['alt'] ?? ZN\Filesystem::removeExtension(ZN\Datatype::divide($image, '/', -1)) }}">
|
||||
@if( $caption = ($attr['caption'] ?? NULL) )
|
||||
<div class="carousel-caption">
|
||||
<h3>{{$caption[0] ?? NULL}}</h3>
|
||||
<p>{{$caption[1] ?? NULL}}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
{[$index++]}
|
||||
@endforeach
|
||||
</div>
|
||||
<a class="left carousel-control" href="#{{ $carouselId }}" data-slide="prev">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span>
|
||||
<span class="sr-only">{{ $carouselPrevName ?: 'Previous' }}</span>
|
||||
</a>
|
||||
<a class="right carousel-control" href="#{{ $carouselId }}" data-slide="next">
|
||||
<span class="glyphicon glyphicon-chevron-right"></span>
|
||||
<span class="sr-only">{{ $carouselNextName ?: 'Next' }}</span>
|
||||
</a>
|
||||
</div>
|
||||
@@ -0,0 +1,51 @@
|
||||
<div id="{{ $carouselId }}" class="carousel slide" data-ride="carousel">
|
||||
|
||||
@if( isset($carouseIndicators) )
|
||||
{[$index = 0]}
|
||||
<ol class="carousel-indicators">
|
||||
@foreach( $carouselImages as $key => $image )
|
||||
{[
|
||||
$active = $index === 0 ? ' class="active"' : NULL
|
||||
]}
|
||||
<li data-target="#{{ $carouselId }}" data-slide-to="{{$index}}"{{$active}}></li>
|
||||
{[$index++]}
|
||||
@endforeach
|
||||
</ol>
|
||||
@endif
|
||||
|
||||
{[$index = 0]}
|
||||
<div class="carousel-inner">
|
||||
@foreach( $carouselImages as $key => $image )
|
||||
{[
|
||||
$active = $index === 0 ? ' active' : NULL;
|
||||
|
||||
if( ! is_numeric($key) )
|
||||
{
|
||||
$attr = $image;
|
||||
$image = $key;
|
||||
}
|
||||
else
|
||||
{
|
||||
$attr = NULL;
|
||||
}
|
||||
]}
|
||||
<div class="carousel-item{{$active}}">
|
||||
<img class="{{ $attr['class'] ?? NULL }}" src="{{ URL::base($image) }}" alt="{{ $attr['alt'] ?? ZN\Filesystem::removeExtension(ZN\Datatype::divide($image, '/', -1)) }}">
|
||||
@if( $caption = ($attr['caption'] ?? NULL) )
|
||||
<div class="carousel-caption d-none d-md-block">
|
||||
<h5>{{$caption[0] ?? NULL}}</h5>
|
||||
<p>{{$caption[1] ?? NULL}}</p>
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
{[$index++]}
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
<a class="carousel-control-prev" href="#{{ $carouselId }}" data-slide="prev">
|
||||
<span class="carousel-control-prev-icon"></span>
|
||||
</a>
|
||||
<a class="carousel-control-next" href="#{{ $carouselId }}" data-slide="next">
|
||||
<span class="carousel-control-next-icon"></span>
|
||||
</a>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
$("{{ $filterSource }}").on("{{ $filterEvent ?? 'keyup' }}", function() {
|
||||
var value = $(this).val().toLowerCase();
|
||||
$("{{ $filterTarget }}").filter(function() {
|
||||
$(this).toggle($(this).text().toLowerCase().indexOf(value) > -1)
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,11 @@
|
||||
<div class="media border {{ $mediaObjectPadding ?? 'p-3' }}">
|
||||
<img src="{{ URL::base($mediaObjectAvatar) }}" alt="{{ $mediaObjectName }}" class="{{ $mediaObjectAvatarMargin ?? 'mr-3 mt-2' }} rounded-{{ $mediObjectAvatarType ?? 'circle' }} " style="width:{{ $mediaObjectAvatarSize ?? 60 }}px;">
|
||||
<div class="media-body">
|
||||
<h4>{{ $mediaObjectName }} <small><i>{{ $mediaObjectDate }}</i></small></h4>
|
||||
<p>{{ $mediaObjectContent }}</p>
|
||||
|
||||
@if( $mediaObjectReply )
|
||||
{{ $mediaObjectReply }}
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,26 @@
|
||||
<div id="{{ $modalId }}" class="modal fade" role="dialog">
|
||||
<div class="modal-dialog {{ZN\Base::prefix($modalSize, 'modal-')}}">
|
||||
<div class="modal-content">
|
||||
@if( ! empty($modalHeader) )
|
||||
<div class="modal-header">
|
||||
@if( ! empty($modalDismissButton) )
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
@endif
|
||||
<h4 class="modal-title">{{ $modalHeader }}</h4>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if( ! empty($modalBody) )
|
||||
<div class="modal-body">
|
||||
<p>{{ $modalBody }}</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if( ! empty($modalFooter) )
|
||||
<div class="modal-footer">
|
||||
{{ $modalFooter }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,26 @@
|
||||
<div id="{{ $modalId }}" class="modal">
|
||||
<div class="modal-dialog {{ZN\Base::prefix($modalSize, 'modal-')}}">
|
||||
<div class="modal-content">
|
||||
@if( ! empty($modalHeader) )
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title">{{ $modalHeader }}</h4>
|
||||
@if( ! empty($modalDismissButton) )
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if( ! empty($modalBody) )
|
||||
<div class="modal-body">
|
||||
{{ $modalBody }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if( ! empty($modalFooter) )
|
||||
<div class="modal-footer">
|
||||
{{ $modalFooter }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,12 @@
|
||||
<div id="{{ $toastId }}" class="toast" data-autohide="{{ $toastAutoHide }}">
|
||||
<div class="toast-header">
|
||||
{{ $toastHeader }}
|
||||
|
||||
@if( ! empty($toastDismissButton) )
|
||||
<button type="button" class="ml-2 mb-1 close" data-dismiss="toast">×</button>
|
||||
@endif
|
||||
</div>
|
||||
<div class="toast-body">
|
||||
{{ $toastBody }}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Inclusion;
|
||||
use ZN\Buffering\Callback;
|
||||
|
||||
class Script implements TextInterface
|
||||
{
|
||||
/**
|
||||
* tag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $tag = false;
|
||||
|
||||
/**
|
||||
* type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'text/javascript';
|
||||
|
||||
/**
|
||||
* Tag
|
||||
*/
|
||||
public function tag()
|
||||
{
|
||||
$this->tag = true;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compress Javascript codes
|
||||
*
|
||||
* @param callback $script
|
||||
* @param string $encoding = 'normal' - [none|numeric|normal|ascii]
|
||||
* @param bool $fastDecode = true
|
||||
* @param bool $specialChars = false
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function compress(callable $callback, string $encoding = 'normal', bool $fastDecode = true, bool $specialChars = false)
|
||||
{
|
||||
$output = Callback::do($callback);
|
||||
|
||||
$packer = new ScriptPacker($output, $encoding, $fastDecode, $specialChars);
|
||||
|
||||
$pack = $packer->pack();
|
||||
|
||||
if( $this->tag )
|
||||
{
|
||||
$pack = $this->open() . $pack . $this->close();
|
||||
|
||||
$this->tag = false;
|
||||
}
|
||||
|
||||
return $pack;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the [type] property of the [script] tag.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function type(string $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports script libraries.
|
||||
*
|
||||
* @param string ...$libraries
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function library(...$libraries)
|
||||
{
|
||||
Inclusion\Script::use(...$libraries);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the [script] tag.
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function open() : string
|
||||
{
|
||||
$script = '<script type="' . $this->type .'">' . EOL;
|
||||
|
||||
$this->default();
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the [/script] tag.
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function close() : string
|
||||
{
|
||||
$script = '</script>' . EOL;
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* protected default
|
||||
*/
|
||||
protected function default()
|
||||
{
|
||||
$this->type = 'text/javascript';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,694 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
class ScriptPacker
|
||||
{
|
||||
/**
|
||||
* Protected $script
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $script = '';
|
||||
|
||||
/**
|
||||
* Protected $encoding
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $encoding = 62;
|
||||
|
||||
/**
|
||||
* Protected $fastDecode
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $fastDecode = true;
|
||||
|
||||
/**
|
||||
* Protected $specialChars
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $specialChars = false;
|
||||
|
||||
/**
|
||||
* Protected $parsers
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $parsers = [];
|
||||
|
||||
/**
|
||||
* Protected $count
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $count = [];
|
||||
|
||||
/**
|
||||
* Protected $buffer
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $buffer;
|
||||
|
||||
/**
|
||||
* Protected $literalEncoding
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $literalEncoding =
|
||||
[
|
||||
'none' => 0,
|
||||
'numeric' => 10,
|
||||
'normal' => 62,
|
||||
'ascii' => 95
|
||||
];
|
||||
|
||||
/**
|
||||
* Magic method constructor
|
||||
*
|
||||
* @param string $script
|
||||
* @param string $encoding = 'normal' - [none|numeric|normal|ascii]
|
||||
* @param bool $fastDecode = true
|
||||
* @param bool $specialChars = false
|
||||
*/
|
||||
public function __construct(string $script, string $encoding = 'normal', bool $fastDecode = true, bool $specialChars = false)
|
||||
{
|
||||
$this->script = $script . "\n";
|
||||
|
||||
if( isset($this->literalEncoding[$encoding]) )
|
||||
{
|
||||
$encoding = $this->literalEncoding[$encoding];
|
||||
}
|
||||
|
||||
$this->encoding = min((int)$encoding, 95);
|
||||
$this->fastDecode = $fastDecode;
|
||||
$this->specialChars = $specialChars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pack
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function pack()
|
||||
{
|
||||
$this->addParser('basicCompression');
|
||||
|
||||
if( $this->specialChars )
|
||||
{
|
||||
$this->addParser('encodeSpecialChars');
|
||||
}
|
||||
|
||||
if( $this->encoding )
|
||||
{
|
||||
$this->addParser('encodeKeywords');
|
||||
}
|
||||
|
||||
return $this->packing($this->script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected packing
|
||||
*/
|
||||
protected function packing($script)
|
||||
{
|
||||
for( $i = 0; isset($this->parsers[$i]); $i++ )
|
||||
{
|
||||
$script = call_user_func(array(&$this,$this->parsers[$i]), $script);
|
||||
}
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected add parser
|
||||
*/
|
||||
protected function addParser($parser)
|
||||
{
|
||||
$this->parsers[] = $parser;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected basic compression
|
||||
*
|
||||
* zero encoding - just removal of white space and comments
|
||||
*/
|
||||
protected function basicCompression($script)
|
||||
{
|
||||
$parser = new ScriptParser();
|
||||
|
||||
# make safe
|
||||
$parser->escapeChar = '\\';
|
||||
|
||||
# protect strings
|
||||
$parser->add('/\'[^\'\\n\\r]*\'/', '$1');
|
||||
$parser->add('/"[^"\\n\\r]*"/', '$1');
|
||||
|
||||
# remove comments
|
||||
$parser->add('/\\/\\/[^\\n\\r]*[\\n\\r]/', ' ');
|
||||
$parser->add('/\\/\\*[^*]*\\*+([^\\/][^*]*\\*+)*\\//', ' ');
|
||||
|
||||
# protect regular expressions
|
||||
$parser->add('/\\s+(\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?)/', '$2'); // IGNORE
|
||||
$parser->add('/[^\\w\\x24\\/\'"*)\\?:]\\/[^\\/\\n\\r\\*][^\\/\\n\\r]*\\/g?i?/', '$1');
|
||||
|
||||
# remove: ;;; doSomething();
|
||||
if( $this->specialChars )
|
||||
{
|
||||
$parser->add('/;;;[^\\n\\r]+[\\n\\r]/');
|
||||
}
|
||||
|
||||
# remove redundant semi-colons
|
||||
$parser->add('/\\(;;\\)/', '$1'); # protect for (;;) loops
|
||||
$parser->add('/;+\\s*([};])/', '$2');
|
||||
|
||||
# apply the above
|
||||
$script = $parser->exec($script);
|
||||
|
||||
# remove white-space
|
||||
$parser->add('/(\\b|\\x24)\\s+(\\b|\\x24)/', '$2 $3');
|
||||
$parser->add('/([+\\-])\\s+([+\\-])/', '$2 $3');
|
||||
$parser->add('/\\s+/', '');
|
||||
|
||||
return $parser->exec($script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected encode special chars
|
||||
*/
|
||||
protected function encodeSpecialChars($script)
|
||||
{
|
||||
$parser = new ScriptParser();
|
||||
|
||||
# replace: $name -> n, $$name -> na
|
||||
$parser->add('/((\\x24+)([a-zA-Z$_]+))(\\d*)/', ['fn' => 'replaceName']);
|
||||
|
||||
# replace: _name -> _0, double-underscore (__name) is ignored
|
||||
$regexp = '/\\b_[A-Za-z\\d]\\w*/';
|
||||
|
||||
# build the word list
|
||||
$keywords = $this->analyze($script, $regexp, 'encodePrivate');
|
||||
|
||||
# quick ref
|
||||
$encoded = $keywords['encoded'];
|
||||
|
||||
# encode
|
||||
$parser->add($regexp, ['fn' => 'replaceEncoded', 'data' => $encoded]);
|
||||
|
||||
return $parser->exec($script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected encode keywords
|
||||
*/
|
||||
protected function encodeKeywords($script)
|
||||
{
|
||||
# escape high-ascii values already in the script (i.e. in strings)
|
||||
if( $this->encoding > 62 )
|
||||
{
|
||||
$script = $this->escape95($script); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
# create the parser
|
||||
$parser = new ScriptParser();
|
||||
|
||||
$encode = $this->getEncoder($this->encoding);
|
||||
|
||||
# for high-ascii, don't encode single character low-ascii
|
||||
$regexp = $this->encoding > 62 ? '/\\w\\w+/' : '/\\w+/';
|
||||
|
||||
# build the word list
|
||||
$keywords = $this->analyze($script, $regexp, $encode);
|
||||
$encoded = $keywords['encoded'];
|
||||
|
||||
# encode
|
||||
$parser->add($regexp, ['fn' => 'replaceEncoded', 'data' => $encoded]);
|
||||
|
||||
if( empty($script) )
|
||||
{
|
||||
return $script; // @codeCoverageIgnore
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->bootstrap($parser->exec($script), $keywords);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected analyze
|
||||
*/
|
||||
protected function analyze($script, $regexp, $encode)
|
||||
{
|
||||
# analyse
|
||||
# retreive all words in the script
|
||||
$all = [];
|
||||
|
||||
preg_match_all($regexp, $script, $all);
|
||||
|
||||
$_sorted = []; # list of words sorted by frequency
|
||||
$_encoded = []; # dictionary of word->encoding
|
||||
$_protected = []; # instances of "protected" words
|
||||
|
||||
$all = $all[0]; # simulate the javascript comportement of global match
|
||||
|
||||
if( ! empty($all) )
|
||||
{
|
||||
$unsorted = []; # same list, not sorted
|
||||
$protected = []; # "protected" words (dictionary of word->"word")
|
||||
$value = []; # dictionary of charCode->encoding (eg. 256->ff)
|
||||
|
||||
$this->count = []; # word->count
|
||||
|
||||
$i = count($all); $j = 0; # $word = null;
|
||||
|
||||
# count the occurrences - used for sorting later
|
||||
do
|
||||
{
|
||||
--$i;
|
||||
$word = '$' . $all[$i];
|
||||
|
||||
if( ! isset($this->count[$word]) )
|
||||
{
|
||||
$this->count[$word] = 0;
|
||||
|
||||
$unsorted[$j] = $word;
|
||||
|
||||
# make a dictionary of all of the protected words in this script
|
||||
# these are words that might be mistaken for encoding
|
||||
# if (is_string($encode) && method_exists($this, $encode) )
|
||||
|
||||
$values[$j] = call_user_func([&$this, $encode], $j);
|
||||
|
||||
$protected['$' . $values[$j]] = $j++;
|
||||
}
|
||||
|
||||
# increment the word counter
|
||||
$this->count[$word]++;
|
||||
|
||||
} while ($i > 0);
|
||||
|
||||
# prepare to sort the word list, first we must protect
|
||||
# words that are also used as codes. we assign them a code
|
||||
# equivalent to the word itself.
|
||||
# e.g. if "do" falls within our encoding range
|
||||
# then we store keywords["do"] = "do";
|
||||
# this avoids problems when decoding
|
||||
$i = count($unsorted);
|
||||
|
||||
do
|
||||
{
|
||||
$word = $unsorted[--$i];
|
||||
|
||||
// @codeCoverageIgnoreStart
|
||||
if( isset($protected[$word]) )
|
||||
{
|
||||
$_sorted[$protected[$word]] = substr($word, 1);
|
||||
$_protected[$protected[$word]] = true;
|
||||
|
||||
$this->count[$word] = 0;
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
|
||||
} while( $i );
|
||||
|
||||
# sort the words by frequency
|
||||
# Note: the javascript and php version of sort can be different :
|
||||
# in php manual, usort :
|
||||
# " If two members compare as equal,
|
||||
# their order in the sorted array is undefined."
|
||||
# so the final packed script is different of the Dean's javascript version
|
||||
# but equivalent.
|
||||
# the ECMAscript standard does not guarantee this behaviour,
|
||||
# and thus not all browsers (e.g. Mozilla versions dating back to at
|
||||
# least 2003) respect this.
|
||||
usort($unsorted, [&$this, 'sortWords']);
|
||||
|
||||
$j = 0;
|
||||
|
||||
# because there are "protected" words in the list
|
||||
# we must add the sorted words around them
|
||||
do
|
||||
{
|
||||
if( ! isset($_sorted[$i]) )
|
||||
{
|
||||
$_sorted[$i] = substr($unsorted[$j++], 1);
|
||||
}
|
||||
|
||||
$_encoded[$_sorted[$i]] = $values[$i];
|
||||
|
||||
} while( ++$i < count($unsorted) );
|
||||
}
|
||||
|
||||
return
|
||||
[
|
||||
'sorted' => $_sorted,
|
||||
'encoded' => $_encoded,
|
||||
'protected' => $_protected
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected sort words
|
||||
*/
|
||||
protected function sortWords($match1, $match2)
|
||||
{
|
||||
return $this->count[$match2] - $this->count[$match1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected bootstrap
|
||||
*
|
||||
* build the boot function used for loading and decoding
|
||||
*/
|
||||
protected function bootstrap($packed, $keywords)
|
||||
{
|
||||
$ENCODE = $this->safeRegExp('$encode\\($count\\)');
|
||||
|
||||
# $packed: the packed script
|
||||
$packed = "'" . $this->escape($packed) . "'";
|
||||
|
||||
# $ascii: base for encoding
|
||||
$ascii = min(count($keywords['sorted']), $this->encoding);
|
||||
|
||||
if( $ascii === 0 )
|
||||
{
|
||||
$ascii = 1; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
# $count: number of words contained in the script
|
||||
$count = count($keywords['sorted']);
|
||||
|
||||
# $keywords: list of words contained in the script
|
||||
foreach( $keywords['protected'] as $i => $value )
|
||||
{
|
||||
$keywords['sorted'][$i] = ''; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
# convert from a string to an array
|
||||
ksort($keywords['sorted']);
|
||||
|
||||
$keywords = "'" . implode('|',$keywords['sorted']) . "'.split('|')";
|
||||
|
||||
$encode = ($this->encoding > 62) ? 'encode95' : $this->getEncoder($ascii);
|
||||
$encode = $this->getJSFunction($encode);
|
||||
$encode = preg_replace('/_encoding/','$ascii', $encode);
|
||||
$encode = preg_replace('/arguments\\.callee/','$encode', $encode);
|
||||
$inline = '\\$count' . ($ascii > 10 ? '.toString(\\$ascii)' : '');
|
||||
|
||||
# $decode: code snippet to speed up decoding
|
||||
if( $this->fastDecode )
|
||||
{
|
||||
# create the decoder
|
||||
$decode = $this->getJSFunction('_decodeBody');
|
||||
|
||||
if( $this->encoding > 62 )
|
||||
{
|
||||
$decode = preg_replace('/\\\\w/', '[\\xa1-\\xff]', $decode); // @codeCoverageIgnore
|
||||
}
|
||||
# perform the encoding inline for lower ascii values
|
||||
elseif( $ascii < 36 )
|
||||
{
|
||||
$decode = preg_replace($ENCODE, $inline, $decode);
|
||||
}
|
||||
|
||||
# special case: when $count==0 there are no keywords. I want to keep
|
||||
# the basic shape of the unpacking funcion so i'll frig the code...
|
||||
if( $count === 0 )
|
||||
{
|
||||
$decode = preg_replace($this->safeRegExp('($count)\\s*=\\s*1'), '$1=0', $decode, 1); // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
|
||||
# boot function
|
||||
$unpack = $this->getJSFunction('_unpack');
|
||||
|
||||
if( $this->fastDecode )
|
||||
{
|
||||
# insert the decoder
|
||||
$this->buffer = $decode;
|
||||
|
||||
$unpack = preg_replace_callback('/\\{/', [&$this, 'insertFastDecode'], $unpack, 1);
|
||||
}
|
||||
|
||||
$unpack = preg_replace('/"/', "'", $unpack);
|
||||
|
||||
if( $this->encoding > 62 )
|
||||
{
|
||||
# high-ascii
|
||||
# get rid of the word-boundaries for regexp matches
|
||||
$unpack = preg_replace('/\'\\\\\\\\b\'\s*\\+|\\+\s*\'\\\\\\\\b\'/', '', $unpack); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
if( $ascii > 36 || $this->encoding > 62 || $this->fastDecode )
|
||||
{
|
||||
# insert the encode function
|
||||
$this->buffer = $encode;
|
||||
$unpack = preg_replace_callback('/\\{/', [&$this, 'insertFastEncode'], $unpack, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
# perform the encoding inline
|
||||
$unpack = preg_replace($ENCODE, $inline, $unpack); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
# pack the boot function too
|
||||
$unpackPacker = new ScriptPacker($unpack, 0, false, true);
|
||||
$unpack = $unpackPacker->pack();
|
||||
|
||||
# arguments
|
||||
$params = [$packed, $ascii, $count, $keywords];
|
||||
|
||||
if( $this->fastDecode )
|
||||
{
|
||||
$params[] = 0;
|
||||
$params[] = '{}';
|
||||
}
|
||||
|
||||
$params = implode(',', $params);
|
||||
|
||||
# the whole thing
|
||||
return 'eval(' . $unpack . '(' . $params . "))\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected insert fast decode
|
||||
*/
|
||||
protected function insertFastDecode($match)
|
||||
{
|
||||
return '{' . $this->buffer . ';';
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected insert fast encode
|
||||
*/
|
||||
protected function insertFastEncode($match)
|
||||
{
|
||||
return '{$encode=' . $this->buffer . ';';
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get encoder
|
||||
*/
|
||||
protected function getEncoder($ascii)
|
||||
{
|
||||
return $ascii > 10 ?
|
||||
$ascii > 36 ?
|
||||
$ascii > 62 ? 'encode95' : 'encode62' : 'encode36' : 'encode10';
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected encode 10
|
||||
*
|
||||
* zero encoding
|
||||
* characters: 0123456789
|
||||
*/
|
||||
protected function encode10($charCode)
|
||||
{
|
||||
return $charCode; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected encode 36
|
||||
*
|
||||
* inherent base36 support
|
||||
* characters: 0123456789abcdefghijklmnopqrstuvwxyz
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function encode36($charCode)
|
||||
{
|
||||
return base_convert($charCode, 10, 36);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected encode 62
|
||||
*
|
||||
* hitch a ride on base36 and add the upper case alpha characters
|
||||
* characters: 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
*
|
||||
*/
|
||||
protected function encode62($charCode)
|
||||
{
|
||||
$res = '';
|
||||
|
||||
if( $charCode >= $this->encoding )
|
||||
{
|
||||
$res = $this->encode62((int)($charCode / $this->encoding)); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$charCode = $charCode % $this->encoding;
|
||||
|
||||
if( $charCode > 35 )
|
||||
{
|
||||
return $res . chr($charCode + 29); // @codeCoverageIgnore
|
||||
}
|
||||
else
|
||||
{
|
||||
return $res . base_convert($charCode, 10, 36);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected encode 95
|
||||
*
|
||||
* use high-ascii values
|
||||
* characters: ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþ
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function encode95($charCode)
|
||||
{
|
||||
$res = '';
|
||||
|
||||
if( $charCode >= $this->encoding )
|
||||
{
|
||||
$res = $this->encode95($charCode / $this->encoding);
|
||||
}
|
||||
|
||||
return $res . chr(($charCode % $this->encoding) + 161);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected safe regex expressions
|
||||
*/
|
||||
protected function safeRegExp($string)
|
||||
{
|
||||
return '/'.preg_replace('/\$/', '\\\$', $string).'/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected encode private
|
||||
*/
|
||||
protected function encodePrivate($charCode)
|
||||
{
|
||||
return "_" . $charCode; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected escape
|
||||
*
|
||||
* protect characters used by the parser
|
||||
*/
|
||||
protected function escape($script)
|
||||
{
|
||||
return preg_replace('/([\\\\\'])/', '\\\$1', $script);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected escape95
|
||||
*
|
||||
* protect high-ascii characters already in the script
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function escape95($script)
|
||||
{
|
||||
return preg_replace_callback
|
||||
(
|
||||
'/[\\xa1-\\xff]/',
|
||||
[&$this, 'escape95Bis'],
|
||||
$script
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected escape 95 bis
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function escape95Bis($match)
|
||||
{
|
||||
return '\x'.((string)dechex(ord($match)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get javascdript function
|
||||
*/
|
||||
protected function getJSFunction($aName)
|
||||
{
|
||||
if( defined($jsFunction = 'self::JSFUNCTION' . $aName) )
|
||||
{
|
||||
return constant($jsFunction);
|
||||
}
|
||||
|
||||
return ''; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
const JSFUNCTION_unpack =
|
||||
'function($packed, $ascii, $count, $keywords, $encode, $decode) {
|
||||
while ($count--) {
|
||||
if ($keywords[$count]) {
|
||||
$packed = $packed.replace(new RegExp(\'\\\\b\' + $encode($count) + \'\\\\b\', \'g\'), $keywords[$count]);
|
||||
}
|
||||
}
|
||||
return $packed;
|
||||
}';
|
||||
|
||||
const JSFUNCTION_decodeBody =
|
||||
' if (!\'\'.replace(/^/, String)) {
|
||||
// decode all the values we need
|
||||
while ($count--) {
|
||||
$decode[$encode($count)] = $keywords[$count] || $encode($count);
|
||||
}
|
||||
// global replacement function
|
||||
$keywords = [function ($encoded) {return $decode[$encoded]}];
|
||||
// generic match
|
||||
$encode = function () {return \'\\\\w+\'};
|
||||
// reset the loop counter - we are now doing a global replace
|
||||
$count = 1;
|
||||
}
|
||||
';
|
||||
|
||||
const JSFUNCTIONencode10 =
|
||||
'function($charCode) {
|
||||
return $charCode;
|
||||
}';
|
||||
|
||||
const JSFUNCTIONencode36 =
|
||||
'function($charCode) {
|
||||
return $charCode.toString(36);
|
||||
}';
|
||||
|
||||
const JSFUNCTIONencode62 =
|
||||
'function($charCode) {
|
||||
return ($charCode < _encoding ? \'\' : arguments.callee(parseInt($charCode / _encoding))) +
|
||||
(($charCode = $charCode % _encoding) > 35 ? String.fromCharCode($charCode + 29) : $charCode.toString(36));
|
||||
}';
|
||||
|
||||
const JSFUNCTIONencode95 =
|
||||
'function($charCode) {
|
||||
return ($charCode < _encoding ? \'\' : arguments.callee($charCode / _encoding)) +
|
||||
String.fromCharCode($charCode % _encoding + 161);
|
||||
}';
|
||||
|
||||
}
|
||||
@@ -0,0 +1,381 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
class ScriptParser
|
||||
{
|
||||
/**
|
||||
* Ignore Case
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $ignoreCase = false;
|
||||
|
||||
/**
|
||||
* Escape Character
|
||||
*/
|
||||
public $escapeChar = '';
|
||||
|
||||
/**
|
||||
* EXPRESSION
|
||||
*
|
||||
* @const int
|
||||
*/
|
||||
const EXPRESSION = 0;
|
||||
|
||||
/**
|
||||
* REPLACEMENT
|
||||
*
|
||||
* @const int
|
||||
*/
|
||||
const REPLACEMENT = 1;
|
||||
|
||||
/**
|
||||
* LENGTH
|
||||
*
|
||||
* @const int
|
||||
*/
|
||||
const LENGTH = 2;
|
||||
|
||||
/**
|
||||
* Protected groups
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $groups = '/\\(/';//g
|
||||
|
||||
/**
|
||||
* Protected subreplace
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $subreplace = '/\\$\\d/';
|
||||
|
||||
/**
|
||||
* Protected indexed
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $indexed = '/^\\$\\d+$/';
|
||||
|
||||
/**
|
||||
* Protected trim
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $trim = '/([\'"])\\1\\.(.*)\\.\\1\\1$/';
|
||||
|
||||
/**
|
||||
* Protected escape
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $escape = '/\\\./';//g
|
||||
|
||||
/**
|
||||
* Protected quote
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $quote = '/\'/';
|
||||
|
||||
/**
|
||||
* Protected deleted
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $deleted = '/\\x01[^\\x01]*\\x01/';//g
|
||||
|
||||
/**
|
||||
* Protected escaped characters
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $escaped = [];
|
||||
|
||||
/**
|
||||
* Protected patterns stored by index
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $patterns = [];
|
||||
|
||||
/**
|
||||
* Protected buffer
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $buffer;
|
||||
|
||||
/**
|
||||
* add
|
||||
*
|
||||
* @param string $expression
|
||||
* @param string $replacement
|
||||
*/
|
||||
public function add($expression, $replacement = '')
|
||||
{
|
||||
# count the number of sub-expressions
|
||||
# add one because each pattern is itself a sub-expression
|
||||
$length = 1 + preg_match_all($this->groups, $this->internalEscape((string)$expression), $out);
|
||||
|
||||
# treat only strings $replacement
|
||||
if( is_string($replacement) )
|
||||
{
|
||||
# does the pattern deal with sub-expressions?
|
||||
if( preg_match($this->subreplace, $replacement) )
|
||||
{
|
||||
# a simple lookup? (e.g. "$2")
|
||||
if( preg_match($this->indexed, $replacement) )
|
||||
{
|
||||
# store the index (used for fast retrieval of matched strings)
|
||||
$replacement = (int)(substr($replacement, 1)) - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
# a complicated lookup (e.g. "Hello $2 $1")
|
||||
# build a function to do the lookup
|
||||
|
||||
$quote = preg_match($this->quote, $this->internalEscape($replacement)) ? '"' : "'";
|
||||
|
||||
$replacement =
|
||||
[
|
||||
'fn' => 'backReferences',
|
||||
'data' =>
|
||||
[
|
||||
'replacement' => $replacement,
|
||||
'length' => $length,
|
||||
'quote' => $quote
|
||||
]
|
||||
];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# pass the modified arguments
|
||||
$this->adding($expression ?: '/^$/', $replacement, $length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exec
|
||||
*
|
||||
* @param string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function exec($string)
|
||||
{
|
||||
# execute the global replacement
|
||||
$this->escaped = [];
|
||||
|
||||
# simulate the _patterns.toSTring of Dean
|
||||
$regexp = '/';
|
||||
|
||||
foreach( $this->patterns as $reg )
|
||||
{
|
||||
$regexp .= '(' . substr($reg[self::EXPRESSION], 1, -1) . ')|';
|
||||
}
|
||||
|
||||
$regexp = substr($regexp, 0, -1) . '/';
|
||||
$regexp.= ($this->ignoreCase) ? 'i' : '';
|
||||
|
||||
$string = $this->escape($string, $this->escapeChar);
|
||||
$string = preg_replace_callback($regexp, [&$this, 'replacement'], $string);
|
||||
$string = $this->unescape($string, $this->escapeChar);
|
||||
|
||||
return preg_replace($this->deleted, '', $string);
|
||||
}
|
||||
|
||||
/**
|
||||
* reset
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
# clear the patterns collection so that this object may be re-used
|
||||
$this->patterns = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected adding
|
||||
*
|
||||
* create and add a new pattern to the patterns collection
|
||||
*/
|
||||
protected function adding()
|
||||
{
|
||||
$arguments = func_get_args();
|
||||
$this->patterns[] = $arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected replacemenet
|
||||
*
|
||||
* this is the global replace function (it's quite complicated)
|
||||
*/
|
||||
protected function replacement($arguments)
|
||||
{
|
||||
if( empty($arguments) )
|
||||
{
|
||||
return ''; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$i = 1; $j = 0;
|
||||
|
||||
# loop through the patterns
|
||||
while( isset($this->patterns[$j]) )
|
||||
{
|
||||
$pattern = $this->patterns[$j++];
|
||||
|
||||
# do we have a result?
|
||||
if( isset($arguments[$i]) && ($arguments[$i] != '') )
|
||||
{
|
||||
$replacement = $pattern[self::REPLACEMENT];
|
||||
|
||||
if( is_array($replacement) && isset($replacement['fn']) )
|
||||
{
|
||||
if( isset($replacement['data']) )
|
||||
{
|
||||
$this->buffer = $replacement['data'];
|
||||
}
|
||||
|
||||
return call_user_func([&$this, $replacement['fn']], $arguments, $i);
|
||||
|
||||
}
|
||||
elseif( is_int($replacement) )
|
||||
{
|
||||
return $arguments[$replacement + $i];
|
||||
|
||||
}
|
||||
|
||||
$delete = ($this->escapeChar == '' || strpos($arguments[$i], $this->escapeChar) === false) ? '' : "\x01" . $arguments[$i] . "\x01";
|
||||
|
||||
return $delete . $replacement;
|
||||
|
||||
# skip over references to sub-expressions
|
||||
}
|
||||
else
|
||||
{
|
||||
$i += $pattern[self::LENGTH];
|
||||
}
|
||||
}
|
||||
|
||||
return ''; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected back references
|
||||
*/
|
||||
protected function backReferences($match, $offset)
|
||||
{
|
||||
$replacement = $this->buffer['replacement'];
|
||||
$quote = $this->buffer['quote'];
|
||||
$i = $this->buffer['length'];
|
||||
|
||||
while( $i )
|
||||
{
|
||||
$replacement = str_replace('$'.$i--, $match[$offset + $i] ?? '', $replacement ?? '');
|
||||
}
|
||||
|
||||
return $replacement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected replace name
|
||||
*/
|
||||
protected function replaceName($match, $offset)
|
||||
{
|
||||
$length = strlen($match[$offset + 2] ?? '');
|
||||
$start = $length - max($length - strlen($match[$offset + 3] ?? ''), 0);
|
||||
|
||||
return substr($match[$offset + 1] ?? '', $start, $length) . ($match[$offset + 4] ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected replace encoded
|
||||
*/
|
||||
protected function replaceEncoded($match, $offset)
|
||||
{
|
||||
return $this->buffer[$match[$offset]];
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected escape
|
||||
*
|
||||
* encode escaped characters
|
||||
*/
|
||||
protected function escape($string, $escapeChar)
|
||||
{
|
||||
if( $escapeChar )
|
||||
{
|
||||
$this->buffer = $escapeChar;
|
||||
|
||||
return preg_replace_callback('/\\' . $escapeChar . '(.)' .'/', [&$this, 'escapeBis'], $string);
|
||||
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected escape bis
|
||||
*/
|
||||
protected function escapeBis($match)
|
||||
{
|
||||
$this->escaped[] = $match[1];
|
||||
|
||||
return $this->buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected unescape
|
||||
*
|
||||
* decode escaped characters
|
||||
*/
|
||||
protected function unescape($string, $escapeChar)
|
||||
{
|
||||
if( $escapeChar )
|
||||
{
|
||||
$regexp = '/'.'\\'.$escapeChar.'/';
|
||||
$this->buffer = ['escapeChar'=> $escapeChar, 'i' => 0];
|
||||
|
||||
return preg_replace_callback($regexp, [&$this, 'unescapeBis'], $string);
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected unescape bis
|
||||
*/
|
||||
protected function unescapeBis()
|
||||
{
|
||||
if( isset($this->escaped[$this->buffer['i']]) && $this->escaped[$this->buffer['i']] != '' )
|
||||
{
|
||||
$temp = $this->escaped[$this->buffer['i']];
|
||||
}
|
||||
else
|
||||
{
|
||||
$temp = ''; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$this->buffer['i']++;
|
||||
|
||||
return $this->buffer['escapeChar'] . $temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected internal escape
|
||||
*/
|
||||
protected function internalEscape($string)
|
||||
{
|
||||
return preg_replace($this->escape, '', $string);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Singleton;
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
class Sheet
|
||||
{
|
||||
/**
|
||||
* selector
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $selector = 'this';
|
||||
|
||||
/**
|
||||
* attr
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attr;
|
||||
|
||||
/**
|
||||
* tag
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $tag = false;
|
||||
|
||||
/**
|
||||
* Magic construct
|
||||
*
|
||||
* @param bool $tag = false
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct($tag = false)
|
||||
{
|
||||
$this->tag = $tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets attributes.
|
||||
*
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function attr(array $attributes)
|
||||
{
|
||||
$this->attr = $this->attrCreator($attributes);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets selector.
|
||||
*
|
||||
* @param string $selector
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function selector(string $selector)
|
||||
{
|
||||
$this->selector = $selector;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates element.
|
||||
*
|
||||
* @param string ...$args
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function create(...$args) : string
|
||||
{
|
||||
$combineTransitions = $args;
|
||||
|
||||
$str = $this->selector . '{';
|
||||
|
||||
if( ! empty($this->attr) )
|
||||
{
|
||||
$str .= EOL . $this->attr . EOL;
|
||||
}
|
||||
|
||||
if( ! empty($combineTransitions) ) foreach( $combineTransitions as $transition )
|
||||
{
|
||||
$str .= $transition;
|
||||
}
|
||||
|
||||
$str .= '}' . EOL;
|
||||
|
||||
return $this->tagCreator($str);
|
||||
}
|
||||
|
||||
/**
|
||||
* protected tag
|
||||
*
|
||||
* @param string $code
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function tagCreator($code)
|
||||
{
|
||||
if( $this->tag === true )
|
||||
{
|
||||
$style = Singleton::class('ZN\Hypertext\Style');
|
||||
|
||||
return $style->open() . $code . $style->close();
|
||||
}
|
||||
|
||||
$this->defaultVariables();
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* protected attr
|
||||
*
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function attrCreator($attributes = [])
|
||||
{
|
||||
$attribute = '';
|
||||
|
||||
if( is_array($attributes) )
|
||||
{
|
||||
foreach( $attributes as $key => $values )
|
||||
{
|
||||
if( is_numeric($key) )
|
||||
{
|
||||
$key = $values;
|
||||
}
|
||||
|
||||
$attribute .= ' ' . $key . ':' . $values . ';';
|
||||
}
|
||||
}
|
||||
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* protected default variables
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function defaultVariables()
|
||||
{
|
||||
$this->attr = NULL;
|
||||
$this->selector = 'this';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Inclusion;
|
||||
|
||||
class Style implements TextInterface
|
||||
{
|
||||
/**
|
||||
* type
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $type = 'text/css';
|
||||
|
||||
/**
|
||||
* Sets the [type] property of the [script] tag.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function type(string $type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports script libraries.
|
||||
*
|
||||
* @param string ...$libraries
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function library(...$libraries)
|
||||
{
|
||||
Inclusion\Style::use(...$libraries);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the [script] tag.
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function open() : string
|
||||
{
|
||||
$script = '<style type="' . $this->type . '">' . EOL;
|
||||
|
||||
$this->defaultVariables();
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the [/script] tag.
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function close() : string
|
||||
{
|
||||
$script = '</style>' . EOL;
|
||||
|
||||
return $script;
|
||||
}
|
||||
|
||||
/**
|
||||
* protected default variables
|
||||
*/
|
||||
protected function defaultVariables()
|
||||
{
|
||||
$this->type = 'text/css';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,217 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Singleton;
|
||||
use ZN\Hypertext\HtmlHelpersAbstract;
|
||||
|
||||
class Table extends HtmlHelpersAbstract
|
||||
{
|
||||
/**
|
||||
* Keeps attributes
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $attr = [];
|
||||
|
||||
/**
|
||||
* Keeps html class
|
||||
*/
|
||||
protected $html;
|
||||
|
||||
/**
|
||||
* Magic Call
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
*
|
||||
* @return Table
|
||||
*/
|
||||
public function __call($method, $parameters)
|
||||
{
|
||||
$method = strtolower($method);
|
||||
|
||||
$this->attr[$method] = $parameters[0] ?? NULL;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->html = Singleton::class('ZN\Hypertext\Html');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets attributes
|
||||
*
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Table
|
||||
*/
|
||||
public function attr(array $attributes) : Table
|
||||
{
|
||||
foreach( $attributes as $att => $val )
|
||||
{
|
||||
$this->attr[$att] = $val;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets table cell
|
||||
*
|
||||
* @param int $spacing
|
||||
* @param int $padding
|
||||
*
|
||||
* @return Table
|
||||
*/
|
||||
public function cell(int $spacing, int $padding) : Table
|
||||
{
|
||||
$this->attr['cellspacing'] = $spacing;
|
||||
$this->attr['cellpadding'] = $padding;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets table border
|
||||
*
|
||||
* @param int $border
|
||||
* @param string $color = NULL
|
||||
*
|
||||
* @return Table
|
||||
*/
|
||||
public function border(int $border, ?string $color = NULL) : Table
|
||||
{
|
||||
$this->attr['border'] = $border;
|
||||
|
||||
if( ! empty($color) )
|
||||
{
|
||||
$this->attr['bordercolor'] = $color;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets table size
|
||||
*
|
||||
* @param int $width
|
||||
* @param int $height
|
||||
*
|
||||
* @return Table
|
||||
*/
|
||||
public function size(int $width, int $height) : Table
|
||||
{
|
||||
$this->attr['width'] = $width;
|
||||
$this->attr['height'] = $height;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets table style attribute
|
||||
*
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return Table
|
||||
*/
|
||||
public function style(array $attributes) : Table
|
||||
{
|
||||
$attribute = '';
|
||||
|
||||
foreach( $attributes as $key => $values )
|
||||
{
|
||||
if( is_numeric($key) )
|
||||
{
|
||||
$key = $values;
|
||||
}
|
||||
|
||||
$attribute .= ' '.$key.':'.$values.';';
|
||||
}
|
||||
|
||||
$this->attr['style'] = $attribute;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates table
|
||||
*
|
||||
* @param string ...$elements
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function create(...$elements) : string
|
||||
{
|
||||
$table = '<table'.$this->html->attributes($this->attr).'>';
|
||||
$table .= $this->_content(...$elements);
|
||||
$table .= '</table>';
|
||||
|
||||
if( ! empty($this->attr)) $this->attr = [];
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Content
|
||||
*/
|
||||
protected function _content(...$elements)
|
||||
{
|
||||
$colNo = 1;
|
||||
$rowNo = 1;
|
||||
$table = '';
|
||||
$eol = EOL;
|
||||
|
||||
if( isset($elements[0][0]) && is_array($elements[0][0]))
|
||||
{
|
||||
$elements = $elements[0]; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
foreach( $elements as $key => $element )
|
||||
{
|
||||
$table .= $eol."\t".'<tr>'.$eol;
|
||||
|
||||
if(is_array($element))foreach($element as $k => $v)
|
||||
{
|
||||
$val = $v;
|
||||
$attr = "";
|
||||
|
||||
if(is_array($v))
|
||||
{
|
||||
$attr = $this->html->attributes($v);
|
||||
$val = $k;
|
||||
}
|
||||
|
||||
if( strpos($val, 'th:') === 0 )
|
||||
{
|
||||
$rowType = 'th'; // @codeCoverageIgnore
|
||||
$val = substr($val, 3); // @codeCoverageIgnore
|
||||
}
|
||||
else
|
||||
{
|
||||
$rowType = 'td';
|
||||
}
|
||||
|
||||
$table .= "\t\t".'<'.$rowType.$attr.'>'.$val.'</'.$rowType.'>'.$eol;
|
||||
$colNo++;
|
||||
}
|
||||
|
||||
$table .= "\t".'</tr>'.$eol;
|
||||
$rowNo++;
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
interface TextInterface
|
||||
{
|
||||
/**
|
||||
* Sets the [type] property of the [script] tag.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function type(string $type);
|
||||
|
||||
/**
|
||||
* Imports script libraries.
|
||||
*
|
||||
* @param string ...$libraries
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function library(...$libraries);
|
||||
|
||||
/**
|
||||
* Opens the [script] tag.
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function open() : string;
|
||||
|
||||
/**
|
||||
* Closes the [/script] tag.
|
||||
*
|
||||
* @param void
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function close() : string;
|
||||
}
|
||||
@@ -0,0 +1,669 @@
|
||||
<?php namespace ZN\Hypertext;
|
||||
/**
|
||||
* ZN PHP Web Framework
|
||||
*
|
||||
* "Simplicity is the ultimate sophistication." ~ Da Vinci
|
||||
*
|
||||
* @package ZN
|
||||
* @license MIT [http://opensource.org/licenses/MIT]
|
||||
* @author Ozan UYKUN [ozan@znframework.com]
|
||||
*/
|
||||
|
||||
use ZN\Base;
|
||||
use ZN\Datatype;
|
||||
use ZN\Buffering;
|
||||
use ZN\Inclusion;
|
||||
use ZN\Authorization;
|
||||
|
||||
trait ViewCommonTrait
|
||||
{
|
||||
use OutputElements,
|
||||
CallableElements,
|
||||
FormElementsTrait,
|
||||
HtmlElementsTrait,
|
||||
BootstrapAttributes,
|
||||
BootstrapComponents,
|
||||
BootstrapLayouts;
|
||||
|
||||
/**
|
||||
* Keeps settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $settings = [];
|
||||
|
||||
/**
|
||||
* Keeps bootstrap options
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $bootstrapOptions = [];
|
||||
|
||||
/**
|
||||
* Sets attributes
|
||||
*
|
||||
* @param array $attributes
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function attributes(array $attributes) : string
|
||||
{
|
||||
unset($this->settings['attr']['perm']);
|
||||
|
||||
$attribute = '';
|
||||
|
||||
if( ! empty($this->settings['attr']) )
|
||||
{
|
||||
$attributes = array_merge($attributes, $this->settings['attr']);
|
||||
|
||||
$this->settings['attr'] = [];
|
||||
}
|
||||
|
||||
foreach( $attributes as $key => $values )
|
||||
{
|
||||
if( is_numeric($key) )
|
||||
{
|
||||
$attribute .= ' '.$values; // @codeCoverageIgnore
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ! empty($key) )
|
||||
{
|
||||
$attribute .= ' '.$key.'="'.$values.'"';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get input
|
||||
*
|
||||
* @param string $type = NULL
|
||||
* @param string $name = NULL
|
||||
* @param string $value = NULL
|
||||
* @param array $attributes = []
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function input(?string $type = NULL, ?string $name = NULL, ?string $value = NULL, array $attributes = []) : string
|
||||
{
|
||||
if( isset($this->settings['attr']['type']) )
|
||||
{
|
||||
$type = $this->settings['attr']['type'];
|
||||
}
|
||||
|
||||
$this->settings['attr'] = [];
|
||||
|
||||
return $this->_input($name, $value, $attributes, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serilize form into controller
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|callable $selector
|
||||
* @param string|array $datatype|$properties
|
||||
*/
|
||||
public function serializer(string $url, $selector = '.modal-body', $datatype = 'standart')
|
||||
{
|
||||
$selector = is_string($selector)
|
||||
? ($this->settings['attr']['data-target'] ?? NULL) . Base::prefix($selector, ' ')
|
||||
: $selector;
|
||||
|
||||
return $this->trigger('click', $url, $selector, $datatype, 'serializer');
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger controller
|
||||
*
|
||||
* @param string $event
|
||||
* @param string $url
|
||||
* @param string|callable $selector
|
||||
* @param string|array $datatype|$properties
|
||||
*/
|
||||
public function trigger(string $event, string $url, $selector, $datatype = 'standart', $resource = 'trigger')
|
||||
{
|
||||
$this->convertSerializerDataType($datatype);
|
||||
|
||||
$data =
|
||||
[
|
||||
'serializerUrl' => $url,
|
||||
'serializerSelector' => $selector,
|
||||
'serializerFunction' => $function = $resource . md5(uniqid()),
|
||||
'serializerProperties'=> $this->transferAttributesAndUnset('serializer', 'properties')
|
||||
];
|
||||
|
||||
$this->settings['attr'][Base::prefix($event, 'on')] = $function . '(this)';
|
||||
|
||||
echo $this->getAjaxResource($resource, $data);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* On event
|
||||
*
|
||||
* @param string $parameter
|
||||
* @param callable $callback
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function on(string $parameter, $callback)
|
||||
{
|
||||
$this->settings['attr']['on'] = $parameter;
|
||||
$this->settings['attr']['onCallback'] = $this->stringOrCallback($callback);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* On key wait event
|
||||
*
|
||||
* @param callable $callback
|
||||
* @param int $time = 100
|
||||
*
|
||||
* @return this
|
||||
*/
|
||||
public function onkeywait($callback, int $time = 300)
|
||||
{
|
||||
$timer = 'timer' . md5(uniqid()); $callback = $this->stringOrCallback($callback);
|
||||
|
||||
$this->settings['attr']['onkeywaititem'] = $timer;
|
||||
|
||||
$compress = (new Script)->compress(function() use($timer, $time, $callback){ return "function {$timer}Function(callback, ms){var $timer = 0; return function(){var context = this, args = arguments; clearTimeout($timer); $timer = setTimeout(function(){callback.apply(context, args);}, ms || 0);};} $('input[onkeywaititem=\"$timer\"]').keyup({$timer}Function(function(e){ $callback }, $time));"; });
|
||||
|
||||
$this->settings['attr']['onkeywait'] = "<script>$compress</script>" . EOL;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected string or callback
|
||||
*/
|
||||
protected function stringOrCallback($content)
|
||||
{
|
||||
if( is_scalar($content) || is_null($content) )
|
||||
{
|
||||
return $content;
|
||||
}
|
||||
elseif( is_callable($content) )
|
||||
{
|
||||
return Buffering\Callback::do($content);
|
||||
}
|
||||
|
||||
throw new Exception\InvalidArgumentException('[$content] parameter must be [scalar] or [callable] type!'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected class resolution
|
||||
*/
|
||||
protected function bootstrapClassResolution($type, $class)
|
||||
{
|
||||
$result = $type . ' ';
|
||||
|
||||
$parts = explode(' ', $class);
|
||||
|
||||
foreach( $parts as $part )
|
||||
{
|
||||
if( ! strstr($part, $type) )
|
||||
{
|
||||
$result .= Base::prefix($part, $type . '-');
|
||||
}
|
||||
else
|
||||
{
|
||||
$result .= $part; // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$result .= ' ';
|
||||
}
|
||||
|
||||
return trim($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected bootstrap class complement
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
protected function bootstrapClassComplement($class)
|
||||
{
|
||||
return preg_replace
|
||||
([
|
||||
'/((sm|md|lg|xs|xl)-[0-9]+)/'
|
||||
],
|
||||
[
|
||||
'col-$1'
|
||||
], $class ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected convert serializeer data type
|
||||
*/
|
||||
protected function convertSerializerDataType($datatype)
|
||||
{
|
||||
if( $datatype === 'json' )
|
||||
{
|
||||
$this->settings['serializer']['properties'] = 'dataType:"json",' . EOL; // @codeCoverageIgnore
|
||||
}
|
||||
elseif( is_array($datatype) )
|
||||
{
|
||||
$this->settings['serializer']['properties'] = rtrim(ltrim(json_encode($datatype), '{'), '}') . ',' . PHP_EOL; // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected transfer attributes and unset
|
||||
*/
|
||||
protected function transferAttributesAndUnset($type, $attr)
|
||||
{
|
||||
$return = $this->settings[$type][$attr] ?? NULL;
|
||||
|
||||
unset($this->settings[$type][$attr]);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected object options
|
||||
*/
|
||||
protected function bootstrapObjectOptions(string $selector, $options, $type)
|
||||
{
|
||||
if( ! empty($options) )
|
||||
{
|
||||
$optionsEncode = json_encode($options);
|
||||
}
|
||||
|
||||
$return = '<script>$(document).ready(function(){$(\'' . $selector . '\').' . $type . '(' . ($optionsEncode ?? NULL) . ')';
|
||||
|
||||
if( $parameter = $this->transferAttributesAndUnset('attr', 'on') )
|
||||
{
|
||||
$return .= '.on(\'' . $parameter . '\', function(){' . $this->transferAttributesAndUnset('attr', 'onCallback') . '})';
|
||||
}
|
||||
|
||||
$return .= '});</script>';
|
||||
|
||||
$this->bootstrapOptions[$type][$selector] = $return;
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is bootstrap attribute
|
||||
*/
|
||||
protected function isBootstrapAttribute($attr, $callback)
|
||||
{
|
||||
if( isset($this->settings['attr'][$attr]) )
|
||||
{
|
||||
$attribute = $this->settings['attr'][$attr];
|
||||
|
||||
if( $attribute === str_replace('-', '', $attr ?? '') )
|
||||
{
|
||||
$attribute = NULL;
|
||||
}
|
||||
|
||||
unset($this->settings['attr'][$attr]);
|
||||
|
||||
$callback($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get resource
|
||||
*/
|
||||
protected function getResource(string $resource, $data, $directory)
|
||||
{
|
||||
return Inclusion\View::use($resource, $data, true, __DIR__ . '/Resources/' . $directory . '/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get modal resource
|
||||
*/
|
||||
protected function getModalResource(string $resource = 'standart', $data = [])
|
||||
{
|
||||
return $this->getResource($resource, $data, 'Modals');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get toast resource
|
||||
*/
|
||||
protected function getToastResource(string $resource = 'standart', $data = [])
|
||||
{
|
||||
return $this->getResource($resource, $data, 'Toasts');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get modal resource
|
||||
*/
|
||||
protected function getAjaxResource(string $resource = 'serializer', $data = [])
|
||||
{
|
||||
return $this->getResource($resource, $data, 'Ajax');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get carousel resource
|
||||
*/
|
||||
protected function getCarouselResource(string $resource = 'standart', $data = [])
|
||||
{
|
||||
return $this->getResource($resource, $data, 'Carousels');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Input
|
||||
*/
|
||||
protected function _input($name = '', $value = '', $attributes = [], $type = '')
|
||||
{
|
||||
$this->setNameAttributeWithReference($name, $attributes);
|
||||
|
||||
$value = htmlspecialchars($value);
|
||||
|
||||
$this->setValueAttributeWithReference($value, $attributes);
|
||||
|
||||
if( ! empty($attributes['name']) )
|
||||
{
|
||||
$this->_postback($attributes['name'], $attributes['value'], $type);
|
||||
|
||||
# 5.8.2.8[added]
|
||||
$this->getVMethodMessages();
|
||||
|
||||
# 5.4.2[added]
|
||||
$this->_validate($attributes['name'], $attributes['name']);
|
||||
|
||||
# 5.4.2[added]
|
||||
$this->_getrow($type, $value, $attributes);
|
||||
}
|
||||
|
||||
$this->commonMethodsForInputElements($type);
|
||||
|
||||
$this->getPermAttribute($perm);
|
||||
|
||||
$this->createFormInputElementByType($type, $attributes, $return);
|
||||
|
||||
$this->createBootstrapFormInputElementByType($type, $return, $attributes, $return);
|
||||
|
||||
$this->outputElement .= $this->_perm($perm, $return);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected change form attributes
|
||||
*/
|
||||
protected function changeFormAttributes($types)
|
||||
{
|
||||
foreach( $types as $new => $old )
|
||||
{
|
||||
$oldEx = explode(':', $old);
|
||||
|
||||
if( isset($this->settings['attr'][$new]) )
|
||||
{
|
||||
unset($this->settings['attr'][$new]); // @codeCoverageIgnore
|
||||
|
||||
$this->settings['attr'][$oldEx[0]] = $oldEx[1]; // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected common methods for input elements
|
||||
*/
|
||||
protected function commonMethodsForInputElements($type)
|
||||
{
|
||||
$this->isBootstrapLabelUsage($type);
|
||||
$this->isBootstrapGroupUsage($type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is bootstrap label usage
|
||||
*/
|
||||
protected function isBootstrapLabelUsage($type)
|
||||
{
|
||||
if( $for = ($this->settings['label']['for'] ?? NULL) )
|
||||
{
|
||||
if( ! $this->isCheckboxOrRadio($type) )
|
||||
{
|
||||
$this->settings['attr']['id'] = $for;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is bootstrap group usage
|
||||
*/
|
||||
protected function isBootstrapGroupUsage($type)
|
||||
{
|
||||
if( ($this->settings['group']['class'] ?? NULL) || isset($this->callableGroup) )
|
||||
{
|
||||
if( ! $this->isCheckboxOrRadio($type) )
|
||||
{
|
||||
if( ! isset($this->settings['attr']['class']) )
|
||||
{
|
||||
$this->settings['attr']['class'] = 'form-control';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->settings['attr']['class'] .= ' form-control'; // @codeCoverageIgnore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is checkbox or radio
|
||||
*/
|
||||
protected function isCheckboxOrRadio($type)
|
||||
{
|
||||
return in_array($type, ['checkbox', 'radio']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set name attribute with reference
|
||||
*/
|
||||
protected function setNameAttributeWithReference($name, &$attributes)
|
||||
{
|
||||
if( $name !== '' )
|
||||
{
|
||||
$attributes['name'] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected set value attribute with reference
|
||||
*/
|
||||
protected function setValueAttributeWithReference($value, &$attributes)
|
||||
{
|
||||
if( $value !== '' )
|
||||
{
|
||||
$attributes['value'] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create form input element by type
|
||||
*/
|
||||
protected function createFormInputElementByType($type, $attributes, &$return)
|
||||
{
|
||||
if( isset($this->settings['attr']['onkeywait']) )
|
||||
{
|
||||
$onkeywait = $this->settings['attr']['onkeywait'];
|
||||
|
||||
unset($this->settings['attr']['onkeywait']);
|
||||
}
|
||||
|
||||
$return .= '<input type="' . $type . '"' . $this->attributes($attributes) . '>' . EOL . ( $onkeywait ?? NULL );
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create form input element by type
|
||||
*/
|
||||
protected function createBootstrapFormInputElementByType($type, $value, $attributes, &$return)
|
||||
{
|
||||
$return = '';
|
||||
|
||||
if( $class = ($this->settings['group']['class'] ?? NULL) )
|
||||
{
|
||||
if( $this->isCheckboxOrRadio($type) )
|
||||
{
|
||||
if( $class === 'form-group' )
|
||||
{
|
||||
$class = $type;
|
||||
}
|
||||
// @codeCoverageIgnoreStart
|
||||
elseif( $class !== $type )
|
||||
{
|
||||
$class = Base::prefix($class, $type . ' ');
|
||||
}
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$return .= '<div class="' . $class . '">' . EOL;
|
||||
|
||||
unset($this->settings['group']);
|
||||
}
|
||||
|
||||
if( $for = ($this->settings['label']['for'] ?? NULL) )
|
||||
{
|
||||
if( ! $this->isCheckboxOrRadio($type) )
|
||||
{
|
||||
$this->createBootstrapInputLabelElement($for, $return);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->createBootstrapRadioOrCheckboxOpenLabelElement($type, $radioOrCheckboxLabel, $return);
|
||||
}
|
||||
|
||||
unset($this->settings['label']);
|
||||
}
|
||||
|
||||
$return .= $value;
|
||||
|
||||
$this->isHelpBlockElement($return);
|
||||
|
||||
$this->isBootstrapColumnSize($return);
|
||||
|
||||
if( isset($radioOrCheckboxLabel) )
|
||||
{
|
||||
$this->createBootstrapRadioOrCheckboxCloseLabelElement($for, $radioOrCheckboxLabel, $return);
|
||||
}
|
||||
|
||||
if( $class )
|
||||
{
|
||||
$return .= '</div>' . EOL;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected is help block element
|
||||
*/
|
||||
protected function isHelpBlockElement(&$return)
|
||||
{
|
||||
$return .= $this->transferAttributesAndUnset('help', 'text');
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected bootstrap column size
|
||||
*/
|
||||
protected function isBootstrapColumnSize(&$return)
|
||||
{
|
||||
if( $colsize = $this->transferAttributesAndUnset('col', 'size'))
|
||||
{
|
||||
$return = $this->getHTMLClass()->class(Base::prefix($colsize, 'col-'))->div($return);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create bootstrap input label element
|
||||
*/
|
||||
protected function createBootstrapInputLabelElement($for, &$return)
|
||||
{
|
||||
$return .= '<label'.$this->createAttribute('class', $this->settings['label']['class']).' for="' . $for . '">' .
|
||||
$this->settings['label']['value'] .
|
||||
'</label>' . EOL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create bootstrap radio or checkbox open label element
|
||||
*/
|
||||
protected function createBootstrapRadioOrCheckboxOpenLabelElement($type, &$radioOrCheckboxLabel, &$return)
|
||||
{
|
||||
if( $value = $this->settings['label']['value'] )
|
||||
{
|
||||
$this->settings['label']['value'] = Base::prefix($value, $type . '-'); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
$return .= '<label'.$this->createAttribute('class', $this->settings['label']['value']).'>' . EOL;
|
||||
|
||||
$radioOrCheckboxLabel = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected create bootstrap radio or checkbox close label element
|
||||
*/
|
||||
protected function createBootstrapRadioOrCheckboxCloseLabelElement($for, &$radioOrCheckboxLabel, &$return)
|
||||
{
|
||||
$return .= $for . EOL . '</label>' . EOL;
|
||||
|
||||
unset($radioOrCheckboxLabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected craete attribute
|
||||
*/
|
||||
protected function createAttribute($type, $value)
|
||||
{
|
||||
return $value ? ' ' . $type . '="' . $value. '"' : NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected get perm attribute
|
||||
*/
|
||||
protected function getPermAttribute(&$perm)
|
||||
{
|
||||
$perm = $this->settings['attr']['perm'] ?? NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Perm [5.4.5]
|
||||
*/
|
||||
protected function _perm($perm, $return)
|
||||
{
|
||||
if( $perm !== NULL )
|
||||
{
|
||||
if( Authorization\PermissionExtends::$roleId === NULL )
|
||||
{
|
||||
throw new Exception\PermissionRoleIdException(); // @codeCoverageIgnore
|
||||
}
|
||||
|
||||
return Authorization\Process::use($perm, $return);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Protected Element
|
||||
*/
|
||||
protected function _element($function, $element)
|
||||
{
|
||||
if( ! is_callable($element) )
|
||||
{
|
||||
if( $element === false )
|
||||
{
|
||||
$element = 'false';
|
||||
}
|
||||
else if( $element === true )
|
||||
{
|
||||
$element = 'true';
|
||||
}
|
||||
else if( is_array($element) || is_object($element) )
|
||||
{
|
||||
$element = json_encode($element, JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
$element = htmlentities($element, ENT_COMPAT);
|
||||
}
|
||||
|
||||
$this->settings['attr'][strtolower($function ?? '')] = $element;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user