├── .travis.yml ├── README.md ├── composer.json ├── phprelease.ini ├── phpunit.xml ├── src └── WebUI │ ├── Components │ ├── Breadcrumbs.php │ ├── Menu │ │ ├── IdentityFinder.php │ │ ├── Menu.php │ │ ├── MenuFolder.php │ │ ├── MenuItem.php │ │ ├── MenuItemCollection.php │ │ └── MenuItemInterface.php │ ├── Pager │ │ ├── BasePager.php │ │ ├── Bootstrap2Pager.php │ │ ├── Bootstrap3Pager.php │ │ ├── BootstrapPager.php │ │ └── Pager.php │ └── React │ │ └── ReactComponent.php │ └── Core │ ├── Div.php │ ├── Element.php │ └── Span.php └── tests └── WebUI ├── Components ├── BreadcrumbsTest.php ├── Menu │ └── MenuTest.php ├── PagerTest.php └── React │ └── ReactComponentTest.php └── Core └── ElementTest.php /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | php: 3 | - 5.4 4 | - 5.5 5 | - 5.6 6 | 7 | before_script: 8 | - phpenv rehash 9 | - composer self-update 10 | - composer require satooshi/php-coveralls "^1" --no-update --dev 11 | - composer install 12 | 13 | script: 14 | - phpunit 15 | 16 | after_script: 17 | - php vendor/bin/coveralls -v 18 | 19 | cache: 20 | - vendor 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | WebUI 2 | ========================= 3 | 4 | WebUI aims to provide a PHP interface to build HTML components with microdata. 5 | 6 | 7 | 8 | Synopsis 9 | ------------------------- 10 | 11 | 12 | ```php 13 | $el = new Element('span'); 14 | $el->append('>'); 15 | $el->addClass('separator'); 16 | 17 | $breadcrumbs = new Breadcrumbs; 18 | 19 | $breadcrumbs->setSeparatorElement($el); 20 | 21 | $breadcrumbs->appendLink('Home', '/', 'The Home Page'); 22 | $breadcrumbs->appendLink('Product', '/', 'All Products'); 23 | $html = $breadcrumbs->render(); 24 | ``` 25 | 26 | And we will get: 27 | 28 | ```html 29 | 42 | ``` 43 | 44 | 45 | Components 46 | ---------------------- 47 | 48 | 49 | ## ReactComponent 50 | 51 | Rendering ReactComponent initializer from PHP settings: 52 | 53 | ```php 54 | $component = new ReactComponent('CRUDListApp', array( 'prop1' => 'setting' )); 55 | $out = $component->render(); 56 | ``` 57 | 58 | The code above renders the html below: 59 | 60 | ```html 61 |
62 | 70 | ``` 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "corneltek/webui", 3 | "description": "Web UI Components Library", 4 | "license": "MIT", 5 | "authors": [ 6 | { 7 | "name": "c9s", 8 | "email": "cornelius.howl@gmail.com" 9 | } 10 | ], 11 | "require": { }, 12 | "require-dev": { 13 | "corneltek/formkit": "*", 14 | "corneltek/phpunit-testmore": "dev-master" 15 | }, 16 | "autoload": { 17 | "psr-4": { "WebUI\\": "src/WebUI/" } 18 | }, 19 | "extra": { "branch-alias": { "dev-master": "2.0.x-dev" } } 20 | } 21 | -------------------------------------------------------------------------------- /phprelease.ini: -------------------------------------------------------------------------------- 1 | Steps = PHPUnit, BumpVersion, GitCommit, GitTag, GitPush, GitPushTags 2 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 10 | 11 | 12 | 13 | tests 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/WebUI/Components/Breadcrumbs.php: -------------------------------------------------------------------------------- 1 | separator = $element; 20 | } 21 | 22 | public function setSeparatorHtml($html) { 23 | $this->separator = $html; 24 | } 25 | 26 | public function appendIndexLink($label, $url, $title = NULL, array $attributes = array()) 27 | { 28 | $span = $this->appendLink($label, $url, $title, $attributes); 29 | $span->getChildAt(0)->setAttributeValue('rel','index'); 30 | } 31 | 32 | 33 | /** 34 | * Append a link "a" element and add "span" element wrapper with microdata automatically. 35 | * 36 | * @param string $label The label of that link. 37 | * @param string $url The url of that link. 38 | * @param string $title The title attribute of the link. 39 | * @param array $attributes The attributes of the link. 40 | */ 41 | public function appendLink($label, $url, $title = NULL, array $attributes = array() ) 42 | { 43 | $span = new Element('span'); 44 | $span['itemscope'] = NULL; 45 | $span['itemtype'] = 'http://data-vocabulary.org/Breadcrumb'; 46 | $span['role'] = 'presentation'; 47 | 48 | $a = new Element('a', $attributes); 49 | $a['title'] = $title ?: $label; 50 | $a['alt'] = $title ?: $label; 51 | $a['itemprop'] = 'url'; 52 | $a['href'] = $url; 53 | $a['aria-level'] = $this->getChildrenSize() + 1; 54 | 55 | # Home 56 | $title = new Element('span'); 57 | $title->appendText($label); 58 | $title['itemprop'] = 'title'; 59 | $a->addChild($title); 60 | 61 | $span->addChild($a); 62 | $this->addChild($span); 63 | return $span; 64 | } 65 | 66 | public function render($attributes = array()) 67 | { 68 | // 13 | */ 14 | class Menu extends Element implements MenuItemInterface, IdentityFinder 15 | { 16 | protected $classes = array('webui-menu'); 17 | 18 | protected $menuItemCollections = array(); 19 | 20 | public function __construct(array $attributes = array()) 21 | { 22 | Element::__construct('nav', array_merge(array( 23 | "role" => "menubar", 24 | "itemscope" => NULL, 25 | "itemtype" => "http://schema.org/SiteNavigationElement", 26 | "class" => $this->classes, 27 | ), $attributes)); 28 | } 29 | 30 | public function appendCollection(array $attributes = array(), $identity = null) 31 | { 32 | $collection = new MenuItemCollection($attributes, $identity); 33 | $this->menuItemCollections[] = $collection; 34 | return $collection; 35 | } 36 | 37 | public function findById($identity) 38 | { 39 | foreach ($this->menuItemCollections as $collection) { 40 | if ($collection instanceof IdentityFinder) { 41 | if ($result = $collection->findById($identity)) { 42 | return $result; 43 | } 44 | } else if ( $collection->getIdentity() === $identity ) { 45 | return $collection; 46 | } 47 | } 48 | } 49 | 50 | public function render($attrs = array()) 51 | { 52 | foreach( $this->menuItemCollections as $collection) { 53 | $this->append($collection); 54 | } 55 | return Element::render($attrs); 56 | } 57 | } 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /src/WebUI/Components/Menu/MenuFolder.php: -------------------------------------------------------------------------------- 1 | 14 | * Folder 15 | * 18 | * 19 | * 20 | */ 21 | class MenuFolder extends Element implements MenuItemInterface, IdentityFinder 22 | { 23 | protected $label; 24 | 25 | protected $linkAttributes = array( 'href' => '#' ); 26 | 27 | protected $menuItemCollection; 28 | 29 | protected $identity; 30 | 31 | public function __construct($label, array $linkAttributes = null, array $attributes = array(), $identity = null) 32 | { 33 | $this->setLabel($label); 34 | if ($linkAttributes) { 35 | $this->setLinkAttributes($linkAttributes); 36 | } 37 | parent::__construct('li', array_merge(array( 38 | "role" => "menuitem", 39 | "itemprop" => "itemListElement", 40 | "itemtype" => "http://schema.org/ItemList", 41 | ), $attributes)); 42 | 43 | $this->menuItemCollection = new MenuItemCollection; 44 | $this->setIdentity( $identity ?: crc32(microtime()) ); 45 | } 46 | 47 | public function getItems() 48 | { 49 | return $this->menuItemCollection; 50 | } 51 | 52 | public function setIdentity($identity) 53 | { 54 | $this->identity = $identity; 55 | } 56 | 57 | public function getIdentity() 58 | { 59 | return $this->identity; 60 | } 61 | 62 | public function setLabel($label) 63 | { 64 | $this->label = $label; 65 | } 66 | 67 | public function setLinkAttributes(array $attributes) 68 | { 69 | $this->linkAttributes = $attributes; 70 | } 71 | 72 | public function setLink($label, array $attributes = array()) { 73 | $this->label = $label; 74 | $this->linkAttributes = $attributes; 75 | } 76 | 77 | public function __call($method, $args) { 78 | if (method_exists($this->menuItemCollection, $method)) { 79 | return call_user_func_array(array($this->menuItemCollection, $method), $args); 80 | } else { 81 | throw new BadMethodCallException; 82 | } 83 | } 84 | 85 | public function findById($identity) 86 | { 87 | foreach ($this->menuItemCollection as $menuItem) { 88 | if ($menuItem instanceof IdentityFinder) { 89 | if ($result = $menuItem->findById($identity)) { 90 | return $result; 91 | } 92 | } 93 | } 94 | } 95 | 96 | public function render($attrs = array()) 97 | { 98 | // create a wrapper div 99 | //
100 | if (!$this->label) { 101 | throw new Exception('Missing menu label'); 102 | } 103 | 104 | // create label with tag "a" 105 | $a = new Element('a', $this->linkAttributes); 106 | $a->append($this->label); 107 | $this->append($a); 108 | 109 | $this->append($this->menuItemCollection); 110 | 111 | return parent::render($attrs); 112 | } 113 | 114 | } 115 | 116 | 117 | 118 | 119 | -------------------------------------------------------------------------------- /src/WebUI/Components/Menu/MenuItem.php: -------------------------------------------------------------------------------- 1 | '#' ); 16 | 17 | protected $identity; 18 | 19 | public function __construct($label, array $linkAttributes = null, array $attributes = array(), $identity = null) 20 | { 21 | $this->setLabel($label); 22 | if ($linkAttributes) { 23 | $this->setLinkAttributes($linkAttributes); 24 | } 25 | parent::__construct('li', array_merge(array( 26 | "role" => "presentation", 27 | "itemprop" => "itemListElement", 28 | "itemscope" => NULL, 29 | ), $attributes)); 30 | $this->setIdentity( $identity ?: uniqid('menuItem') ); 31 | } 32 | 33 | public function setIdentity($identity) 34 | { 35 | $this->identity = $identity; 36 | } 37 | 38 | public function getIdentity() 39 | { 40 | return $this->identity; 41 | } 42 | 43 | public function setLabel($label) 44 | { 45 | $this->label = $label; 46 | } 47 | 48 | public function setLinkAttributes(array $attributes) 49 | { 50 | $this->linkAttributes = $attributes; 51 | } 52 | 53 | public function setLink($label, array $attributes = array()) { 54 | $this->label = $label; 55 | $this->linkAttributes = $attributes; 56 | } 57 | 58 | public function render($attributes = array()) 59 | { 60 | if (!$this->label) { 61 | throw new Exception('Missing menu label'); 62 | } 63 | 64 | // create label with tag "a" 65 | $a = new Element('a', $this->linkAttributes); 66 | $a->setAttributeValue("role","menuitem"); 67 | $a->append($this->label); 68 | $this->append($a); 69 | return parent::render($attributes); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/WebUI/Components/Menu/MenuItemCollection.php: -------------------------------------------------------------------------------- 1 | "menu", 21 | "itemscope" => NULL, 22 | "class" => "nav", 23 | "itemtype" => "http://schema.org/ItemList", 24 | ), $attributes)); 25 | 26 | $this->setIdentity( $identity ?: crc32(microtime()) ); 27 | } 28 | 29 | public function setIdentity($identity) 30 | { 31 | $this->identity = $identity; 32 | } 33 | 34 | public function getIdentity() 35 | { 36 | return $this->identity; 37 | } 38 | 39 | public function render($attrs = array()) 40 | { 41 | $this->setAttributeValue('role', 'menu'); 42 | $this->setAttributes(array( 43 | 'itemscope' => null, 44 | 'itemtype' => "http://schema.org/ItemList", 45 | )); 46 | 47 | foreach ($this->menuItems as $item) { 48 | $this->append($item); 49 | } 50 | return Element::render($attrs); 51 | } 52 | 53 | public function appendLink($label, array $linkAttributes = array(), array $attributes = array()) { 54 | $item = new MenuItem($label, $attributes); 55 | $item->setLinkAttributes($linkAttributes); 56 | $this->addMenuItem($item); 57 | return $item; 58 | } 59 | 60 | public function appendFolder($label, array $attributes = array(), array $config = array()) 61 | { 62 | $folder = self::createFolder($label, $attributes, $config); 63 | $this->addMenuItem($folder); 64 | return $folder; 65 | } 66 | 67 | 68 | static public function createItem($label, array $linkAttributes = array(), array $attributes = array()) 69 | { 70 | $item = new MenuItem($label, $attributes); 71 | $item->setLinkAttributes($linkAttributes); 72 | return $item; 73 | } 74 | 75 | static public function createFolder($label, array $attributes = array(), array $config = array()) 76 | { 77 | $folder = new MenuFolder($attributes); 78 | if (isset($config['icon_class'])) { 79 | $label = ' ' . $label; 80 | } 81 | $folder->setLabel($label); 82 | return $folder; 83 | } 84 | 85 | 86 | 87 | public function addMenuItem(MenuItemInterface $item) 88 | { 89 | $this->menuItems[] = $item; 90 | } 91 | 92 | public function getMenuItemByIndex($index) 93 | { 94 | if (isset($this->menuItems[ $index ])) { 95 | return $this->menuItems[ $index ]; 96 | } 97 | } 98 | 99 | public function removeMenuItemByIndex($index) 100 | { 101 | return array_splice($this->menuItems, $index, 1); 102 | } 103 | 104 | public function getIterator() 105 | { 106 | return new ArrayIterator($this->menuItems); // array 107 | } 108 | 109 | public function count() 110 | { 111 | return count($this->menuItems); 112 | } 113 | 114 | public function findById($identity) 115 | { 116 | foreach( $this->menuItems as $item ) { 117 | if ($item instanceof IdentityFinder) { 118 | if ($result = $item->findById($identity)) { 119 | return $result; 120 | } 121 | } else if ( $item->getIdentity() === $identity ) { 122 | return $item; 123 | } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /src/WebUI/Components/Menu/MenuItemInterface.php: -------------------------------------------------------------------------------- 1 | 0 ? ceil($numberOfTotalItems / $pageSize) : 1; 9 | } 10 | } 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/WebUI/Components/Pager/Bootstrap2Pager.php: -------------------------------------------------------------------------------- 1 | firstText = _('Page.First'); 31 | $this->lastText = _('Page.Last'); 32 | $this->nextText = _('Page.Next'); 33 | $this->prevText = _('Page.Previous'); 34 | $this->currentPage = $currentPage; 35 | $this->totalPages = $totalPages; 36 | } 37 | 38 | 39 | public function setFirstPageText($text) 40 | { 41 | $this->firstText = $text; 42 | } 43 | 44 | public function setLastPageText($text) 45 | { 46 | $this->lastText = $text; 47 | } 48 | 49 | public function setNextPagetext($text) 50 | { 51 | $this->nextText = $text; 52 | } 53 | 54 | public function setPrevPageText($text) 55 | { 56 | $this->prevText = $text; 57 | } 58 | 59 | public function addClass($class) 60 | { 61 | $this->wrapperClass[] = $class; 62 | } 63 | 64 | public function mergeQuery( $orig_params , $params = array() ) 65 | { 66 | $params = array_merge( $orig_params , $params ); 67 | 68 | return '?' . http_build_query( $params ); 69 | } 70 | 71 | public function renderLink( $num , $text = null , $moreclass = "" , $disabled = false , $active = false ) 72 | { 73 | if ( $text == null ) 74 | $text = $num; 75 | 76 | if ( $disabled ) 77 | return $this->renderDisabledLink( $text , $moreclass ); 78 | 79 | $args = array_merge( $_GET , $_POST ); 80 | $href = $this->mergeQuery( $args , array( "page" => $num ) ); 81 | $liClass = ''; 82 | if ( $active ) { 83 | $liClass = 'active'; 84 | } 85 | return <<$text 87 | EOF; 88 | } 89 | 90 | protected function renderDisabledLink( $text , $moreclass = "" ) 91 | { 92 | return <<$text 94 | EOF; 95 | } 96 | 97 | public function __toString() 98 | { 99 | return $this->render(); 100 | } 101 | 102 | public function render() 103 | { 104 | $cur = $this->currentPage; 105 | $total_pages = $this->totalPages; 106 | 107 | if ($this->whenOverflow && $this->totalPages <= 1) { 108 | return ""; 109 | } 110 | 111 | $pagenum_start = $cur > $this->rangeLimit ? $cur - $this->rangeLimit : 1 ; 112 | $pagenum_end = $cur + $this->rangeLimit < $total_pages ? $cur + $this->rangeLimit : $total_pages; 113 | 114 | $output = ""; 115 | $output .= '
'; 116 | $output .= '
    '; 117 | 118 | if ($this->showNavigator) { 119 | if ( $cur > 1 ) 120 | $output .= $this->renderLink( 1 , $this->firstText , 'pager-first' , $cur == 1 ); 121 | 122 | if ( $cur > 1 ) 123 | $output .= $this->renderLink( $cur -1 , $this->prevText , 'pager-prev' , $cur == 1 ); 124 | } 125 | 126 | 127 | if ( $this->showPageNumbers ) { 128 | if ( $cur > 5 ) { 129 | $output .= $this->renderLink( 1 , 1 , 'pager-number' ); 130 | $output .= '
  • ...
  • '; 131 | } 132 | 133 | for ($i = $pagenum_start ; $i <= $pagenum_end ; $i++) { 134 | if ( $i == $this->currentPage ) { 135 | $output .= $this->renderLink( $i , $i , 'pager-number active pager-number-current', false, true); 136 | } else { 137 | $output .= $this->renderLink( $i , $i , 'pager-number' ); 138 | } 139 | } 140 | 141 | if ( $cur + 5 < $total_pages ) { 142 | $output .= '
  • ...
  • '; 143 | $output .= $this->renderLink( $total_pages , $total_pages , 'pager-number' ); 144 | } 145 | } 146 | 147 | if ($this->showNavigator) { 148 | 149 | if ( $cur < $total_pages ) 150 | $output .= $this->renderLink( $cur + 1, 151 | $this->nextText , 'pager-next' , $cur == $this->totalPages ); 152 | 153 | if ( $total_pages > 1 && $cur < $total_pages ) 154 | $output .= $this->renderLink( $this->totalPages, 155 | $this->lastText , 'pager-last' , $cur == $this->totalPages ); 156 | } 157 | 158 | $output .= '
'; 159 | $output .= '
'; 160 | return $output; 161 | } 162 | } 163 | -------------------------------------------------------------------------------- /src/WebUI/Components/Pager/Bootstrap3Pager.php: -------------------------------------------------------------------------------- 1 | firstText = _('Page.First'); 39 | $this->lastText = _('Page.Last'); 40 | $this->nextText = _('Page.Next'); 41 | $this->prevText = _('Page.Previous'); 42 | 43 | $this->currentPage = $currentPage; 44 | $this->totalPages = $totalPages; 45 | } 46 | 47 | public function setFirstPageText($text) 48 | { 49 | $this->firstText = $text; 50 | } 51 | 52 | public function setLastPageText($text) 53 | { 54 | $this->lastText = $text; 55 | } 56 | 57 | public function setNextPagetext($text) 58 | { 59 | $this->nextText = $text; 60 | } 61 | 62 | public function setPrevPageText($text) 63 | { 64 | $this->prevText = $text; 65 | } 66 | 67 | public function addClass($class) 68 | { 69 | $this->wrapperClass[] = $class; 70 | } 71 | 72 | public function mergeQuery( $orig_params , $params = array() ) 73 | { 74 | $params = array_merge( $orig_params , $params ); 75 | return '?' . http_build_query( $params ); 76 | } 77 | 78 | public function renderLink( $num , $text = null , $moreclass = "" , $disabled = false , $active = false ) 79 | { 80 | if ($text === null) { 81 | $text = $num; 82 | } 83 | 84 | if ($disabled) { 85 | return $this->renderLinkDisabled( $text , $moreclass ); 86 | } 87 | 88 | $args = array_merge( $_GET , $_POST ); 89 | $href = $this->mergeQuery( $args , array( "page" => $num ) ); 90 | $liClass = ''; 91 | if ($active) { 92 | $liClass = 'active'; 93 | } 94 | return <<$text 96 | EOF; 97 | 98 | 99 | } 100 | 101 | public function renderLinkDisabled( $text , $moreclass = "" ) 102 | { 103 | return <<$text 105 | EOF; 106 | } 107 | 108 | public function __toString() 109 | { 110 | return $this->render(); 111 | } 112 | 113 | public function render() 114 | { 115 | $cur = $this->currentPage; 116 | $total_pages = $this->totalPages; 117 | 118 | if ($this->whenOverflow && $this->totalPages <= 1) { 119 | return ""; 120 | } 121 | 122 | $pagenum_start = $cur > $this->rangeLimit ? $cur - $this->rangeLimit : 1 ; 123 | $pagenum_end = $cur + $this->rangeLimit < $total_pages ? $cur + $this->rangeLimit : $total_pages; 124 | 125 | $output = ""; 126 | $output .= '
    '; 127 | 128 | if ($this->navigator) { 129 | $output .= $this->renderLink( 1 , $this->firstText , 'pager-first' , $cur == 1 ); 130 | $output .= $this->renderLink( $cur - 1 , $this->prevText , 'pager-prev' , $cur == 1 ); 131 | } 132 | 133 | 134 | if ( $this->showPageNumbers ) { 135 | if ( $cur > 5 ) { 136 | $output .= $this->renderLink( 1 , 1 , 'pager-number' ); 137 | $output .= '
  • ...
  • '; 138 | } 139 | 140 | for ($i = $pagenum_start ; $i <= $pagenum_end ; $i++) { 141 | if ( $i == $this->currentPage ) { 142 | $output .= $this->renderLink( $i , $i , 'pager-number active pager-number-current', false, true); 143 | } else { 144 | $output .= $this->renderLink( $i , $i , 'pager-number' ); 145 | } 146 | } 147 | 148 | if ( $cur + 5 < $total_pages ) { 149 | $output .= '
  • ...
  • '; 150 | $output .= $this->renderLink( $total_pages , $total_pages , 'pager-number' ); 151 | } 152 | } 153 | 154 | if ($this->navigator) { 155 | $output .= $this->renderLink( $cur + 1, 156 | $this->nextText , 'pager-next' , $cur == $this->totalPages ); 157 | $output .= $this->renderLink( $this->totalPages, 158 | $this->lastText , 'pager-last' , $cur == $this->totalPages ); 159 | } 160 | $output .= '
'; 161 | return $output; 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /src/WebUI/Components/Pager/Pager.php: -------------------------------------------------------------------------------- 1 | firstPageLabel = '«'; 47 | $this->lastPageLabel = '»'; 48 | $this->nextPageLabel = '›'; 49 | $this->prevPageLabel = '‹'; 50 | $this->currentPage = $currentPage; 51 | $this->totalPages = $totalPages; 52 | $this->baseUrl = $baseUrl; 53 | parent::__construct('ul'); 54 | } 55 | 56 | public function setBaseUrl($url) 57 | { 58 | $this->baseUrl = $url; 59 | } 60 | 61 | public function setFirstPageLabel($text) 62 | { 63 | $this->firstPageLabel = $text; 64 | } 65 | 66 | public function setLastPageLabel($text) 67 | { 68 | $this->lastPageLabel = $text; 69 | } 70 | 71 | public function setNextPagetext($text) 72 | { 73 | $this->nextPageLabel = $text; 74 | } 75 | 76 | public function setPrevPageLabel($text) 77 | { 78 | $this->prevPageLabel = $text; 79 | } 80 | 81 | /** 82 | * build page query 83 | */ 84 | protected function buildQuery(array $origParams , $params = array() ) 85 | { 86 | $params = array_merge($origParams , $params); 87 | return $this->baseUrl . '?' . http_build_query($params); 88 | } 89 | 90 | public function __toString() 91 | { 92 | return $this->render(); 93 | } 94 | 95 | protected function appendPageOmitNavItem($text = '...') 96 | { 97 | $li = new Element('li'); 98 | $a = new Element('a'); 99 | $a->appendTo($li); 100 | $a->setInnerHtml($text); 101 | return $li; 102 | } 103 | 104 | public function appendNavItem($text, $page, $active = false, $disabled = false) { 105 | $li = new Element('li'); 106 | $a = new Element('a'); 107 | $a->appendTo($li); 108 | $a->setInnerHtml($text); 109 | 110 | $href = $this->buildQuery($_REQUEST, array("page" => $page)); 111 | $a->setAttributeValue('href', $href); 112 | 113 | $li->setAttributeValue('role', 'presentation'); 114 | if ($disabled) { 115 | $li->addClass('disabled'); 116 | $a->setAttributeValue('aria-disabled','true'); 117 | } 118 | 119 | if ($active) { 120 | $li->addClass('active'); 121 | $li->addClass('current'); 122 | } 123 | $this->addChild($li); 124 | return $li; 125 | } 126 | 127 | public function render($attributes = array()) 128 | { 129 | $cur = $this->currentPage; 130 | $totalPages = $this->totalPages; 131 | 132 | if ($this->whenOverflow && $this->totalPages <= 1) { 133 | return ""; 134 | } 135 | 136 | $pageStart = $cur > $this->rangeLimit ? $cur - $this->rangeLimit : 1 ; 137 | $pageEnd = $cur + $this->rangeLimit < $totalPages ? $cur + $this->rangeLimit : $totalPages; 138 | 139 | // Create inner elements and append to children element list. 140 | if ($this->showNavigator) { 141 | if ($cur > 2) { 142 | $li = $this->appendNavItem($this->firstPageLabel, 1, $cur == 1, $cur == 1); 143 | $li->getChildAt(0)->setAttributeValue('rel','first'); 144 | } 145 | $li = $this->appendNavItem($this->prevPageLabel, $cur - 1, false, $cur == 1); 146 | $li->getChildAt(0)->setAttributeValue('rel','prev'); 147 | } 148 | 149 | if ($this->showNearbyPages) { 150 | if ($cur > 5) { 151 | $this->appendNavItem(1, 1); 152 | $this->appendPageOmitNavItem('...'); 153 | } 154 | 155 | for ($i = $pageStart ; $i <= $pageEnd ; $i++) { 156 | $this->appendNavItem($i, $i, $cur == $i); 157 | } 158 | 159 | if ($cur + 5 < $totalPages) { 160 | $this->appendPageOmitNavItem('...'); 161 | $this->appendNavItem($totalPages, $totalPages); 162 | } 163 | } 164 | 165 | if ($this->showNavigator) { 166 | $li = $this->appendNavItem($this->nextPageLabel, $cur + 1, $cur >= $totalPages); 167 | $li->getChildAt(0)->setAttributeValue('rel','next'); 168 | 169 | if ($totalPages > 1 && $cur < $totalPages) { 170 | $li = $this->appendNavItem($this->lastPageLabel, $this->totalPages); 171 | $li->getChildAt(0)->setAttributeValue('rel','last'); 172 | } 173 | } 174 | 175 | $html = parent::render(); 176 | 177 | if ($this->navWrapper) { 178 | $nav = new Element('nav'); 179 | $nav->setAttributeValue('role', 'navigation'); 180 | $nav->setAttributeValue('aria-label', "Pagination"); 181 | $nav->setInnerHtml($html); 182 | return $nav->render($attributes); 183 | } 184 | return $html; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/WebUI/Components/React/ReactComponent.php: -------------------------------------------------------------------------------- 1 | jsClassName = $jsClassName; 20 | $this->props = $props; 21 | $this->id = uniqid($jsClassName); 22 | $this->addClass('react-component react-app'); 23 | } 24 | 25 | public function setDebug($debugLevel = 1) 26 | { 27 | $this->debug = $debugLevel; 28 | } 29 | 30 | public function render($attributes = array()) 31 | { 32 | $varId = uniqid('app'); 33 | // render the div element 34 | $out = parent::render($attributes) . "\n"; 35 | $out .= "\n"; 44 | return $out; 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/WebUI/Core/Div.php: -------------------------------------------------------------------------------- 1 | tagName, $attributes); 12 | } 13 | } 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /src/WebUI/Core/Element.php: -------------------------------------------------------------------------------- 1 | tagName = $tagName; 45 | $this->setAttributeType( 'class', self::ATTR_ARRAY ); 46 | $this->setAttributes( $attributes ); 47 | $this->init($attributes); 48 | } 49 | 50 | public function setExtraAttributeString($attrString) 51 | { 52 | $this->extraAttributeString = $attrString; 53 | } 54 | 55 | public function isIgnoredAttribute($name) 56 | { 57 | return isset($this->_ignoredAttributes[$name]); 58 | } 59 | 60 | public function addIgnoredAttribute($name) 61 | { 62 | $this->_ignoredAttributes[$name] = true; 63 | } 64 | 65 | public function removeIgnoredAttribute($name) 66 | { 67 | unset($this->_ignoredAttributes[$name]); 68 | } 69 | 70 | /** 71 | * Register new attribute with type, 72 | * This creates accessors for objects. 73 | * 74 | * @param string $name attribute name 75 | * @param integer $type attribute type 76 | */ 77 | public function setAttributeType( $name , $type ) 78 | { 79 | $this->_supportedAttributes[ $name ] = $type; 80 | } 81 | 82 | 83 | /** 84 | * Remove attribute 85 | * 86 | * @param string $name 87 | */ 88 | public function removeAttributeType($name) 89 | { 90 | unset( $this->_supportedAttributes[ $name ] ); 91 | } 92 | 93 | 94 | /** 95 | * Get attribute value 96 | * 97 | * @param string $name 98 | * @return mixed value 99 | */ 100 | public function __get($name) 101 | { 102 | if (isset($this->_attributes[ $name ] )) 103 | return $this->_attributes[ $name ]; 104 | } 105 | 106 | /** 107 | * Set attribute value 108 | * 109 | * @param string $name 110 | * @param mixed $value 111 | */ 112 | public function __set($name,$value) 113 | { 114 | $this->_attributes[ $name ] = $value; 115 | } 116 | 117 | 118 | 119 | /** 120 | * Check property and set attribute value without type 121 | * checking. 122 | * 123 | * If there is a property with the same name 124 | * Then the value will be set to the property. 125 | * 126 | * Or the value will be stored in $this->_attributes array. 127 | * 128 | * This is for internal use. 129 | * 130 | * @param string $name 131 | * @param mixed $arg 132 | */ 133 | public function setAttributeValue($name,$arg) 134 | { 135 | if (property_exists($this, $name)) { 136 | $this->$name = $arg; 137 | } else { 138 | $this->_attributes[ $name ] = $arg; 139 | } 140 | } 141 | 142 | public function getAttributeValue($name) 143 | { 144 | if ( property_exists($this, $name) ) { 145 | return $this->$name; 146 | } elseif (array_key_exists($name, $this->_attributes)) { 147 | return $this->_attributes[ $name ]; 148 | } 149 | } 150 | 151 | public function hasAttribute($name) 152 | { 153 | return property_exists($this, $name) || array_key_exists($name, $this->_attributes); 154 | } 155 | 156 | /** 157 | * Check if the attribute is registered 158 | * if it's registered, the type registered will 159 | * change the behavior of setting values. 160 | * 161 | * 162 | * @param string $name 163 | * @param array $args 164 | */ 165 | public function setAttribute($name,$args) 166 | { 167 | if ($this->isIgnoredAttribute($name)) { 168 | return; 169 | } 170 | 171 | // check if it's registered. 172 | if( isset($this->_supportedAttributes[ $name ]) ) 173 | { 174 | $c = count($args); 175 | $t = $this->_supportedAttributes[ $name ]; 176 | 177 | if( $t != self::ATTR_FLAG && $c == 0 ) { 178 | throw new Exception( 'Attribute value is required.' ); 179 | } 180 | 181 | switch( $t ) 182 | { 183 | case self::ATTR_ANY: 184 | $this->setAttributeValue( $name, $args[0] ); 185 | break; 186 | 187 | case self::ATTR_ARRAY: 188 | if( $c > 1 ) { 189 | $this->setAttributeValue( $name, $args ); 190 | } 191 | elseif( is_array($args[0]) ) 192 | { 193 | $this->setAttributeValue( $name , $args[0] ); 194 | } 195 | else 196 | { 197 | $this->setAttributeValue( $name , (array) $args[0] ); 198 | } 199 | break; 200 | 201 | case self::ATTR_STRING: 202 | if( is_string($args[0]) ) { 203 | $this->setAttributeValue($name,$args[0]); 204 | } 205 | else { 206 | throw new Exception("attribute value of $name is not a string."); 207 | } 208 | break; 209 | 210 | case self::ATTR_INTEGER: 211 | if( is_integer($args[0])) { 212 | $this->setAttributeValue( $name , $args[0] ); 213 | } 214 | else { 215 | throw new Exception("attribute value of $name is not a integer."); 216 | } 217 | break; 218 | 219 | case self::ATTR_CALLABLE: 220 | 221 | /** 222 | * handle for __invoke, array($obj,$name), 'function_name 223 | */ 224 | if( is_callable($args[0]) ) { 225 | $this->setAttributeValue( $name, $args[0] ); 226 | } else { 227 | throw new Exception("attribute value of $name is not callable type."); 228 | } 229 | break; 230 | 231 | case self::ATTR_FLAG: 232 | $this->setAttributeValue($name,true); 233 | break; 234 | 235 | default: 236 | throw new Exception("Unsupported attribute type: $name"); 237 | } 238 | return $this; 239 | } 240 | // save unknown attribute by default 241 | else if( $this->allowUndefinedAttribute ) 242 | { 243 | $this->setAttributeValue( $name, $args[0] ); 244 | } 245 | else { 246 | throw new Exception("Undefined attribute $name, Do you want to use allowUndefinedAttribute option?"); 247 | } 248 | } 249 | 250 | 251 | public function __call($method,$args) 252 | { 253 | $this->setAttribute($method,$args); 254 | return $this; 255 | } 256 | 257 | 258 | 259 | /** 260 | * ========================================== 261 | * Magic methods for convinence. 262 | * ========================================== 263 | */ 264 | 265 | 266 | public function offsetSet($name,$value) 267 | { 268 | $this->setAttribute($name, array($value)); 269 | } 270 | 271 | public function offsetExists($name) 272 | { 273 | return isset($this->_attributes[ $name ]); 274 | } 275 | 276 | public function offsetGet($name) 277 | { 278 | if( ! isset( $this->_attributes[ $name ] ) ) { 279 | // detect type for setting up default value. 280 | $type = @$this->_supportedAttributes[ $name ]; 281 | if( $type == self::ATTR_ARRAY ) { 282 | $this->_attributes[ $name ] = array(); 283 | } 284 | } 285 | $val =& $this->_attributes[ $name ]; 286 | return $val; 287 | } 288 | 289 | public function offsetUnset($name) 290 | { 291 | unset($this->_attributes[$name]); 292 | } 293 | 294 | 295 | 296 | // -------------------------- end of cascading attributes 297 | 298 | 299 | // ================================= 300 | // Element methods and members 301 | // ================================= 302 | 303 | 304 | /** 305 | * element tag name 306 | */ 307 | public $tagName; 308 | 309 | /** 310 | * @var array class name 311 | */ 312 | protected $class = array(); 313 | 314 | 315 | /** 316 | * @var Use close tag with empty children, when this option is on, 317 | * A tag with no children is rendered as " ". 318 | */ 319 | public $closeEmpty = false; 320 | 321 | /** 322 | * Children elements 323 | * 324 | * @var array 325 | */ 326 | public $children = array(); 327 | 328 | 329 | /** 330 | * @var id field 331 | */ 332 | public $id; 333 | 334 | /** 335 | * @var array Standard attribute from element class member. 336 | */ 337 | protected $standardAttributes = array( 338 | /* core attributes */ 339 | 'class','id' 340 | ); 341 | 342 | /** 343 | * @var array Custom attributes (append your attribute name to render class 344 | * member as attribute) 345 | */ 346 | protected $customAttributes = array(); 347 | 348 | 349 | 350 | 351 | 352 | protected function init($attributes) 353 | { 354 | 355 | } 356 | 357 | 358 | /** 359 | * Add custom attribute name (will be rendered) 360 | * 361 | * @param string $attribute Attribute name 362 | */ 363 | public function registerCustomAttribute($attribute) 364 | { 365 | $this->customAttributes[] = $attribute; 366 | return $this; 367 | } 368 | 369 | 370 | /** 371 | * Add attribute to customAttribute list 372 | * 373 | * @param string|array $attributes 374 | * 375 | * $this->addAttributes('id class for'); 376 | */ 377 | public function registerCustomAttributes($attributes) 378 | { 379 | if( is_string($attributes) ) { 380 | $attributes = explode(' ',$attributes); 381 | } 382 | $this->customAttributes = array_merge( $this->customAttributes , (array) $attributes ); 383 | return $this; 384 | } 385 | 386 | 387 | /** 388 | * 389 | * @param string $class class name 390 | */ 391 | public function addClass($class) 392 | { 393 | if ( is_array($this->class) ) { 394 | if( is_array($class) ) { 395 | $this->class = array_merge( $this->class , $class ); 396 | } else { 397 | $this->class[] = $class; 398 | } 399 | } elseif ( is_string($this->class) ) { 400 | $this->class .= " " . $class; 401 | } else { 402 | throw new Exception("Wrong class name type, array expected."); 403 | } 404 | return $this; 405 | } 406 | 407 | /** 408 | * @param string $class 409 | * @return bool 410 | */ 411 | public function hasClass($class) 412 | { 413 | return array_search($class,$this->class) !== false; 414 | } 415 | 416 | 417 | /** 418 | * @param string $class class name 419 | */ 420 | public function removeClass($class) 421 | { 422 | $index = array_search( $class, $this->class ); 423 | array_splice( $this->class, $index , 1 ); 424 | return $this; 425 | } 426 | 427 | /** 428 | * Add class 429 | */ 430 | public function getClass() 431 | { 432 | return $this->class; 433 | } 434 | 435 | 436 | /** 437 | * Set element id 438 | * 439 | * @param string $id add identifier attribute 440 | */ 441 | public function setId($id) 442 | { 443 | $this->id = $id; 444 | return $this; 445 | } 446 | 447 | public function getId($id) 448 | { 449 | return $this->id; 450 | } 451 | 452 | 453 | /** 454 | * Prepend Child element. 455 | * 456 | * @param FormKit\Element 457 | */ 458 | public function prepend($child) 459 | { 460 | array_splice($this->children,0,0,array($child)); 461 | return $this; 462 | } 463 | 464 | 465 | public function insert($child) 466 | { 467 | array_splice($this->children,0,0,array($child)); 468 | return $this; 469 | } 470 | 471 | /** 472 | * Insert child at index position. 473 | * 474 | * @param FormKit\Element $child 475 | * @param integer $pos index position 476 | */ 477 | public function insertChild($child, $pos = 0) 478 | { 479 | array_splice($this->children, $pos, 0, $child); 480 | return $this; 481 | } 482 | 483 | 484 | /** 485 | * Append child element at the end of list. 486 | * 487 | * @param FormKit\Element $child 488 | */ 489 | public function append($child) 490 | { 491 | $this->children[] = $child; 492 | return $this; 493 | } 494 | 495 | 496 | public function setInnerText($text) 497 | { 498 | $this->children = array(new DOMText($text)); 499 | } 500 | 501 | 502 | public function setInnerHtml($html) 503 | { 504 | $this->children = array(strval($html)); 505 | } 506 | 507 | /** 508 | * Append DOMText node to children list. 509 | */ 510 | public function appendText($text) 511 | { 512 | if ( $text ) { 513 | $this->addChild( new DOMText($text) ); 514 | } 515 | return $this; 516 | } 517 | 518 | 519 | 520 | /** 521 | * As same as `append` method 522 | * 523 | * @param FormKit\Element $child 524 | */ 525 | public function addChild($child) 526 | { 527 | $this->children[] = $child; 528 | return $this; 529 | } 530 | 531 | 532 | public function appendTo($container) 533 | { 534 | $container->append($this); 535 | return $this; 536 | } 537 | 538 | 539 | /** 540 | * Check if this node contains children. 541 | * 542 | * @return bool 543 | */ 544 | public function hasChildren() 545 | { 546 | return !empty($this->children); 547 | } 548 | 549 | /** 550 | * Return children elements 551 | * 552 | * @return array FormKit\Element[] 553 | */ 554 | public function getChildren() 555 | { 556 | return $this->children; 557 | } 558 | 559 | public function getChildrenSize() 560 | { 561 | return count($this->children); 562 | } 563 | 564 | public function getChildAt($index) 565 | { 566 | if (isset($this->children[$index])) { 567 | return $this->children[$index]; 568 | } 569 | } 570 | 571 | public function removeChildAt($index) 572 | { 573 | $removed = array_splice($this->children, $index, 1); 574 | return $removed; 575 | } 576 | 577 | 578 | protected function _renderNodes(array $nodes) 579 | { 580 | $html = ''; 581 | foreach($nodes as $node) 582 | { 583 | if ($node instanceof DOMText || $node instanceof DOMNode ) { 584 | // to use C14N(), the DOMNode must be belongs to an instance of DOMDocument. 585 | $dom = new DOMDocument; 586 | $node2 = $dom->importNode($node); 587 | $dom->appendChild($node2); 588 | $html .= $node2->C14N();; 589 | } elseif (is_string($node) ) { 590 | $html .= $node; 591 | } elseif (is_object($node) 592 | && ($node instanceof \FormKit\Element 593 | || $node instanceof \FormKit\Layout\BaseLayout 594 | || method_exists($node,'render') )) 595 | { 596 | $html .= $node->render(); 597 | } 598 | else 599 | { 600 | throw new Exception('Unknown node type'); 601 | } 602 | } 603 | return $html; 604 | } 605 | 606 | 607 | /** 608 | * Render children nodes 609 | */ 610 | public function renderChildren() 611 | { 612 | if ($this->hasChildren()) { 613 | return $this->_renderNodes($this->children); 614 | } 615 | return ''; 616 | } 617 | 618 | /** 619 | * Set attributes from array 620 | * 621 | * @param array $attributes 622 | */ 623 | public function setAttributes($attributes) 624 | { 625 | foreach( $attributes as $k => $val ) { 626 | if ($this->isIgnoredAttribute($k)) { 627 | continue; 628 | } 629 | 630 | // this is for adding new class name with 631 | // +=newClass 632 | if (is_string($val) && strpos($val ,'+=') !== false ) { 633 | $origValue = $this->getAttributeValue($k); 634 | if( is_string($origValue) ) { 635 | $origValue .= ' ' . substr($val,2); 636 | } elseif ( is_array($origValue) ) { 637 | $origValue[] = substr($val,2); 638 | } elseif ( is_object($origValue) ) { 639 | throw new Exception('Invalid Object for attribute: ' . get_class($origValue) ); 640 | } else { 641 | throw new Exception('Unknown attribute value type.'); 642 | } 643 | $this->setAttributeValue($k,$origValue); 644 | } else { 645 | $this->setAttributeValue($k, $val); 646 | } 647 | } 648 | } 649 | 650 | /** 651 | * Render attributes string 652 | * 653 | * @return string Standard Attribute string 654 | */ 655 | public function renderAttributes() 656 | { 657 | return $this->_renderAttributes($this->standardAttributes) 658 | . $this->_renderAttributes($this->customAttributes) 659 | . $this->_renderAttributes(array_keys($this->_attributes), true); 660 | } 661 | 662 | /** 663 | * Render attributes 664 | * 665 | * @param array $keys 666 | * @return string 667 | */ 668 | protected function _renderAttributes($keys, $allowNull = false) 669 | { 670 | $html = ''; 671 | foreach($keys as $key) { 672 | if ($this->hasAttribute($key)) { 673 | $val = $this->getAttributeValue($key); 674 | 675 | if (!$allowNull && ($val === NULL || (is_array($val) && empty($val))) ) 676 | continue; 677 | 678 | if (is_array($val)) { 679 | // check if the array is an indexed array, check keys of 680 | // array[0..cnt] 681 | // 682 | // if it's an indexed array 683 | // for attributes key like "class", the value can be 684 | // 685 | // array('class1','class2') 686 | // 687 | // this renders the attribute as "class1 class2" 688 | // 689 | // if it's an associative array 690 | // for attribute key like "style", the value can be 691 | // 692 | // array( 'border' => '1px solid #ccc' ) 693 | // 694 | // this renders the attribute as 695 | // 696 | // "border: 1px solid #ccc;" 697 | // 698 | if (array_keys($val) === range(0, count($val)-1) ) { 699 | $val = join(' ', $val); 700 | } else { 701 | $val0 = $val; 702 | $val = ''; 703 | foreach( $val0 as $name => $data ) { 704 | $val .= "$name:$data;"; 705 | } 706 | } 707 | } 708 | // for boolean type values like readonly attribute, 709 | // we render it as readonly="readonly". 710 | elseif ($val === TRUE || $val === FALSE) { 711 | $val = $key; 712 | } 713 | 714 | // Convert camalcase name to dash-separated name 715 | // 716 | // for dataUrl attributes, render these attributes like data-url 717 | // ( use dash separator) 718 | if ($val === NULL) { 719 | $html .= sprintf(' %s',strtolower(preg_replace('/[A-Z]/', '-$0', $key))); 720 | } else { 721 | $html .= sprintf(' %s="%s"', 722 | strtolower(preg_replace('/[A-Z]/', '-$0', $key)), 723 | htmlspecialchars( $val ) 724 | ); 725 | } 726 | } 727 | } 728 | return $html; 729 | } 730 | 731 | 732 | /** 733 | * Render open tag 734 | * 735 | * 736 | * $form->open(); 737 | * 738 | * $form->renderChildren(); 739 | * 740 | * $form->close(); 741 | */ 742 | public function open($attributes = array()) 743 | { 744 | $this->setAttributes( $attributes ); 745 | $html = '<' . $this->tagName 746 | . $this->renderAttributes() 747 | . ($this->extraAttributeString ?: '') 748 | ; 749 | // should we close it ? 750 | if ($this->closeEmpty || $this->hasChildren()) { 751 | $html .= '>'; 752 | } else { 753 | $html .= '/>'; 754 | } 755 | return $html; 756 | } 757 | 758 | /** 759 | * Render close tag 760 | */ 761 | public function close() 762 | { 763 | $html = ''; 764 | if ($this->closeEmpty || $this->hasChildren()) { 765 | $html .= 'tagName . '>'; 766 | } 767 | return $html; 768 | } 769 | 770 | 771 | /** 772 | * Render the whole element. 773 | * 774 | * @param array $attributes attributes to override. 775 | * @param string HTML 776 | */ 777 | public function render($attributes = array()) 778 | { 779 | if (!$this->tagName) { 780 | throw new Exception('tagName is not defined.'); 781 | } 782 | $html = $this->open( $attributes ); 783 | $html .= $this->renderChildren(); 784 | $html .= $this->close(); 785 | return $html; 786 | } 787 | 788 | public function formatRender($attributes = array()) 789 | { 790 | $html = $this->render($attributes); 791 | $dom = new DOMDocument('1.0'); 792 | $dom->preserveWhiteSpace = true; 793 | $dom->formatOutput = true; 794 | $dom->strictErrorChecking = true; 795 | $dom->validateOnParse = false; 796 | $dom->resolveExternals = false; 797 | $dom->loadXML($html); 798 | 799 | $prettyHTML = ''; 800 | foreach ($dom->childNodes as $node) { 801 | $prettyHTML .= $dom->saveXML($node) . "\n"; 802 | } 803 | return $prettyHTML; 804 | } 805 | 806 | 807 | public function __toString() 808 | { 809 | return $this->render(); 810 | } 811 | } 812 | 813 | -------------------------------------------------------------------------------- /src/WebUI/Core/Span.php: -------------------------------------------------------------------------------- 1 | tagName, $attributes); 12 | } 13 | } 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /tests/WebUI/Components/BreadcrumbsTest.php: -------------------------------------------------------------------------------- 1 | append('>'); 11 | $el->addClass('separator'); 12 | 13 | $breadcrumbs = new Breadcrumbs; 14 | ok($breadcrumbs); 15 | 16 | $breadcrumbs->setSeparatorElement($el); 17 | 18 | $breadcrumbs->appendIndexLink('Home', '/', 'The Home Page'); 19 | 20 | $breadcrumbs->appendLink('Product', '/product', 'All Products'); 21 | 22 | $breadcrumbs->appendLink('Product A123', '/product/a123', 'Product A123'); 23 | 24 | ok($html = $breadcrumbs->render()); 25 | // echo $html, "\n\n"; 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /tests/WebUI/Components/Menu/MenuTest.php: -------------------------------------------------------------------------------- 1 | setTitle('Product Collection'); 14 | $item->setLink('Product Collection', [ 15 | 'href' => '/products', 16 | 'data-target' => '#productContainer', 17 | 'dataContainer' => 'body' 18 | ]); 19 | ok('
  • Product Collection
  • ',$item->render()); 20 | } 21 | 22 | 23 | public function testMenuFolder() 24 | { 25 | $menu = new MenuFolder('Products'); 26 | $item1 = $menu->appendLink('Car', [ 'href' => '/products/car' ]); 27 | ok($item1); 28 | $item2 = $menu->appendLink('Bicycle', [ 'href' => '/products/bicycle' ]); 29 | ok($item2); 30 | $item3 = $menu->appendLink('Truck', [ 'href' => '/products/truck' ]); 31 | ok($item3); 32 | 33 | $item4 = $menu->appendLink('Others', [ 'href' => '/products/others' ]); 34 | ok($item4); 35 | $html = $menu->render(); 36 | //var_dump( $html ); 37 | // file_put_contents('test.html', '' . $html . ''); 38 | } 39 | 40 | public function testMenu() 41 | { 42 | $menu = new Menu; 43 | $collection = $menu->appendCollection([], 'main'); 44 | $collection->appendLink('Car', ['href' => '/products/car']); 45 | $collection->appendLink('Bicycle', ['href' => '/products/bicycle']); 46 | $folder = $collection->appendFolder('Others'); 47 | $folder->appendLink('A', [ 'href' => '/products/a']); 48 | $folder->appendLink('B', [ 'href' => '/products/b']); 49 | 50 | $collection = $menu->appendCollection([], 'second'); 51 | $folder = $collection->appendFolder('Others2'); 52 | $folder->appendLink('C', [ 'href' => '/products/c']); 53 | $folder->appendLink('D', [ 'href' => '/products/d']); 54 | 55 | $html = $menu->render(); 56 | 57 | //echo $html; 58 | file_put_contents('test.html', '' . $html . ''); 59 | } 60 | 61 | public function testMenuItemCollection() 62 | { 63 | $menu = new MenuItemCollection; 64 | $item1 = $menu->appendLink('Car', [ 'href' => '/products/car' ]); 65 | ok($item1); 66 | $folder = $menu->appendFolder('Others'); 67 | ok($folder); 68 | $folder->appendLink('A', [ 'href' => '/products/a']); 69 | $folder->appendLink('B', [ 'href' => '/products/b']); 70 | $html = $menu->render(); 71 | 72 | $dom = new DOMDocument('1.0'); 73 | $dom->preserveWhiteSpace = false; 74 | $dom->formatOutput = true; 75 | $dom->loadHtml($html); 76 | echo $dom->saveHTML(); 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /tests/WebUI/Components/PagerTest.php: -------------------------------------------------------------------------------- 1 | setBaseUrl('/product'); 10 | $html = $pager->render(); 11 | 12 | $dom = new DOMDocument('1.0'); 13 | $dom->loadXml($html); 14 | $navs = $dom->getElementsByTagName('nav'); 15 | is(1, $navs->length); 16 | 17 | $lis = $dom->getElementsByTagName('li'); 18 | is(8, $lis->length); 19 | } 20 | } 21 | 22 | -------------------------------------------------------------------------------- /tests/WebUI/Components/React/ReactComponentTest.php: -------------------------------------------------------------------------------- 1 | 'setting' )); 9 | $out = $component->render(); 10 | echo $out; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tests/WebUI/Core/ElementTest.php: -------------------------------------------------------------------------------- 1 | 'menu' 10 | ]); 11 | $element->append(new Element('li')); 12 | $element->append(new Element('li')); 13 | $html = $element->formatRender(); 14 | $this->assertNotNull($html); 15 | } 16 | } 17 | 18 | --------------------------------------------------------------------------------