new pisilinux web sites

This commit is contained in:
Erkan IŞIK
2026-07-01 16:44:17 +03:00
commit b58488b586
21740 changed files with 2066209 additions and 0 deletions
+135
View File
@@ -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 ?? '&times;');
}
/**
* 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()'
]
];
}
+833
View File
@@ -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;
}
}
+555
View File
@@ -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("&nbsp;", $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; ?>
+86
View File
@@ -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">&times;</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">&times;</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">&times;</button>
@endif
</div>
<div class="toast-body">
{{ $toastBody }}
</div>
</div>
+133
View File
@@ -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';
}
}
+694
View File
@@ -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);
}';
}
+381
View File
@@ -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);
}
}
+168
View File
@@ -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';
}
}
+88
View File
@@ -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';
}
}
+217
View File
@@ -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;
}
}