├── README.md ├── blank └── app │ └── code │ └── Namespace │ └── Module │ ├── Block │ ├── Adminhtml │ │ ├── Form │ │ │ └── Element │ │ │ │ └── Image.php │ │ ├── Module.php │ │ └── Module │ │ │ ├── Edit.php │ │ │ ├── Edit │ │ │ ├── Form.php │ │ │ ├── Tab │ │ │ │ ├── Content.php │ │ │ │ ├── Image.php │ │ │ │ └── Main.php │ │ │ └── Tabs.php │ │ │ └── Grid.php │ ├── Module.php │ └── View.php │ ├── Controller │ ├── AbstractController │ │ ├── ModuleLoader.php │ │ ├── ModuleLoaderInterface.php │ │ └── View.php │ ├── Adminhtml │ │ └── Index │ │ │ ├── Delete.php │ │ │ ├── Edit.php │ │ │ ├── Grid.php │ │ │ ├── Index.php │ │ │ ├── NewAction.php │ │ │ ├── PostDataProcessor.php │ │ │ └── Save.php │ ├── Index │ │ ├── Index.php │ │ └── View.php │ └── ModuleInterface.php │ ├── Helper │ └── Data.php │ ├── Model │ ├── Module.php │ └── ResourceModel │ │ ├── Module.php │ │ └── Module │ │ └── Collection.php │ ├── Setup │ └── InstallSchema.php │ ├── etc │ ├── acl.xml │ ├── adminhtml │ │ ├── menu.xml │ │ ├── routes.xml │ │ └── system.xml │ ├── config.xml │ ├── frontend │ │ ├── di.xml │ │ └── routes.xml │ └── module.xml │ ├── i18n │ └── en_US.csv │ ├── registration.php │ └── view │ ├── adminhtml │ └── layout │ │ ├── module_index_edit.xml │ │ ├── module_index_grid.xml │ │ ├── module_index_index.xml │ │ └── module_index_new.xml │ └── frontend │ ├── layout │ ├── default.xml │ ├── module_index_index.xml │ └── module_index_view.xml │ └── templates │ ├── module.phtml │ └── view.phtml ├── form.php ├── index.php ├── js ├── jquery-1.11.1.js ├── jquery.js └── jquery.validate.js └── main.css /README.md: -------------------------------------------------------------------------------- 1 | # magento2-module-creator 2 | Magento 2 Module Creator 3 | 4 | 10 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Adminhtml/Form/Element/Image.php: -------------------------------------------------------------------------------- 1 | Form Image File Element Block 5 | * 6 | */ 7 | namespace \\Block\Adminhtml\Form\Element; 8 | 9 | class Image extends Magento\Framework\Data\Form\Element\Image 10 | { 11 | /** 12 | * Get image preview url 13 | * 14 | * @return string 15 | */ 16 | protected function _getUrl() 17 | { 18 | return $this->getValue(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Adminhtml/Module.php: -------------------------------------------------------------------------------- 1 | list block 4 | * 5 | */ 6 | namespace \\Block\Adminhtml; 7 | 8 | class extends \Magento\Backend\Block\Widget\Grid\Container 9 | { 10 | /** 11 | * Constructor 12 | * 13 | * @return void 14 | */ 15 | protected function _construct() 16 | { 17 | $this->_controller = 'adminhtml_'; 18 | $this->_blockGroup = '_'; 19 | $this->_headerText = __(''); 20 | $this->_addButtonLabel = __('Add New '); 21 | parent::_construct(); 22 | if ($this->_isAllowedAction('_::save')) { 23 | $this->buttonList->update('add', 'label', __('Add New ')); 24 | } else { 25 | $this->buttonList->remove('add'); 26 | } 27 | } 28 | 29 | /** 30 | * Check permission for passed action 31 | * 32 | * @param string $resourceId 33 | * @return bool 34 | */ 35 | protected function _isAllowedAction($resourceId) 36 | { 37 | return $this->_authorization->isAllowed($resourceId); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit.php: -------------------------------------------------------------------------------- 1 | \\Block\Adminhtml\; 3 | 4 | /** 5 | * Admin page 6 | * 7 | */ 8 | class Edit extends \Magento\Backend\Block\Widget\Form\Container 9 | { 10 | /** 11 | * Core registry 12 | * 13 | * @var \Magento\Framework\Registry 14 | */ 15 | protected $_coreRegistry = null; 16 | 17 | /** 18 | * @param \Magento\Backend\Block\Widget\Context $context 19 | * @param \Magento\Framework\Registry $registry 20 | * @param array $data 21 | */ 22 | public function __construct( 23 | \Magento\Backend\Block\Widget\Context $context, 24 | \Magento\Framework\Registry $registry, 25 | array $data = [] 26 | ) { 27 | $this->_coreRegistry = $registry; 28 | parent::__construct($context, $data); 29 | } 30 | 31 | /** 32 | * Initialize cms page edit block 33 | * 34 | * @return void 35 | */ 36 | protected function _construct() 37 | { 38 | $this->_objectId = '_id'; 39 | $this->_blockGroup = '_'; 40 | $this->_controller = 'adminhtml_'; 41 | 42 | parent::_construct(); 43 | 44 | if ($this->_isAllowedAction('_::save')) { 45 | $this->buttonList->update('save', 'label', __('Save ')); 46 | $this->buttonList->add( 47 | 'saveandcontinue', 48 | [ 49 | 'label' => __('Save and Continue Edit'), 50 | 'class' => 'save', 51 | 'data_attribute' => [ 52 | 'mage-init' => [ 53 | 'button' => ['event' => 'saveAndContinueEdit', 'target' => '#edit_form'], 54 | ], 55 | ] 56 | ], 57 | -100 58 | ); 59 | } else { 60 | $this->buttonList->remove('save'); 61 | } 62 | 63 | if ($this->_isAllowedAction('_::_delete')) { 64 | $this->buttonList->update('delete', 'label', __('Delete ')); 65 | } else { 66 | $this->buttonList->remove('delete'); 67 | } 68 | } 69 | 70 | /** 71 | * Retrieve text for header element depending on loaded page 72 | * 73 | * @return string 74 | */ 75 | public function getHeaderText() 76 | { 77 | if ($this->_coreRegistry->registry('')->getId()) { 78 | return __("Edit '%1'", $this->escapeHtml($this->_coreRegistry->registry('')->getTitle())); 79 | } else { 80 | return __('New '); 81 | } 82 | } 83 | 84 | /** 85 | * Check permission for passed action 86 | * 87 | * @param string $resourceId 88 | * @return bool 89 | */ 90 | protected function _isAllowedAction($resourceId) 91 | { 92 | return $this->_authorization->isAllowed($resourceId); 93 | } 94 | 95 | /** 96 | * Getter of url for "Save and Continue" button 97 | * tab_id will be replaced by desired by JS later 98 | * 99 | * @return string 100 | */ 101 | protected function _getSaveAndContinueUrl() 102 | { 103 | return $this->getUrl('/*/save', ['_current' => true, 'back' => 'edit', 'active_tab' => '{{tab_id}}']); 104 | } 105 | 106 | /** 107 | * Prepare layout 108 | * 109 | * @return \Magento\Framework\View\Element\AbstractBlock 110 | */ 111 | protected function _prepareLayout() 112 | { 113 | $this->_formScripts[] = " 114 | function toggleEditor() { 115 | if (tinyMCE.getInstanceById('page_content') == null) { 116 | tinyMCE.execCommand('mceAddControl', false, 'page_content'); 117 | } else { 118 | tinyMCE.execCommand('mceRemoveControl', false, 'page_content'); 119 | } 120 | }; 121 | "; 122 | return parent::_prepareLayout(); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Form.php: -------------------------------------------------------------------------------- 1 | \\Block\Adminhtml\\Edit; 3 | 4 | /** 5 | * Adminhtml edit form block 6 | * 7 | */ 8 | class Form extends \Magento\Backend\Block\Widget\Form\Generic 9 | { 10 | /** 11 | * Prepare form 12 | * 13 | * @return $this 14 | */ 15 | protected function _prepareForm() 16 | { 17 | /** @var \Magento\Framework\Data\Form $form */ 18 | $form = $this->_formFactory->create( 19 | ['data' => ['id' => 'edit_form', 'action' => $this->getData('action'), 'method' => 'post','enctype' => 'multipart/form-data']] 20 | ); 21 | $form->setUseContainer(true); 22 | $this->setForm($form); 23 | return parent::_prepareForm(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Tab/Content.php: -------------------------------------------------------------------------------- 1 | \\Block\Adminhtml\\Edit\Tab; 3 | 4 | /** 5 | * edit form main tab 6 | */ 7 | class Content extends \Magento\Backend\Block\Widget\Form\Generic implements 8 | \Magento\Backend\Block\Widget\Tab\TabInterface 9 | { 10 | /** 11 | * @var \Magento\Cms\Model\Wysiwyg\Config 12 | */ 13 | protected $_wysiwygConfig; 14 | 15 | /** 16 | * @param \Magento\Backend\Block\Template\Context $context 17 | * @param \Magento\Framework\Registry $registry 18 | * @param \Magento\Framework\Data\FormFactory $formFactory 19 | * @param \Magento\Cms\Model\Wysiwyg\Config $wysiwygConfig 20 | * @param array $data 21 | */ 22 | public function __construct( 23 | \Magento\Backend\Block\Template\Context $context, 24 | \Magento\Framework\Registry $registry, 25 | \Magento\Framework\Data\FormFactory $formFactory, 26 | \Magento\Cms\Model\Wysiwyg\Config $wysiwygConfig, 27 | array $data = [] 28 | ) { 29 | $this->_wysiwygConfig = $wysiwygConfig; 30 | parent::__construct($context, $registry, $formFactory, $data); 31 | } 32 | 33 | /** 34 | * Prepare form 35 | * 36 | * @return $this 37 | */ 38 | protected function _prepareForm() 39 | { 40 | /** @var $model \Model\ */ 41 | $model = $this->_coreRegistry->registry(''); 42 | 43 | /* 44 | * Checking if user have permissions to save information 45 | */ 46 | if ($this->_isAllowedAction('_::save')) { 47 | $isElementDisabled = false; 48 | } else { 49 | $isElementDisabled = true; 50 | } 51 | 52 | /** @var \Magento\Framework\Data\Form $form */ 53 | $form = $this->_formFactory->create(); 54 | 55 | $form->setHtmlIdPrefix('_content_'); 56 | 57 | $fieldset = $form->addFieldset( 58 | 'content_fieldset', 59 | ['legend' => __('Content'), 'class' => 'fieldset-wide'] 60 | ); 61 | 62 | $wysiwygConfig = $this->_wysiwygConfig->getConfig(['tab_id' => $this->getTabId()]); 63 | 64 | $contentField = $fieldset->addField( 65 | 'content', 66 | 'editor', 67 | [ 68 | 'name' => 'content', 69 | 'style' => 'height:36em;', 70 | 'required' => true, 71 | 'disabled' => $isElementDisabled, 72 | 'config' => $wysiwygConfig 73 | ] 74 | ); 75 | 76 | // Setting custom renderer for content field to remove label column 77 | $renderer = $this->getLayout()->createBlock( 78 | 'Magento\Backend\Block\Widget\Form\Renderer\Fieldset\Element' 79 | )->setTemplate( 80 | 'Magento_Cms::page/edit/form/renderer/content.phtml' 81 | ); 82 | $contentField->setRenderer($renderer); 83 | 84 | $this->_eventManager->dispatch('adminhtml__edit_tab_content_prepare_form', ['form' => $form]); 85 | $form->setValues($model->getData()); 86 | $this->setForm($form); 87 | 88 | return parent::_prepareForm(); 89 | } 90 | 91 | /** 92 | * Prepare label for tab 93 | * 94 | * @return string 95 | */ 96 | public function getTabLabel() 97 | { 98 | return __('Content'); 99 | } 100 | 101 | /** 102 | * Prepare title for tab 103 | * 104 | * @return string 105 | */ 106 | public function getTabTitle() 107 | { 108 | return __('Content'); 109 | } 110 | 111 | /** 112 | * Returns status flag about this tab can be shown or not 113 | * 114 | * @return bool 115 | */ 116 | public function canShowTab() 117 | { 118 | return true; 119 | } 120 | 121 | /** 122 | * Returns status flag about this tab hidden or not 123 | * 124 | * @return bool 125 | */ 126 | public function isHidden() 127 | { 128 | return false; 129 | } 130 | 131 | /** 132 | * Check permission for passed action 133 | * 134 | * @param string $resourceId 135 | * @return bool 136 | */ 137 | protected function _isAllowedAction($resourceId) 138 | { 139 | return $this->_authorization->isAllowed($resourceId); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Tab/Image.php: -------------------------------------------------------------------------------- 1 | \\Block\Adminhtml\\Edit\Tab; 3 | 4 | /** 5 | * @SuppressWarnings(PHPMD.DepthOfInheritance) 6 | */ 7 | class Image extends \Magento\Backend\Block\Widget\Form\Generic implements 8 | \Magento\Backend\Block\Widget\Tab\TabInterface 9 | { 10 | 11 | /** 12 | * @param \Magento\Backend\Block\Template\Context $context 13 | * @param \Magento\Framework\Registry $registry 14 | * @param \Magento\Framework\Data\FormFactory $formFactory 15 | * @param array $data 16 | */ 17 | public function __construct( 18 | \Magento\Backend\Block\Template\Context $context, 19 | \Magento\Framework\Registry $registry, 20 | \Magento\Framework\Data\FormFactory $formFactory, 21 | array $data = [] 22 | ) { 23 | parent::__construct($context, $registry, $formFactory, $data); 24 | } 25 | 26 | /** 27 | * Initialise form fields 28 | * 29 | * @return $this 30 | * @SuppressWarnings(PHPMD.ExcessiveMethodLength) 31 | */ 32 | protected function _prepareForm() 33 | { 34 | /** @var \Magento\Framework\Data\Form $form */ 35 | $form = $this->_formFactory->create(['data' => ['html_id_prefix' => '_image_']]); 36 | 37 | $model = $this->_coreRegistry->registry(''); 38 | 39 | /* 40 | * Checking if user have permissions to save information 41 | */ 42 | if ($this->_isAllowedAction('_::save')) { 43 | $isElementDisabled = false; 44 | } else { 45 | $isElementDisabled = true; 46 | } 47 | 48 | $layoutFieldset = $form->addFieldset( 49 | 'image_fieldset', 50 | ['legend' => __('Image Thumbnail'), 'class' => 'fieldset-wide', 'disabled' => $isElementDisabled] 51 | ); 52 | 53 | $layoutFieldset->addField( 54 | 'image', 55 | 'image', 56 | [ 57 | 'name' => 'image', 58 | 'label' => __('Image'), 59 | 'title' => __('Image'), 60 | 'required' => false, 61 | 'disabled' => $isElementDisabled 62 | ] 63 | ); 64 | 65 | $this->_eventManager->dispatch('adminhtml__edit_tab_image_prepare_form', ['form' => $form]); 66 | 67 | $form->setValues($model->getData()); 68 | 69 | $this->setForm($form); 70 | 71 | return parent::_prepareForm(); 72 | } 73 | 74 | /** 75 | * Prepare label for tab 76 | * 77 | * @return string 78 | */ 79 | public function getTabLabel() 80 | { 81 | return __('Image Thumbnail'); 82 | } 83 | 84 | /** 85 | * Prepare title for tab 86 | * 87 | * @return string 88 | */ 89 | public function getTabTitle() 90 | { 91 | return __('Image Thumbnail'); 92 | } 93 | 94 | /** 95 | * {@inheritdoc} 96 | */ 97 | public function canShowTab() 98 | { 99 | return true; 100 | } 101 | 102 | /** 103 | * {@inheritdoc} 104 | */ 105 | public function isHidden() 106 | { 107 | return false; 108 | } 109 | 110 | /** 111 | * Check permission for passed action 112 | * 113 | * @param string $resourceId 114 | * @return bool 115 | */ 116 | protected function _isAllowedAction($resourceId) 117 | { 118 | return $this->_authorization->isAllowed($resourceId); 119 | } 120 | 121 | /** 122 | * Return predefined additional element types 123 | * 124 | * @return array 125 | */ 126 | protected function _getAdditionalElementTypes() 127 | { 128 | return ['image' => '\\Block\Adminhtml\Form\Element\Image']; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Tab/Main.php: -------------------------------------------------------------------------------- 1 | \\Block\Adminhtml\\Edit\Tab; 3 | 4 | /** 5 | * Cms page edit form main tab 6 | */ 7 | class Main extends \Magento\Backend\Block\Widget\Form\Generic implements \Magento\Backend\Block\Widget\Tab\TabInterface 8 | { 9 | /** 10 | * @var \Magento\Store\Model\System\Store 11 | */ 12 | protected $_systemStore; 13 | 14 | /** 15 | * @param \Magento\Backend\Block\Template\Context $context 16 | * @param \Magento\Framework\Registry $registry 17 | * @param \Magento\Framework\Data\FormFactory $formFactory 18 | * @param \Magento\Store\Model\System\Store $systemStore 19 | * @param array $data 20 | */ 21 | public function __construct( 22 | \Magento\Backend\Block\Template\Context $context, 23 | \Magento\Framework\Registry $registry, 24 | \Magento\Framework\Data\FormFactory $formFactory, 25 | \Magento\Store\Model\System\Store $systemStore, 26 | array $data = [] 27 | ) { 28 | $this->_systemStore = $systemStore; 29 | parent::__construct($context, $registry, $formFactory, $data); 30 | } 31 | 32 | /** 33 | * Prepare form 34 | * 35 | * @return $this 36 | */ 37 | protected function _prepareForm() 38 | { 39 | /* @var $model \Magento\Cms\Model\Page */ 40 | $model = $this->_coreRegistry->registry(''); 41 | 42 | /* 43 | * Checking if user have permissions to save information 44 | */ 45 | if ($this->_isAllowedAction('_::save')) { 46 | $isElementDisabled = false; 47 | } else { 48 | $isElementDisabled = true; 49 | } 50 | 51 | /** @var \Magento\Framework\Data\Form $form */ 52 | $form = $this->_formFactory->create(); 53 | 54 | $form->setHtmlIdPrefix('_main_'); 55 | 56 | $fieldset = $form->addFieldset('base_fieldset', ['legend' => __(' Information')]); 57 | 58 | if ($model->getId()) { 59 | $fieldset->addField('_id', 'hidden', ['name' => '_id']); 60 | } 61 | 62 | $fieldset->addField( 63 | 'title', 64 | 'text', 65 | [ 66 | 'name' => 'title', 67 | 'label' => __(' Title'), 68 | 'title' => __(' Title'), 69 | 'required' => true, 70 | 'disabled' => $isElementDisabled 71 | ] 72 | ); 73 | 74 | $fieldset->addField( 75 | 'author', 76 | 'text', 77 | [ 78 | 'name' => 'author', 79 | 'label' => __('Author'), 80 | 'title' => __('Author'), 81 | 'required' => true, 82 | 'disabled' => $isElementDisabled 83 | ] 84 | ); 85 | 86 | $dateFormat = $this->_localeDate->getDateFormat(\IntlDateFormatter::SHORT); 87 | $fieldset->addField('published_at', 'date', [ 88 | 'name' => 'published_at', 89 | 'date_format' => $dateFormat, 90 | 'image' => $this->getViewFileUrl('images/grid-cal.gif'), 91 | 'value' => $model->getPublishedAt(), 92 | 'label' => __('Publishing Date'), 93 | 'title' => __('Publishing Date'), 94 | 'required' => true 95 | ]); 96 | 97 | $this->_eventManager->dispatch('adminhtml__edit_tab_main_prepare_form', ['form' => $form]); 98 | 99 | $form->setValues($model->getData()); 100 | $this->setForm($form); 101 | 102 | return parent::_prepareForm(); 103 | } 104 | 105 | /** 106 | * Prepare label for tab 107 | * 108 | * @return string 109 | */ 110 | public function getTabLabel() 111 | { 112 | return __(' Information'); 113 | } 114 | 115 | /** 116 | * Prepare title for tab 117 | * 118 | * @return string 119 | */ 120 | public function getTabTitle() 121 | { 122 | return __(' Information'); 123 | } 124 | 125 | /** 126 | * {@inheritdoc} 127 | */ 128 | public function canShowTab() 129 | { 130 | return true; 131 | } 132 | 133 | /** 134 | * {@inheritdoc} 135 | */ 136 | public function isHidden() 137 | { 138 | return false; 139 | } 140 | 141 | /** 142 | * Check permission for passed action 143 | * 144 | * @param string $resourceId 145 | * @return bool 146 | */ 147 | protected function _isAllowedAction($resourceId) 148 | { 149 | return $this->_authorization->isAllowed($resourceId); 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Tabs.php: -------------------------------------------------------------------------------- 1 | \\Block\Adminhtml\\Edit; 3 | 4 | /** 5 | * Admin left menu 6 | */ 7 | class Tabs extends \Magento\Backend\Block\Widget\Tabs 8 | { 9 | /** 10 | * @return void 11 | */ 12 | protected function _construct() 13 | { 14 | parent::_construct(); 15 | $this->setId('page_tabs'); 16 | $this->setDestElementId('edit_form'); 17 | $this->setTitle(__(' Information')); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Adminhtml/Module/Grid.php: -------------------------------------------------------------------------------- 1 | \\Block\Adminhtml\; 3 | 4 | /** 5 | * Adminhtml grid 6 | */ 7 | class Grid extends \Magento\Backend\Block\Widget\Grid\Extended 8 | { 9 | /** 10 | * @var \\\Model\ResourceModel\\CollectionFactory 11 | */ 12 | protected $_collectionFactory; 13 | 14 | /** 15 | * @var \\\Model\ 16 | */ 17 | protected $_; 18 | 19 | /** 20 | * @param \Magento\Backend\Block\Template\Context $context 21 | * @param \Magento\Backend\Helper\Data $backendHelper 22 | * @param \\\Model\ $Page 23 | * @param \\\Model\ResourceModel\\CollectionFactory $collectionFactory 24 | * @param \Magento\Core\Model\PageLayout\Config\Builder $pageLayoutBuilder 25 | * @param array $data 26 | */ 27 | public function __construct( 28 | \Magento\Backend\Block\Template\Context $context, 29 | \Magento\Backend\Helper\Data $backendHelper, 30 | \\\Model\ $, 31 | \\\Model\ResourceModel\\CollectionFactory $collectionFactory, 32 | array $data = [] 33 | ) { 34 | $this->_collectionFactory = $collectionFactory; 35 | $this->_ = $; 36 | parent::__construct($context, $backendHelper, $data); 37 | } 38 | 39 | /** 40 | * @return void 41 | */ 42 | protected function _construct() 43 | { 44 | parent::_construct(); 45 | $this->setId('Grid'); 46 | $this->setDefaultSort('_id'); 47 | $this->setDefaultDir('DESC'); 48 | $this->setUseAjax(true); 49 | $this->setSaveParametersInSession(true); 50 | } 51 | 52 | /** 53 | * Prepare collection 54 | * 55 | * @return \Magento\Backend\Block\Widget\Grid 56 | */ 57 | protected function _prepareCollection() 58 | { 59 | $collection = $this->_collectionFactory->create(); 60 | /* @var $collection \\\Model\ResourceModel\\Collection */ 61 | $this->setCollection($collection); 62 | 63 | return parent::_prepareCollection(); 64 | } 65 | 66 | /** 67 | * Prepare columns 68 | * 69 | * @return \Magento\Backend\Block\Widget\Grid\Extended 70 | */ 71 | protected function _prepareColumns() 72 | { 73 | $this->addColumn('_id', [ 74 | 'header' => __('ID'), 75 | 'index' => '_id', 76 | ]); 77 | 78 | $this->addColumn('title', ['header' => __('Title'), 'index' => 'title']); 79 | $this->addColumn('author', ['header' => __('Author'), 'index' => 'author']); 80 | 81 | $this->addColumn( 82 | 'published_at', 83 | [ 84 | 'header' => __('Published On'), 85 | 'index' => 'published_at', 86 | 'type' => 'date', 87 | 'header_css_class' => 'col-date', 88 | 'column_css_class' => 'col-date' 89 | ] 90 | ); 91 | 92 | $this->addColumn( 93 | 'created_at', 94 | [ 95 | 'header' => __('Created'), 96 | 'index' => 'created_at', 97 | 'type' => 'datetime', 98 | 'header_css_class' => 'col-date', 99 | 'column_css_class' => 'col-date' 100 | ] 101 | ); 102 | 103 | $this->addColumn( 104 | 'action', 105 | [ 106 | 'header' => __('Edit'), 107 | 'type' => 'action', 108 | 'getter' => 'getId', 109 | 'actions' => [ 110 | [ 111 | 'caption' => __('Edit'), 112 | 'url' => [ 113 | 'base' => '*/*/edit', 114 | 'params' => ['store' => $this->getRequest()->getParam('store')] 115 | ], 116 | 'field' => '_id' 117 | ] 118 | ], 119 | 'sortable' => false, 120 | 'filter' => false, 121 | 'header_css_class' => 'col-action', 122 | 'column_css_class' => 'col-action' 123 | ] 124 | ); 125 | 126 | return parent::_prepareColumns(); 127 | } 128 | 129 | /** 130 | * Row click url 131 | * 132 | * @param \Magento\Framework\Object $row 133 | * @return string 134 | */ 135 | public function getRowUrl($row) 136 | { 137 | return $this->getUrl('*/*/edit', ['_id' => $row->getId()]); 138 | } 139 | 140 | /** 141 | * Get grid url 142 | * 143 | * @return string 144 | */ 145 | public function getGridUrl() 146 | { 147 | return $this->getUrl('*/*/grid', ['_current' => true]); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/Module.php: -------------------------------------------------------------------------------- 1 | \\Block; 4 | 5 | /** 6 | * content block 7 | */ 8 | class extends \Magento\Framework\View\Element\Template 9 | { 10 | /** 11 | * collection 12 | * 13 | * @var \\Model\ResourceModel\\Collection 14 | */ 15 | protected $_Collection = null; 16 | 17 | /** 18 | * factory 19 | * 20 | * @var \\\Model\Factory 21 | */ 22 | protected $_CollectionFactory; 23 | 24 | /** @var \\\Helper\Data */ 25 | protected $_dataHelper; 26 | 27 | /** 28 | * @param \Magento\Framework\View\Element\Template\Context $context 29 | * @param \\\Model\ResourceModel\\CollectionFactory $CollectionFactory 30 | * @param array $data 31 | */ 32 | public function __construct( 33 | \Magento\Framework\View\Element\Template\Context $context, 34 | \\\Model\ResourceModel\\CollectionFactory $CollectionFactory, 35 | \\\Helper\Data $dataHelper, 36 | array $data = [] 37 | ) { 38 | $this->_CollectionFactory = $CollectionFactory; 39 | $this->_dataHelper = $dataHelper; 40 | parent::__construct( 41 | $context, 42 | $data 43 | ); 44 | } 45 | 46 | /** 47 | * Retrieve collection 48 | * 49 | * @return \\Model\ResourceModel\\Collection 50 | */ 51 | protected function _getCollection() 52 | { 53 | $collection = $this->_CollectionFactory->create(); 54 | return $collection; 55 | } 56 | 57 | /** 58 | * Retrieve prepared collection 59 | * 60 | * @return \\Model\ResourceModel\\Collection 61 | */ 62 | public function getCollection() 63 | { 64 | if (is_null($this->_Collection)) { 65 | $this->_Collection = $this->_getCollection(); 66 | $this->_Collection->setCurPage($this->getCurrentPage()); 67 | $this->_Collection->setPageSize($this->_dataHelper->getPerPage()); 68 | $this->_Collection->setOrder('published_at','asc'); 69 | } 70 | 71 | return $this->_Collection; 72 | } 73 | 74 | /** 75 | * Fetch the current page for the list 76 | * 77 | * @return int 78 | */ 79 | public function getCurrentPage() 80 | { 81 | return $this->getData('current_page') ? $this->getData('current_page') : 1; 82 | } 83 | 84 | /** 85 | * Return URL to item's view page 86 | * 87 | * @param \\Model\ $Item 88 | * @return string 89 | */ 90 | public function getItemUrl($Item) 91 | { 92 | return $this->getUrl('*/*/view', array('id' => $Item->getId())); 93 | } 94 | 95 | /** 96 | * Return URL for resized Item image 97 | * 98 | * @param \\Model\ $item 99 | * @param integer $width 100 | * @return string|false 101 | */ 102 | public function getImageUrl($item, $width) 103 | { 104 | return $this->_dataHelper->resize($item, $width); 105 | } 106 | 107 | /** 108 | * Get a pager 109 | * 110 | * @return string|null 111 | */ 112 | public function getPager() 113 | { 114 | $pager = $this->getChildBlock('_list_pager'); 115 | if ($pager instanceof \Magento\Framework\Object) { 116 | $PerPage = $this->_dataHelper->getPerPage(); 117 | 118 | $pager->setAvailableLimit([$PerPage => $PerPage]); 119 | $pager->setTotalNum($this->getCollection()->getSize()); 120 | $pager->setCollection($this->getCollection()); 121 | $pager->setShowPerPage(TRUE); 122 | $pager->setFrameLength( 123 | $this->_scopeConfig->getValue( 124 | 'design/pagination/pagination_frame', 125 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE 126 | ) 127 | )->setJump( 128 | $this->_scopeConfig->getValue( 129 | 'design/pagination/pagination_frame_skip', 130 | \Magento\Store\Model\ScopeInterface::SCOPE_STORE 131 | ) 132 | ); 133 | 134 | return $pager->toHtml(); 135 | } 136 | 137 | return NULL; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Block/View.php: -------------------------------------------------------------------------------- 1 | \\Block; 4 | 5 | class View extends \Magento\Framework\View\Element\Template 6 | { 7 | 8 | /** 9 | * Core registry 10 | * 11 | * @var \Magento\Framework\Registry 12 | */ 13 | protected $_coreRegistry = null; 14 | 15 | /** @var \\\Helper\Data */ 16 | protected $_dataHelper; 17 | 18 | /** 19 | * @param \Magento\Framework\View\Element\Template\Context $context 20 | * @param \Magento\Framework\Registry $registry 21 | * @param \Magento\Framework\App\Http\Context $httpContext 22 | * @param \Magento\Payment\Helper\Data $paymentHelper 23 | * @param array $data 24 | */ 25 | public function __construct( 26 | \Magento\Framework\View\Element\Template\Context $context, 27 | \Magento\Framework\Registry $registry, 28 | \Magento\Framework\App\Http\Context $httpContext, 29 | \\\Helper\Data $dataHelper, 30 | array $data = [] 31 | ) { 32 | $this->_coreRegistry = $registry; 33 | $this->httpContext = $httpContext; 34 | $this->_dataHelper = $dataHelper; 35 | parent::__construct($context, $data); 36 | } 37 | 38 | /** 39 | * @return void 40 | */ 41 | protected function _prepareLayout() 42 | { 43 | $this->pageConfig->getTitle()->set($this->get()->getTitle()); 44 | } 45 | 46 | /** 47 | * Retrieve current order model instance 48 | * 49 | * @return \\\Model\ 50 | */ 51 | public function get() 52 | { 53 | return $this->_coreRegistry->registry('current_'); 54 | } 55 | 56 | /** 57 | * Return back url for logged in and guest users 58 | * 59 | * @return string 60 | */ 61 | public function getBackUrl() 62 | { 63 | return $this->getUrl('/index/index'); 64 | } 65 | 66 | /** 67 | * Return back title for logged in and guest users 68 | * 69 | * @return string 70 | */ 71 | public function getBackTitle() 72 | { 73 | if ($this->httpContext->getValue(Context::CONTEXT_AUTH)) { 74 | return __('Back to My Orders'); 75 | } 76 | return __('View Another Order'); 77 | } 78 | 79 | /** 80 | * Return URL for resized Item image 81 | * 82 | * @param \\Model\ $item 83 | * @param integer $width 84 | * @return string|false 85 | */ 86 | public function getImageUrl($item, $width) 87 | { 88 | return $this->_dataHelper->resize($item, $width); 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/AbstractController/ModuleLoader.php: -------------------------------------------------------------------------------- 1 | \\Controller\AbstractController; 4 | 5 | use Magento\Framework\App\RequestInterface; 6 | use Magento\Framework\App\ResponseInterface; 7 | use Magento\Framework\Registry; 8 | 9 | class Loader implements LoaderInterface 10 | { 11 | /** 12 | * @var \\\Model\Factory 13 | */ 14 | protected $Factory; 15 | 16 | /** 17 | * @var \Magento\Framework\Registry 18 | */ 19 | protected $registry; 20 | 21 | /** 22 | * @var \Magento\Framework\UrlInterface 23 | */ 24 | protected $url; 25 | 26 | /** 27 | * @param \\\Model\Factory $Factory 28 | * @param OrderViewAuthorizationInterface $orderAuthorization 29 | * @param Registry $registry 30 | * @param \Magento\Framework\UrlInterface $url 31 | */ 32 | public function __construct( 33 | \\\Model\Factory $Factory, 34 | Registry $registry, 35 | \Magento\Framework\UrlInterface $url 36 | ) { 37 | $this->Factory = $Factory; 38 | $this->registry = $registry; 39 | $this->url = $url; 40 | } 41 | 42 | /** 43 | * @param RequestInterface $request 44 | * @param ResponseInterface $response 45 | * @return bool 46 | */ 47 | public function load(RequestInterface $request, ResponseInterface $response) 48 | { 49 | $id = (int)$request->getParam('id'); 50 | if (!$id) { 51 | $request->initForward(); 52 | $request->setActionName('noroute'); 53 | $request->setDispatched(false); 54 | return false; 55 | } 56 | 57 | $ = $this->Factory->create()->load($id); 58 | $this->registry->register('current_', $); 59 | return true; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/AbstractController/ModuleLoaderInterface.php: -------------------------------------------------------------------------------- 1 | \\Controller\AbstractController; 4 | 5 | use Magento\Framework\App\RequestInterface; 6 | use Magento\Framework\App\ResponseInterface; 7 | 8 | interface LoaderInterface 9 | { 10 | /** 11 | * @param RequestInterface $request 12 | * @param ResponseInterface $response 13 | * @return \\\Model\ 14 | */ 15 | public function load(RequestInterface $request, ResponseInterface $response); 16 | } 17 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/AbstractController/View.php: -------------------------------------------------------------------------------- 1 | \\Controller\AbstractController; 4 | 5 | use Magento\Framework\App\Action; 6 | use Magento\Framework\View\Result\PageFactory; 7 | 8 | abstract class View extends Action\Action 9 | { 10 | /** 11 | * @var \\\Controller\AbstractController\LoaderInterface 12 | */ 13 | protected $Loader; 14 | 15 | /** 16 | * @var PageFactory 17 | */ 18 | protected $resultPageFactory; 19 | 20 | /** 21 | * @param Action\Context $context 22 | * @param OrderLoaderInterface $orderLoader 23 | * @param PageFactory $resultPageFactory 24 | */ 25 | public function __construct(Action\Context $context, LoaderInterface $Loader, PageFactory $resultPageFactory) 26 | { 27 | $this->Loader = $Loader; 28 | $this->resultPageFactory = $resultPageFactory; 29 | parent::__construct($context); 30 | } 31 | 32 | /** 33 | * view page 34 | * 35 | * @return void 36 | */ 37 | public function execute() 38 | { 39 | if (!$this->Loader->load($this->_request, $this->_response)) { 40 | return; 41 | } 42 | 43 | /** @var \Magento\Framework\View\Result\Page $resultPage */ 44 | $resultPage = $this->resultPageFactory->create(); 45 | return $resultPage; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Delete.php: -------------------------------------------------------------------------------- 1 | \\Controller\Adminhtml\Index; 4 | 5 | class Delete extends \Magento\Backend\App\Action 6 | { 7 | /** 8 | * {@inheritdoc} 9 | */ 10 | protected function _isAllowed() 11 | { 12 | return $this->_authorization->isAllowed('_::_delete'); 13 | } 14 | 15 | /** 16 | * Delete action 17 | * 18 | * @return void 19 | */ 20 | public function execute() 21 | { 22 | // check if we know what should be deleted 23 | $id = $this->getRequest()->getParam('_id'); 24 | /** @var \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ 25 | $resultRedirect = $this->resultRedirectFactory->create(); 26 | if ($id) { 27 | $title = ""; 28 | try { 29 | // init model and delete 30 | $model = $this->_objectManager->create('\\Model\'); 31 | $model->load($id); 32 | $title = $model->getTitle(); 33 | $model->delete(); 34 | // display success message 35 | $this->messageManager->addSuccess(__('The data has been deleted.')); 36 | // go to grid 37 | return $resultRedirect->setPath('*/*/'); 38 | } catch (\Exception $e) { 39 | // display error message 40 | $this->messageManager->addError($e->getMessage()); 41 | // go back to edit form 42 | return $resultRedirect->setPath('*/*/edit', ['page_id' => $id]); 43 | } 44 | } 45 | // display error message 46 | $this->messageManager->addError(__('We can\'t find a data to delete.')); 47 | // go to grid 48 | return $resultRedirect->setPath('*/*/'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Edit.php: -------------------------------------------------------------------------------- 1 | \\Controller\Adminhtml\Index; 4 | 5 | use Magento\Backend\App\Action; 6 | 7 | class Edit extends \Magento\Backend\App\Action 8 | { 9 | /** 10 | * Core registry 11 | * 12 | * @var \Magento\Framework\Registry 13 | */ 14 | protected $_coreRegistry = null; 15 | 16 | /** 17 | * @var \Magento\Framework\View\Result\PageFactory 18 | */ 19 | protected $resultPageFactory; 20 | 21 | /** 22 | * @param Action\Context $context 23 | * @param \Magento\Framework\View\Result\PageFactory $resultPageFactory 24 | * @param \Magento\Framework\Registry $registry 25 | */ 26 | public function __construct(Action\Context $context, \Magento\Framework\View\Result\PageFactory $resultPageFactory, \Magento\Framework\Registry $registry) 27 | { 28 | $this->resultPageFactory = $resultPageFactory; 29 | $this->_coreRegistry = $registry; 30 | parent::__construct($context); 31 | } 32 | 33 | /** 34 | * {@inheritdoc} 35 | */ 36 | protected function _isAllowed() 37 | { 38 | return $this->_authorization->isAllowed('_::save'); 39 | } 40 | 41 | /** 42 | * Init actions 43 | * 44 | * @return $this 45 | */ 46 | protected function _initAction() 47 | { 48 | // load layout, set active menu and breadcrumbs 49 | /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ 50 | $resultPage = $this->resultPageFactory->create(); 51 | $resultPage->setActiveMenu( 52 | '_::_manage' 53 | )->addBreadcrumb( 54 | __(''), 55 | __('') 56 | )->addBreadcrumb( 57 | __('Manage '), 58 | __('Manage ') 59 | ); 60 | return $resultPage; 61 | } 62 | 63 | /** 64 | * Edit CMS page 65 | * 66 | * @return void 67 | */ 68 | public function execute() 69 | { 70 | // 1. Get ID and create model 71 | $id = $this->getRequest()->getParam('_id'); 72 | $model = $this->_objectManager->create('\\Model\'); 73 | 74 | // 2. Initial checking 75 | if ($id) { 76 | $model->load($id); 77 | if (!$model->getId()) { 78 | $this->messageManager->addError(__('This no longer exists.')); 79 | /** \Magento\Backend\Model\View\Result\Redirect $resultRedirect */ 80 | $resultRedirect = $this->resultRedirectFactory->create(); 81 | return $resultRedirect->setPath('*/*/'); 82 | } 83 | } 84 | 85 | // 3. Set entered data if was error when we do save 86 | $data = $this->_objectManager->get('Magento\Backend\Model\Session')->getFormData(true); 87 | if (!empty($data)) { 88 | $model->setData($data); 89 | } 90 | 91 | // 4. Register model to use later in blocks 92 | $this->_coreRegistry->register('', $model); 93 | 94 | // 5. Build edit form 95 | /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ 96 | $resultPage = $this->_initAction(); 97 | $resultPage->addBreadcrumb( 98 | $id ? __('Edit ') : __('New '), 99 | $id ? __('Edit ') : __('New ') 100 | ); 101 | $resultPage->getConfig()->getTitle()->prepend(__('')); 102 | $resultPage->getConfig()->getTitle() 103 | ->prepend($model->getId() ? $model->getTitle() : __('New ')); 104 | return $resultPage; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Grid.php: -------------------------------------------------------------------------------- 1 | \\Controller\Adminhtml\Index; 4 | 5 | class Grid extends \Magento\Customer\Controller\Adminhtml\Index 6 | { 7 | /** 8 | * Customer grid action 9 | * 10 | * @return void 11 | */ 12 | public function execute() 13 | { 14 | $this->_view->loadLayout(false); 15 | $this->_view->renderLayout(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Index.php: -------------------------------------------------------------------------------- 1 | \\Controller\Adminhtml\Index; 4 | 5 | use Magento\Backend\App\Action\Context; 6 | use Magento\Framework\View\Result\PageFactory; 7 | 8 | class Index extends \Magento\Backend\App\Action 9 | { 10 | /** 11 | * @var PageFactory 12 | */ 13 | protected $resultPageFactory; 14 | 15 | /** 16 | * @param Context $context 17 | * @param PageFactory $resultPageFactory 18 | */ 19 | public function __construct( 20 | Context $context, 21 | PageFactory $resultPageFactory 22 | ) { 23 | parent::__construct($context); 24 | $this->resultPageFactory = $resultPageFactory; 25 | } 26 | 27 | /** 28 | * Check the permission to run it 29 | * 30 | * @return bool 31 | */ 32 | protected function _isAllowed() 33 | { 34 | return $this->_authorization->isAllowed('_::_manage'); 35 | } 36 | 37 | /** 38 | * List action 39 | * 40 | * @return void 41 | */ 42 | public function execute() 43 | { 44 | /** @var \Magento\Backend\Model\View\Result\Page $resultPage */ 45 | $resultPage = $this->resultPageFactory->create(); 46 | $resultPage->setActiveMenu( 47 | '_::_manage' 48 | )->addBreadcrumb( 49 | __(''), 50 | __('') 51 | )->addBreadcrumb( 52 | __('Manage '), 53 | __('Manage ') 54 | ); 55 | $resultPage->getConfig()->getTitle()->prepend(__('')); 56 | return $resultPage; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/Adminhtml/Index/NewAction.php: -------------------------------------------------------------------------------- 1 | \\Controller\Adminhtml\Index; 4 | 5 | class NewAction extends \Magento\Backend\App\Action 6 | { 7 | /** 8 | * @var \Magento\Backend\Model\View\Result\Forward 9 | */ 10 | protected $resultForwardFactory; 11 | 12 | /** 13 | * @param \Magento\Backend\App\Action\Context $context 14 | * @param \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory 15 | */ 16 | public function __construct( 17 | \Magento\Backend\App\Action\Context $context, 18 | \Magento\Backend\Model\View\Result\ForwardFactory $resultForwardFactory 19 | ) { 20 | $this->resultForwardFactory = $resultForwardFactory; 21 | parent::__construct($context); 22 | } 23 | 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function _isAllowed() 28 | { 29 | return $this->_authorization->isAllowed('_::save'); 30 | } 31 | 32 | /** 33 | * Forward to edit 34 | * 35 | * @return void 36 | */ 37 | public function execute() 38 | { 39 | /** @var \Magento\Backend\Model\View\Result\Forward $resultForward */ 40 | $resultForward = $this->resultForwardFactory->create(); 41 | return $resultForward->forward('edit'); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/Adminhtml/Index/PostDataProcessor.php: -------------------------------------------------------------------------------- 1 | \\Controller\Adminhtml\Index; 4 | 5 | class PostDataProcessor 6 | { 7 | /** 8 | * @var \Magento\Framework\Stdlib\DateTime\Filter\Date 9 | */ 10 | protected $dateFilter; 11 | 12 | /** 13 | * @var \Magento\Framework\Message\ManagerInterface 14 | */ 15 | protected $messageManager; 16 | 17 | /** 18 | * @param \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter 19 | * @param \Magento\Framework\Message\ManagerInterface $messageManager 20 | * @param \Magento\Core\Model\Layout\Update\ValidatorFactory $validatorFactory 21 | */ 22 | public function __construct( 23 | \Magento\Framework\Stdlib\DateTime\Filter\Date $dateFilter, 24 | \Magento\Framework\Message\ManagerInterface $messageManager 25 | ) { 26 | $this->dateFilter = $dateFilter; 27 | $this->messageManager = $messageManager; 28 | } 29 | 30 | /** 31 | * Filtering posted data. Converting localized data if needed 32 | * 33 | * @param array $data 34 | * @return array 35 | */ 36 | public function filter($data) 37 | { 38 | $inputFilter = new \Zend_Filter_Input( 39 | ['published_at' => $this->dateFilter], 40 | [], 41 | $data 42 | ); 43 | $data = $inputFilter->getUnescaped(); 44 | return $data; 45 | } 46 | 47 | /** 48 | * Validate post data 49 | * 50 | * @param array $data 51 | * @return bool Return FALSE if someone item is invalid 52 | */ 53 | public function validate($data) 54 | { 55 | $errorNo = true; 56 | return $errorNo; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Save.php: -------------------------------------------------------------------------------- 1 | \\Controller\Adminhtml\Index; 4 | 5 | use Magento\Backend\App\Action; 6 | 7 | class Save extends \Magento\Backend\App\Action 8 | { 9 | /** 10 | * @var PostDataProcessor 11 | */ 12 | protected $dataProcessor; 13 | 14 | /** 15 | * @param Action\Context $context 16 | * @param PostDataProcessor $dataProcessor 17 | */ 18 | public function __construct(Action\Context $context, PostDataProcessor $dataProcessor) 19 | { 20 | $this->dataProcessor = $dataProcessor; 21 | parent::__construct($context); 22 | } 23 | 24 | /** 25 | * {@inheritdoc} 26 | */ 27 | protected function _isAllowed() 28 | { 29 | return $this->_authorization->isAllowed('_::save'); 30 | } 31 | 32 | /** 33 | * Save action 34 | * 35 | * @return void 36 | */ 37 | public function execute() 38 | { 39 | $data = $this->getRequest()->getPostValue(); 40 | if ($data) { 41 | $data = $this->dataProcessor->filter($data); 42 | $model = $this->_objectManager->create('\\Model\'); 43 | 44 | $id = $this->getRequest()->getParam('_id'); 45 | if ($id) { 46 | $model->load($id); 47 | } 48 | 49 | // save image data and remove from data array 50 | if (isset($data['image'])) { 51 | $imageData = $data['image']; 52 | unset($data['image']); 53 | } else { 54 | $imageData = array(); 55 | } 56 | 57 | $model->addData($data); 58 | 59 | if (!$this->dataProcessor->validate($data)) { 60 | $this->_redirect('*/*/edit', ['_id' => $model->getId(), '_current' => true]); 61 | return; 62 | } 63 | 64 | try { 65 | $imageHelper = $this->_objectManager->get('\\Helper\Data'); 66 | 67 | if (isset($imageData['delete']) && $model->getImage()) { 68 | $imageHelper->removeImage($model->getImage()); 69 | $model->setImage(null); 70 | } 71 | 72 | $imageFile = $imageHelper->uploadImage('image'); 73 | if ($imageFile) { 74 | $model->setImage($imageFile); 75 | } 76 | 77 | $model->save(); 78 | $this->messageManager->addSuccess(__('The Data has been saved.')); 79 | $this->_objectManager->get('Magento\Backend\Model\Session')->setFormData(false); 80 | if ($this->getRequest()->getParam('back')) { 81 | $this->_redirect('*/*/edit', ['_id' => $model->getId(), '_current' => true]); 82 | return; 83 | } 84 | $this->_redirect('*/*/'); 85 | return; 86 | } catch (\Magento\Framework\Model\Exception $e) { 87 | $this->messageManager->addError($e->getMessage()); 88 | } catch (\RuntimeException $e) { 89 | $this->messageManager->addError($e->getMessage()); 90 | } catch (\Exception $e) { 91 | $this->messageManager->addException($e, __('Something went wrong while saving the data.')); 92 | } 93 | 94 | $this->_getSession()->setFormData($data); 95 | $this->_redirect('*/*/edit', ['_id' => $this->getRequest()->getParam('_id')]); 96 | return; 97 | } 98 | $this->_redirect('*/*/'); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/Index/Index.php: -------------------------------------------------------------------------------- 1 | \\Controller\Index; 4 | 5 | use Magento\Framework\View\Result\PageFactory; 6 | 7 | class Index extends \Magento\Framework\App\Action\Action 8 | { 9 | /** 10 | * @var PageFactory 11 | */ 12 | protected $resultPageFactory; 13 | 14 | /** 15 | * @param \Magento\Framework\App\Action\Context $context 16 | * @param PageFactory $resultPageFactory 17 | */ 18 | public function __construct( 19 | \Magento\Framework\App\Action\Context $context, 20 | PageFactory $resultPageFactory 21 | ) { 22 | $this->resultPageFactory = $resultPageFactory; 23 | parent::__construct($context); 24 | } 25 | 26 | /** 27 | * Default Index page 28 | * 29 | * @return void 30 | */ 31 | public function execute() 32 | { 33 | $this->_view->loadLayout(); 34 | $this->_view->getLayout()->initMessages(); 35 | $this->_view->getPage()->getConfig()->getTitle()->set(__('Site ')); 36 | $listBlock = $this->_view->getLayout()->getBlock('.list'); 37 | 38 | if ($listBlock) { 39 | $currentPage = abs(intval($this->getRequest()->getParam('p'))); 40 | if ($currentPage < 1) { 41 | $currentPage = 1; 42 | } 43 | 44 | $listBlock->setCurrentPage($currentPage); 45 | } 46 | 47 | /** @var \Magento\Framework\View\Result\Page $resultPage */ 48 | $resultPage = $this->resultPageFactory->create(); 49 | return $resultPage; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/Index/View.php: -------------------------------------------------------------------------------- 1 | \\Controller\Index; 4 | 5 | use \\Controller\Interface; 6 | 7 | class View extends \\\Controller\AbstractController\View implements Interface 8 | { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Controller/ModuleInterface.php: -------------------------------------------------------------------------------- 1 | \\Controller; 4 | 5 | use Magento\Framework\App\ActionInterface; 6 | 7 | interface Interface extends ActionInterface 8 | { 9 | } 10 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Helper/Data.php: -------------------------------------------------------------------------------- 1 | data helper 5 | */ 6 | namespace \\Helper; 7 | 8 | use Magento\Framework\App\Filesystem\DirectoryList; 9 | 10 | class Data extends \Magento\Framework\App\Helper\AbstractHelper 11 | { 12 | /** 13 | * Path to store config where count of posts per page is stored 14 | * 15 | * @var string 16 | */ 17 | const XML_PATH_ITEMS_PER_PAGE = '/view/items_per_page'; 18 | 19 | /** 20 | * Media path to extension images 21 | * 22 | * @var string 23 | */ 24 | const MEDIA_PATH = ''; 25 | 26 | /** 27 | * Maximum size for image in bytes 28 | * Default value is 1M 29 | * 30 | * @var int 31 | */ 32 | const MAX_FILE_SIZE = 1048576; 33 | 34 | /** 35 | * Manimum image height in pixels 36 | * 37 | * @var int 38 | */ 39 | const MIN_HEIGHT = 50; 40 | 41 | /** 42 | * Maximum image height in pixels 43 | * 44 | * @var int 45 | */ 46 | const MAX_HEIGHT = 800; 47 | 48 | /** 49 | * Manimum image width in pixels 50 | * 51 | * @var int 52 | */ 53 | const MIN_WIDTH = 50; 54 | 55 | /** 56 | * Maximum image width in pixels 57 | * 58 | * @var int 59 | */ 60 | const MAX_WIDTH = 1024; 61 | 62 | /** 63 | * Array of image size limitation 64 | * 65 | * @var array 66 | */ 67 | protected $_imageSize = array( 68 | 'minheight' => self::MIN_HEIGHT, 69 | 'minwidth' => self::MIN_WIDTH, 70 | 'maxheight' => self::MAX_HEIGHT, 71 | 'maxwidth' => self::MAX_WIDTH, 72 | ); 73 | 74 | /** 75 | * @var \Magento\Framework\Filesystem\Directory\WriteInterface 76 | */ 77 | protected $mediaDirectory; 78 | 79 | /** 80 | * @var \Magento\Framework\Filesystem 81 | */ 82 | protected $filesystem; 83 | 84 | /** 85 | * @var \Magento\Framework\HTTP\Adapter\FileTransferFactory 86 | */ 87 | protected $httpFactory; 88 | 89 | /** 90 | * File Uploader factory 91 | * 92 | * @var \Magento\Core\Model\File\UploaderFactory 93 | */ 94 | protected $_fileUploaderFactory; 95 | 96 | /** 97 | * File Uploader factory 98 | * 99 | * @var \Magento\Framework\Io\File 100 | */ 101 | protected $_ioFile; 102 | 103 | /** 104 | * Store manager 105 | * 106 | * @var \Magento\Store\Model\StoreManagerInterface 107 | */ 108 | protected $_storeManager; 109 | 110 | /** 111 | * @param \Magento\Framework\App\Helper\Context $context 112 | */ 113 | public function __construct( 114 | \Magento\Framework\App\Helper\Context $context, 115 | \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig, 116 | \Magento\Framework\Filesystem $filesystem, 117 | \Magento\Framework\File\Size $fileSize, 118 | \Magento\Framework\HTTP\Adapter\FileTransferFactory $httpFactory, 119 | \Magento\MediaStorage\Model\File\UploaderFactory $fileUploaderFactory, 120 | \Magento\Framework\Filesystem\Io\File $ioFile, 121 | \Magento\Store\Model\StoreManagerInterface $storeManager, 122 | \Magento\Framework\Image\Factory $imageFactory 123 | ) { 124 | $this->_scopeConfig = $scopeConfig; 125 | $this->filesystem = $filesystem; 126 | $this->mediaDirectory = $filesystem->getDirectoryWrite(DirectoryList::MEDIA); 127 | $this->httpFactory = $httpFactory; 128 | $this->_fileUploaderFactory = $fileUploaderFactory; 129 | $this->_ioFile = $ioFile; 130 | $this->_storeManager = $storeManager; 131 | $this->_imageFactory = $imageFactory; 132 | parent::__construct($context); 133 | } 134 | 135 | /** 136 | * Remove item image by image filename 137 | * 138 | * @param string $imageFile 139 | * @return bool 140 | */ 141 | public function removeImage($imageFile) 142 | { 143 | $io = $this->_ioFile; 144 | $io->open(array('path' => $this->getBaseDir())); 145 | if ($io->fileExists($imageFile)) { 146 | return $io->rm($imageFile); 147 | } 148 | return false; 149 | } 150 | 151 | /** 152 | * Return URL for resized Item Image 153 | * 154 | * @param \\Model\ $item 155 | * @param integer $width 156 | * @param integer $height 157 | * @return bool|string 158 | */ 159 | public function resize(\\\Model\ $item, $width, $height = null) 160 | { 161 | if (!$item->getImage()) { 162 | return false; 163 | } 164 | 165 | if ($width < self::MIN_WIDTH || $width > self::MAX_WIDTH) { 166 | return false; 167 | } 168 | $width = (int)$width; 169 | 170 | if (!is_null($height)) { 171 | if ($height < self::MIN_HEIGHT || $height > self::MAX_HEIGHT) { 172 | return false; 173 | } 174 | $height = (int)$height; 175 | } 176 | 177 | $imageFile = $item->getImage(); 178 | $cacheDir = $this->getBaseDir() . '/' . 'cache' . '/' . $width; 179 | $cacheUrl = $this->getBaseUrl() . '/' . 'cache' . '/' . $width . '/'; 180 | 181 | $io = $this->_ioFile; 182 | $io->checkAndCreateFolder($cacheDir); 183 | $io->open(array('path' => $cacheDir)); 184 | if ($io->fileExists($imageFile)) { 185 | return $cacheUrl . $imageFile; 186 | } 187 | 188 | try { 189 | $image = $this->_imageFactory->create($this->getBaseDir() . '/' . $imageFile); 190 | $image->resize($width, $height); 191 | $image->save($cacheDir . '/' . $imageFile); 192 | return $cacheUrl . $imageFile; 193 | } catch (\Exception $e) { 194 | return false; 195 | } 196 | } 197 | 198 | /** 199 | * Upload image and return uploaded image file name or false 200 | * 201 | * @throws Mage_Core_Exception 202 | * @param string $scope the request key for file 203 | * @return bool|string 204 | */ 205 | public function uploadImage($scope) 206 | { 207 | $adapter = $this->httpFactory->create(); 208 | $adapter->addValidator(new \Zend_Validate_File_ImageSize($this->_imageSize)); 209 | $adapter->addValidator( 210 | new \Zend_Validate_File_FilesSize(['max' => self::MAX_FILE_SIZE]) 211 | ); 212 | 213 | if ($adapter->isUploaded($scope)) { 214 | // validate image 215 | if (!$adapter->isValid($scope)) { 216 | throw new \Magento\Framework\Model\Exception(__('Uploaded image is not valid.')); 217 | } 218 | 219 | $uploader = $this->_fileUploaderFactory->create(['fileId' => $scope]); 220 | $uploader->setAllowedExtensions(['jpg', 'jpeg', 'gif', 'png']); 221 | $uploader->setAllowRenameFiles(true); 222 | $uploader->setFilesDispersion(false); 223 | $uploader->setAllowCreateFolders(true); 224 | 225 | if ($uploader->save($this->getBaseDir())) { 226 | return $uploader->getUploadedFileName(); 227 | } 228 | } 229 | return false; 230 | } 231 | 232 | /** 233 | * Return the base media directory for Item images 234 | * 235 | * @return string 236 | */ 237 | public function getBaseDir() 238 | { 239 | $path = $this->filesystem->getDirectoryRead( 240 | DirectoryList::MEDIA 241 | )->getAbsolutePath(self::MEDIA_PATH); 242 | return $path; 243 | } 244 | 245 | /** 246 | * Return the Base URL for Item images 247 | * 248 | * @return string 249 | */ 250 | public function getBaseUrl() 251 | { 252 | return $this->_storeManager->getStore()->getBaseUrl( 253 | \Magento\Framework\UrlInterface::URL_TYPE_MEDIA 254 | ) . '/' . self::MEDIA_PATH; 255 | } 256 | 257 | /** 258 | * Return the number of items per page 259 | * @return int 260 | */ 261 | public function getPerPage() 262 | { 263 | return abs((int)$this->_scopeConfig->getValue(self::XML_PATH_ITEMS_PER_PAGE, \Magento\Store\Model\ScopeInterface::SCOPE_STORE)); 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Model/Module.php: -------------------------------------------------------------------------------- 1 | \\Model; 4 | 5 | /** 6 | * Model 7 | * 8 | * @method \\\Model\Resource\Page _getResource() 9 | * @method \\\Model\Resource\Page getResource() 10 | */ 11 | class extends \Magento\Framework\Model\AbstractModel 12 | { 13 | /** 14 | * Initialize resource model 15 | * 16 | * @return void 17 | */ 18 | protected function _construct() 19 | { 20 | $this->_init('\\Model\ResourceModel\'); 21 | } 22 | 23 | } 24 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Model/ResourceModel/Module.php: -------------------------------------------------------------------------------- 1 | \\Model\ResourceModel; 4 | 5 | /** 6 | * Resource Model 7 | */ 8 | class extends \Magento\Framework\Model\ResourceModel\Db\AbstractDb 9 | { 10 | /** 11 | * Initialize resource model 12 | * 13 | * @return void 14 | */ 15 | protected function _construct() 16 | { 17 | $this->_init('_', '_id'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Model/ResourceModel/Module/Collection.php: -------------------------------------------------------------------------------- 1 | Resource Collection 5 | */ 6 | namespace \\Model\ResourceModel\; 7 | 8 | class Collection extends \Magento\Framework\Model\ResourceModel\Db\Collection\AbstractCollection 9 | { 10 | /** 11 | * Resource initialization 12 | * 13 | * @return void 14 | */ 15 | protected function _construct() 16 | { 17 | $this->_init('\\Model\', '\\Model\ResourceModel\'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/Setup/InstallSchema.php: -------------------------------------------------------------------------------- 1 | \\Setup; 5 | 6 | use Magento\Framework\Setup\InstallSchemaInterface; 7 | use Magento\Framework\Setup\ModuleContextInterface; 8 | use Magento\Framework\Setup\SchemaSetupInterface; 9 | 10 | /** 11 | * @codeCoverageIgnore 12 | */ 13 | class InstallSchema implements InstallSchemaInterface 14 | { 15 | /** 16 | * {@inheritdoc} 17 | * @SuppressWarnings(PHPMD.ExcessiveMethodLength) 18 | */ 19 | public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) 20 | { 21 | $installer = $setup; 22 | $installer->startSetup(); 23 | 24 | /** 25 | * Creating table _ 26 | */ 27 | $table = $installer->getConnection()->newTable( 28 | $installer->getTable('_') 29 | )->addColumn( 30 | '_id', 31 | \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER, 32 | null, 33 | ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true], 34 | 'Entity Id' 35 | )->addColumn( 36 | 'title', 37 | \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 38 | 255, 39 | ['nullable' => true], 40 | 'News Title' 41 | )->addColumn( 42 | 'author', 43 | \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 44 | 255, 45 | ['nullable' => true,'default' => null], 46 | 'Author' 47 | )->addColumn( 48 | 'content', 49 | \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 50 | '2M', 51 | ['nullable' => true,'default' => null], 52 | 'Content' 53 | )->addColumn( 54 | 'image', 55 | \Magento\Framework\DB\Ddl\Table::TYPE_TEXT, 56 | null, 57 | ['nullable' => true,'default' => null], 58 | ' image media path' 59 | )->addColumn( 60 | 'created_at', 61 | \Magento\Framework\DB\Ddl\Table::TYPE_TIMESTAMP, 62 | null, 63 | ['nullable' => false], 64 | 'Created At' 65 | )->addColumn( 66 | 'published_at', 67 | \Magento\Framework\DB\Ddl\Table::TYPE_DATE, 68 | null, 69 | ['nullable' => true,'default' => null], 70 | 'World publish date' 71 | )->addIndex( 72 | $installer->getIdxName( 73 | '_', 74 | ['published_at'], 75 | \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX 76 | ), 77 | ['published_at'], 78 | ['type' => \Magento\Framework\DB\Adapter\AdapterInterface::INDEX_TYPE_INDEX] 79 | )->setComment( 80 | ' item' 81 | ); 82 | $installer->getConnection()->createTable($table); 83 | $installer->endSetup(); 84 | } 85 | } -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/etc/acl.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/etc/adminhtml/menu.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/etc/adminhtml/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/etc/adminhtml/system.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | separator-top 6 | 7 | general 8 | [Namespace]_[Module]::config_[module] 9 | 10 | 11 | 12 | 13 | Magento\Backend\Model\Config\Source\Yesno 14 | 15 | 16 |
17 |
18 |
19 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/etc/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <[module]> 5 | 6 | 1 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/etc/frontend/di.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/etc/frontend/routes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/etc/module.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/i18n/en_US.csv: -------------------------------------------------------------------------------- 1 | "Site ","Site " -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/registration.php: -------------------------------------------------------------------------------- 1 | _', 6 | __DIR__ 7 | ); 8 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/view/adminhtml/layout/module_index_edit.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | main_section 19 | [module]_edit_tab_main 20 | 21 | 22 | content_section 23 | [module]_edit_tab_content 24 | 25 | 26 | image_section 27 | [module]_edit_tab_image 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/view/adminhtml/layout/module_index_grid.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/view/adminhtml/layout/module_index_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/view/adminhtml/layout/module_index_new.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/view/frontend/layout/default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | [Module] 8 | [module] 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/view/frontend/layout/module_index_index.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/view/frontend/layout/module_index_view.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/view/frontend/templates/module.phtml: -------------------------------------------------------------------------------- 1 | = $this->getCollection(); ?> 2 | ->getSize()): ?> 3 |
4 | as $Item): ?> 5 |
6 |

7 | 8 | escapeHtml($Item->getTitle()) ?> 9 | 10 |

11 | 12 |
13 | formatDate($Item->getPublishedAt()) ?> | 14 | escapeHtml($Item->getAuthor()) ?> 15 |
16 | 17 | getImageUrl($Item, 100)): ?> 18 |

<?php echo $this->escapeHtml($<module>Item->getTitle()); ?>

19 | 20 |
21 | 22 |
23 | getPager() ?> 24 | 25 |
.'); ?>
26 | 27 | -------------------------------------------------------------------------------- /blank/app/code/Namespace/Module/view/frontend/templates/view.phtml: -------------------------------------------------------------------------------- 1 | template for separate item 4 | * 5 | */ 6 | 7 | /** 8 | * @var $this \\Block\View 9 | * @see \\Block\View 10 | */ 11 | ?> 12 | Item = $this->get(); ?> 13 |
14 | formatDate($_Item->getPublishedAt()) ?> | 15 | escapeHtml($_Item->getAuthor()) ?> 16 |
17 | 18 |
19 | getImageUrl($_Item, 400)): ?> 20 |

<?php echo $this->escapeHtml($_<module>Item->getTitle()) ?>

21 | 22 | 23 |
Item->getContent() ?>
24 | 25 |
26 | 27 | 28 | 29 |
30 |
-------------------------------------------------------------------------------- /form.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Module Creator - Magento2 6 | 7 | 8 | 9 | 24 | 25 | 27 |
Namespace Name:


28 |
Module Name:

29 |


30 | '; 31 | ?> 32 | 33 |
34 |
35 | 36 |

Module Creator - Magento 2

37 |
38 | 39 |
40 |
41 | 42 |
43 |
44 |
45 | 46 | 47 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | to files do not match.'); 26 | } 27 | foreach ($to as $file) { 28 | $newPath = substr($file, 0, strrpos($file, '/')); 29 | createFolderPath($newPath, $shop); 30 | } 31 | for ($i = 0; $i < count($to); $i++) { 32 | if (copy($root.$from[$i], $shop.$to[$i]) === false) { 33 | throw new Exception('Could not copy blanko files.'); 34 | } 35 | } 36 | return true; 37 | } 38 | 39 | function createFolderPath($paths, $shop = null) { 40 | global $root; 41 | if (!is_array($paths)) { 42 | $paths = array($paths); 43 | } 44 | if ($shop === null) { 45 | $shop = $root; 46 | } 47 | foreach ($paths as $path) { 48 | $folders = explode('/', $path); 49 | $current = ''; 50 | 51 | foreach ($folders as $folder) { 52 | $fp = $current . DIRECTORY_SEPARATOR . $folder; 53 | if (!is_dir($shop.$fp)) { 54 | if (mkdir($shop.$fp) === false) { 55 | throw new Exception('Could not create new path: '. $shop.$fp); 56 | } 57 | } 58 | $current = $fp; 59 | } 60 | } 61 | return true; 62 | } 63 | 64 | function insertCustomVars($files, $shop = null) { 65 | global $root, $capModule, $lowModule, $isSystem, $typeData, $labelData, $codeData; 66 | 67 | if (!is_array($files)) { 68 | $files = array($files); 69 | } 70 | if ($shop === null) { 71 | $shop = $root . 'new'.DIRECTORY_SEPARATOR; 72 | } 73 | 74 | foreach ($files as $file) { 75 | $handle = fopen ($shop.$file, 'r+'); 76 | $content = ''; 77 | while (!feof($handle)) { 78 | $content .= fgets($handle); 79 | } 80 | fclose($handle); 81 | 82 | $type = strrchr($file, '.'); 83 | switch ($type) { 84 | case '.xml': 85 | $content = replaceXml($content); 86 | break; 87 | case '.php': 88 | case '.csv': 89 | case '.phtml': 90 | $content = replacePhp($content); 91 | break; 92 | default: 93 | throw new Exception('Unknown file type found: '.$type); 94 | } 95 | $handle = fopen ($shop.$file, 'w'); 96 | fputs($handle, $content); 97 | fclose($handle); 98 | 99 | $filename = basename($shop.$file); 100 | } 101 | } 102 | 103 | function replacePhp($content) 104 | { 105 | global $capNamespace, $lowNamespace, $capModule, $lowModule; 106 | 107 | $search = array( 108 | '//', 109 | '//', 110 | '//', 111 | '//', 112 | ); 113 | 114 | $replace = array( 115 | $capNamespace, 116 | $lowNamespace, 117 | $capModule, 118 | $lowModule, 119 | ); 120 | 121 | return preg_replace($search, $replace, $content); 122 | } 123 | 124 | function replaceXml($content) 125 | { 126 | global $capNamespace, $lowNamespace, $capModule, $lowModule, $tabLabel, $sectionLabel, $groupCode, $groupLabel; 127 | 128 | $search = array( 129 | '/\[Namespace\]/', 130 | '/\[namespace\]/', 131 | '/\[Module\]/', 132 | '/\[module\]/', 133 | '/\[tab_label\]/', 134 | '/\[section_label\]/', 135 | '/\[group_code\]/', 136 | '/\[group_label\]/', 137 | ); 138 | 139 | $replace = array( 140 | $capNamespace, 141 | $lowNamespace, 142 | $capModule, 143 | $lowModule, 144 | $tabLabel, 145 | $sectionLabel, 146 | $groupCode, 147 | $groupLabel 148 | ); 149 | 150 | return preg_replace($search, $replace, $content); 151 | } 152 | 153 | $ns = isset($_POST['namespace']) ? $_POST['namespace']:''; 154 | $mod = isset($_POST['module']) ? $_POST['module']:''; 155 | 156 | if(!empty($_POST)) { 157 | $namespace = $_POST['namespace']; 158 | $module = $_POST['module']; 159 | $capNamespace = ucfirst($namespace); 160 | $lowNamespace = strtolower($namespace); 161 | $capModule = ucfirst($module); 162 | $lowModule = strtolower($module); 163 | 164 | $fromFiles = array( 165 | 'blank/app/code/Namespace/Module/registration.php', 166 | 'blank/app/code/Namespace/Module/Block/Module.php', 167 | 'blank/app/code/Namespace/Module/Block/View.php', 168 | 'blank/app/code/Namespace/Module/Block/Adminhtml/Module.php', 169 | 'blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit.php', 170 | 'blank/app/code/Namespace/Module/Block/Adminhtml/Module/Grid.php', 171 | 'blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Form.php', 172 | 'blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Tabs.php', 173 | 'blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Tab/Content.php', 174 | 'blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Tab/Image.php', 175 | 'blank/app/code/Namespace/Module/Block/Adminhtml/Module/Edit/Tab/Main.php', 176 | 'blank/app/code/Namespace/Module/Block/Adminhtml/Form/Element/Image.php', 177 | 'blank/app/code/Namespace/Module/Controller/ModuleInterface.php', 178 | 'blank/app/code/Namespace/Module/Controller/Index/Index.php', 179 | 'blank/app/code/Namespace/Module/Controller/Index/View.php', 180 | 'blank/app/code/Namespace/Module/Controller/AbstractController/ModuleLoader.php', 181 | 'blank/app/code/Namespace/Module/Controller/AbstractController/ModuleLoaderInterface.php', 182 | 'blank/app/code/Namespace/Module/Controller/AbstractController/View.php', 183 | 'blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Delete.php', 184 | 'blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Edit.php', 185 | 'blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Grid.php', 186 | 'blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Index.php', 187 | 'blank/app/code/Namespace/Module/Controller/Adminhtml/Index/NewAction.php', 188 | 'blank/app/code/Namespace/Module/Controller/Adminhtml/Index/PostDataProcessor.php', 189 | 'blank/app/code/Namespace/Module/Controller/Adminhtml/Index/Save.php', 190 | 'blank/app/code/Namespace/Module/etc/acl.xml', 191 | 'blank/app/code/Namespace/Module/etc/config.xml', 192 | 'blank/app/code/Namespace/Module/etc/module.xml', 193 | 'blank/app/code/Namespace/Module/etc/adminhtml/menu.xml', 194 | 'blank/app/code/Namespace/Module/etc/adminhtml/routes.xml', 195 | 'blank/app/code/Namespace/Module/etc/adminhtml/system.xml', 196 | 'blank/app/code/Namespace/Module/etc/frontend/di.xml', 197 | 'blank/app/code/Namespace/Module/etc/frontend/routes.xml', 198 | 'blank/app/code/Namespace/Module/Helper/Data.php', 199 | 'blank/app/code/Namespace/Module/i18n/en_US.csv', 200 | 'blank/app/code/Namespace/Module/Model/Module.php', 201 | 'blank/app/code/Namespace/Module/Model/ResourceModel/Module.php', 202 | 'blank/app/code/Namespace/Module/Model/ResourceModel/Module/Collection.php', 203 | 'blank/app/code/Namespace/Module/Setup/InstallSchema.php', 204 | 'blank/app/code/Namespace/Module/view/adminhtml/layout/module_index_edit.xml', 205 | 'blank/app/code/Namespace/Module/view/adminhtml/layout/module_index_grid.xml', 206 | 'blank/app/code/Namespace/Module/view/adminhtml/layout/module_index_index.xml', 207 | 'blank/app/code/Namespace/Module/view/adminhtml/layout/module_index_new.xml', 208 | 'blank/app/code/Namespace/Module/view/frontend/layout/default.xml', 209 | 'blank/app/code/Namespace/Module/view/frontend/layout/module_index_index.xml', 210 | 'blank/app/code/Namespace/Module/view/frontend/layout/module_index_view.xml', 211 | 'blank/app/code/Namespace/Module/view/frontend/templates/module.phtml', 212 | 'blank/app/code/Namespace/Module/view/frontend/templates/view.phtml', 213 | ); 214 | 215 | $toFiles = array( 216 | 'app/code/'.$capNamespace.'/'.$capModule.'/registration.php', 217 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/'.$capModule.'.php', 218 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/View.php', 219 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/Adminhtml/'.$capModule.'.php', 220 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/Adminhtml/'.$capModule.'/Edit.php', 221 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/Adminhtml/'.$capModule.'/Grid.php', 222 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/Adminhtml/'.$capModule.'/Edit/Form.php', 223 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/Adminhtml/'.$capModule.'/Edit/Tabs.php', 224 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/Adminhtml/'.$capModule.'/Edit/Tab/Content.php', 225 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/Adminhtml/'.$capModule.'/Edit/Tab/Image.php', 226 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/Adminhtml/'.$capModule.'/Edit/Tab/Main.php', 227 | 'app/code/'.$capNamespace.'/'.$capModule.'/Block/Adminhtml/Form/Element/Image.php', 228 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/'.$capModule.'Interface.php', 229 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/Index/Index.php', 230 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/Index/View.php', 231 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/AbstractController/'.$capModule.'Loader.php', 232 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/AbstractController/'.$capModule.'LoaderInterface.php', 233 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/AbstractController/View.php', 234 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/Adminhtml/Index/Delete.php', 235 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/Adminhtml/Index/Edit.php', 236 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/Adminhtml/Index/Grid.php', 237 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/Adminhtml/Index/Index.php', 238 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/Adminhtml/Index/NewAction.php', 239 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/Adminhtml/Index/PostDataProcessor.php', 240 | 'app/code/'.$capNamespace.'/'.$capModule.'/Controller/Adminhtml/Index/Save.php', 241 | 'app/code/'.$capNamespace.'/'.$capModule.'/etc/acl.xml', 242 | 'app/code/'.$capNamespace.'/'.$capModule.'/etc/config.xml', 243 | 'app/code/'.$capNamespace.'/'.$capModule.'/etc/module.xml', 244 | 'app/code/'.$capNamespace.'/'.$capModule.'/etc/adminhtml/menu.xml', 245 | 'app/code/'.$capNamespace.'/'.$capModule.'/etc/adminhtml/routes.xml', 246 | 'app/code/'.$capNamespace.'/'.$capModule.'/etc/adminhtml/system.xml', 247 | 'app/code/'.$capNamespace.'/'.$capModule.'/etc/frontend/di.xml', 248 | 'app/code/'.$capNamespace.'/'.$capModule.'/etc/frontend/routes.xml', 249 | 'app/code/'.$capNamespace.'/'.$capModule.'/Helper/Data.php', 250 | 'app/code/'.$capNamespace.'/'.$capModule.'/i18n/en_US.csv', 251 | 'app/code/'.$capNamespace.'/'.$capModule.'/Model/'.$capModule.'.php', 252 | 'app/code/'.$capNamespace.'/'.$capModule.'/Model/ResourceModel/'.$capModule.'.php', 253 | 'app/code/'.$capNamespace.'/'.$capModule.'/Model/ResourceModel/'.$capModule.'/Collection.php', 254 | 'app/code/'.$capNamespace.'/'.$capModule.'/Setup/InstallSchema.php', 255 | 'app/code/'.$capNamespace.'/'.$capModule.'/view/adminhtml/layout/'.$lowModule.'_index_edit.xml', 256 | 'app/code/'.$capNamespace.'/'.$capModule.'/view/adminhtml/layout/'.$lowModule.'_index_grid.xml', 257 | 'app/code/'.$capNamespace.'/'.$capModule.'/view/adminhtml/layout/'.$lowModule.'_index_index.xml', 258 | 'app/code/'.$capNamespace.'/'.$capModule.'/view/adminhtml/layout/'.$lowModule.'_index_new.xml', 259 | 'app/code/'.$capNamespace.'/'.$capModule.'/view/frontend/layout/default.xml', 260 | 'app/code/'.$capNamespace.'/'.$capModule.'/view/frontend/layout/'.$lowModule.'_index_index.xml', 261 | 'app/code/'.$capNamespace.'/'.$capModule.'/view/frontend/layout/'.$lowModule.'_index_view.xml', 262 | 'app/code/'.$capNamespace.'/'.$capModule.'/view/frontend/templates/'.$lowModule.'.phtml', 263 | 'app/code/'.$capNamespace.'/'.$capModule.'/view/frontend/templates/view.phtml', 264 | ); 265 | 266 | if ($_POST['create']) { 267 | if (!empty($module) && !empty($namespace)) { 268 | copyBlankoFiles($fromFiles, $toFiles, $shop); 269 | insertCustomVars($toFiles, $shop); 270 | 271 | $message = '

New Module successfully created!

272 |
    273 |
  • You\'ll find a new folder called \'new\'. Go to the folder where news files are located.
  • 274 |
  • This folder has the same structure as your Magento 2 Installation.
  • 275 |
  • Create a "code" folder inside your_magento_webroot/app folder.
  • 276 |
  • Put this Module inside "code" folder like app/code/Namespace/Modulename
  • 277 |
  • execute command "php magento setup:upgrade" from your_magento_webroot/bin directory
  • 278 |
  • Implement your module functionality and you\'re done!
  • 279 |
'; 280 | $message .= '
'; 281 | } else { 282 | $message = '

Please fill out the required fields.

'; 283 | } 284 | } 285 | } else { 286 | $message = '
287 | This module creator script will save magento developers time which helps in providing estimation of custom module development.
288 | To create a new module for Magento 2, insert Namespace and a Module name (e.g. Blog, Forum, etc.) below.
289 | This script will create module which has basic folders, required PHP and XML files, frontend listing and view, backend listing and view according to Magento 2 structure and coding standards.
290 | You can later start work by keeping/adding/removing/changing files according to your requirement. 291 |
'; 292 | } 293 | include('form.php'); -------------------------------------------------------------------------------- /js/jquery.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | var parts = document.location.search.slice( 1 ).split( "&" ), 4 | length = parts.length, 5 | scripts = document.getElementsByTagName("script"), 6 | src = scripts[ scripts.length - 1].src, 7 | i = 0, 8 | current, 9 | version = "1.11.1", 10 | file = ""; 11 | 12 | for ( ; i < length; i++ ) { 13 | current = parts[ i ].split( "=" ); 14 | if ( current[ 0 ] === "jquery" ) { 15 | version = current[ 1 ]; 16 | break; 17 | } 18 | } 19 | 20 | if (version != "git") { 21 | file = src.replace(/jquery\.js$/, "jquery-" + version + ".js"); 22 | } 23 | 24 | 25 | document.write( "" ); 26 | 27 | })(); 28 | -------------------------------------------------------------------------------- /js/jquery.validate.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Validation Plugin v1.13.1 3 | * 4 | * http://jqueryvalidation.org/ 5 | * 6 | * Copyright (c) 2014 Jörn Zaefferer 7 | * Released under the MIT license 8 | */ 9 | (function( factory ) { 10 | if ( typeof define === "function" && define.amd ) { 11 | define( ["jquery"], factory ); 12 | } else { 13 | factory( jQuery ); 14 | } 15 | }(function( $ ) { 16 | 17 | $.extend($.fn, { 18 | // http://jqueryvalidation.org/validate/ 19 | validate: function( options ) { 20 | 21 | // if nothing is selected, return nothing; can't chain anyway 22 | if ( !this.length ) { 23 | if ( options && options.debug && window.console ) { 24 | console.warn( "Nothing selected, can't validate, returning nothing." ); 25 | } 26 | return; 27 | } 28 | 29 | // check if a validator for this form was already created 30 | var validator = $.data( this[ 0 ], "validator" ); 31 | if ( validator ) { 32 | return validator; 33 | } 34 | 35 | // Add novalidate tag if HTML5. 36 | this.attr( "novalidate", "novalidate" ); 37 | 38 | validator = new $.validator( options, this[ 0 ] ); 39 | $.data( this[ 0 ], "validator", validator ); 40 | 41 | if ( validator.settings.onsubmit ) { 42 | 43 | this.validateDelegate( ":submit", "click", function( event ) { 44 | if ( validator.settings.submitHandler ) { 45 | validator.submitButton = event.target; 46 | } 47 | // allow suppressing validation by adding a cancel class to the submit button 48 | if ( $( event.target ).hasClass( "cancel" ) ) { 49 | validator.cancelSubmit = true; 50 | } 51 | 52 | // allow suppressing validation by adding the html5 formnovalidate attribute to the submit button 53 | if ( $( event.target ).attr( "formnovalidate" ) !== undefined ) { 54 | validator.cancelSubmit = true; 55 | } 56 | }); 57 | 58 | // validate the form on submit 59 | this.submit( function( event ) { 60 | if ( validator.settings.debug ) { 61 | // prevent form submit to be able to see console output 62 | event.preventDefault(); 63 | } 64 | function handle() { 65 | var hidden, result; 66 | if ( validator.settings.submitHandler ) { 67 | if ( validator.submitButton ) { 68 | // insert a hidden input as a replacement for the missing submit button 69 | hidden = $( "" ) 70 | .attr( "name", validator.submitButton.name ) 71 | .val( $( validator.submitButton ).val() ) 72 | .appendTo( validator.currentForm ); 73 | } 74 | result = validator.settings.submitHandler.call( validator, validator.currentForm, event ); 75 | if ( validator.submitButton ) { 76 | // and clean up afterwards; thanks to no-block-scope, hidden can be referenced 77 | hidden.remove(); 78 | } 79 | if ( result !== undefined ) { 80 | return result; 81 | } 82 | return false; 83 | } 84 | return true; 85 | } 86 | 87 | // prevent submit for invalid forms or custom submit handlers 88 | if ( validator.cancelSubmit ) { 89 | validator.cancelSubmit = false; 90 | return handle(); 91 | } 92 | if ( validator.form() ) { 93 | if ( validator.pendingRequest ) { 94 | validator.formSubmitted = true; 95 | return false; 96 | } 97 | return handle(); 98 | } else { 99 | validator.focusInvalid(); 100 | return false; 101 | } 102 | }); 103 | } 104 | 105 | return validator; 106 | }, 107 | // http://jqueryvalidation.org/valid/ 108 | valid: function() { 109 | var valid, validator; 110 | 111 | if ( $( this[ 0 ] ).is( "form" ) ) { 112 | valid = this.validate().form(); 113 | } else { 114 | valid = true; 115 | validator = $( this[ 0 ].form ).validate(); 116 | this.each( function() { 117 | valid = validator.element( this ) && valid; 118 | }); 119 | } 120 | return valid; 121 | }, 122 | // attributes: space separated list of attributes to retrieve and remove 123 | removeAttrs: function( attributes ) { 124 | var result = {}, 125 | $element = this; 126 | $.each( attributes.split( /\s/ ), function( index, value ) { 127 | result[ value ] = $element.attr( value ); 128 | $element.removeAttr( value ); 129 | }); 130 | return result; 131 | }, 132 | // http://jqueryvalidation.org/rules/ 133 | rules: function( command, argument ) { 134 | var element = this[ 0 ], 135 | settings, staticRules, existingRules, data, param, filtered; 136 | 137 | if ( command ) { 138 | settings = $.data( element.form, "validator" ).settings; 139 | staticRules = settings.rules; 140 | existingRules = $.validator.staticRules( element ); 141 | switch ( command ) { 142 | case "add": 143 | $.extend( existingRules, $.validator.normalizeRule( argument ) ); 144 | // remove messages from rules, but allow them to be set separately 145 | delete existingRules.messages; 146 | staticRules[ element.name ] = existingRules; 147 | if ( argument.messages ) { 148 | settings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages ); 149 | } 150 | break; 151 | case "remove": 152 | if ( !argument ) { 153 | delete staticRules[ element.name ]; 154 | return existingRules; 155 | } 156 | filtered = {}; 157 | $.each( argument.split( /\s/ ), function( index, method ) { 158 | filtered[ method ] = existingRules[ method ]; 159 | delete existingRules[ method ]; 160 | if ( method === "required" ) { 161 | $( element ).removeAttr( "aria-required" ); 162 | } 163 | }); 164 | return filtered; 165 | } 166 | } 167 | 168 | data = $.validator.normalizeRules( 169 | $.extend( 170 | {}, 171 | $.validator.classRules( element ), 172 | $.validator.attributeRules( element ), 173 | $.validator.dataRules( element ), 174 | $.validator.staticRules( element ) 175 | ), element ); 176 | 177 | // make sure required is at front 178 | if ( data.required ) { 179 | param = data.required; 180 | delete data.required; 181 | data = $.extend( { required: param }, data ); 182 | $( element ).attr( "aria-required", "true" ); 183 | } 184 | 185 | // make sure remote is at back 186 | if ( data.remote ) { 187 | param = data.remote; 188 | delete data.remote; 189 | data = $.extend( data, { remote: param }); 190 | } 191 | 192 | return data; 193 | } 194 | }); 195 | 196 | // Custom selectors 197 | $.extend( $.expr[ ":" ], { 198 | // http://jqueryvalidation.org/blank-selector/ 199 | blank: function( a ) { 200 | return !$.trim( "" + $( a ).val() ); 201 | }, 202 | // http://jqueryvalidation.org/filled-selector/ 203 | filled: function( a ) { 204 | return !!$.trim( "" + $( a ).val() ); 205 | }, 206 | // http://jqueryvalidation.org/unchecked-selector/ 207 | unchecked: function( a ) { 208 | return !$( a ).prop( "checked" ); 209 | } 210 | }); 211 | 212 | // constructor for validator 213 | $.validator = function( options, form ) { 214 | this.settings = $.extend( true, {}, $.validator.defaults, options ); 215 | this.currentForm = form; 216 | this.init(); 217 | }; 218 | 219 | // http://jqueryvalidation.org/jQuery.validator.format/ 220 | $.validator.format = function( source, params ) { 221 | if ( arguments.length === 1 ) { 222 | return function() { 223 | var args = $.makeArray( arguments ); 224 | args.unshift( source ); 225 | return $.validator.format.apply( this, args ); 226 | }; 227 | } 228 | if ( arguments.length > 2 && params.constructor !== Array ) { 229 | params = $.makeArray( arguments ).slice( 1 ); 230 | } 231 | if ( params.constructor !== Array ) { 232 | params = [ params ]; 233 | } 234 | $.each( params, function( i, n ) { 235 | source = source.replace( new RegExp( "\\{" + i + "\\}", "g" ), function() { 236 | return n; 237 | }); 238 | }); 239 | return source; 240 | }; 241 | 242 | $.extend( $.validator, { 243 | 244 | defaults: { 245 | messages: {}, 246 | groups: {}, 247 | rules: {}, 248 | errorClass: "error", 249 | validClass: "valid", 250 | errorElement: "label", 251 | focusCleanup: false, 252 | focusInvalid: true, 253 | errorContainer: $( [] ), 254 | errorLabelContainer: $( [] ), 255 | onsubmit: true, 256 | ignore: ":hidden", 257 | ignoreTitle: false, 258 | onfocusin: function( element ) { 259 | this.lastActive = element; 260 | 261 | // Hide error label and remove error class on focus if enabled 262 | if ( this.settings.focusCleanup ) { 263 | if ( this.settings.unhighlight ) { 264 | this.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass ); 265 | } 266 | this.hideThese( this.errorsFor( element ) ); 267 | } 268 | }, 269 | onfocusout: function( element ) { 270 | if ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) { 271 | this.element( element ); 272 | } 273 | }, 274 | onkeyup: function( element, event ) { 275 | if ( event.which === 9 && this.elementValue( element ) === "" ) { 276 | return; 277 | } else if ( element.name in this.submitted || element === this.lastElement ) { 278 | this.element( element ); 279 | } 280 | }, 281 | onclick: function( element ) { 282 | // click on selects, radiobuttons and checkboxes 283 | if ( element.name in this.submitted ) { 284 | this.element( element ); 285 | 286 | // or option elements, check parent select in that case 287 | } else if ( element.parentNode.name in this.submitted ) { 288 | this.element( element.parentNode ); 289 | } 290 | }, 291 | highlight: function( element, errorClass, validClass ) { 292 | if ( element.type === "radio" ) { 293 | this.findByName( element.name ).addClass( errorClass ).removeClass( validClass ); 294 | } else { 295 | $( element ).addClass( errorClass ).removeClass( validClass ); 296 | } 297 | }, 298 | unhighlight: function( element, errorClass, validClass ) { 299 | if ( element.type === "radio" ) { 300 | this.findByName( element.name ).removeClass( errorClass ).addClass( validClass ); 301 | } else { 302 | $( element ).removeClass( errorClass ).addClass( validClass ); 303 | } 304 | } 305 | }, 306 | 307 | // http://jqueryvalidation.org/jQuery.validator.setDefaults/ 308 | setDefaults: function( settings ) { 309 | $.extend( $.validator.defaults, settings ); 310 | }, 311 | 312 | messages: { 313 | required: "This field is required.", 314 | remote: "Please fix this field.", 315 | email: "Please enter a valid email address.", 316 | url: "Please enter a valid URL.", 317 | date: "Please enter a valid date.", 318 | dateISO: "Please enter a valid date ( ISO ).", 319 | number: "Please enter a valid number.", 320 | digits: "Please enter only digits.", 321 | creditcard: "Please enter a valid credit card number.", 322 | equalTo: "Please enter the same value again.", 323 | maxlength: $.validator.format( "Please enter no more than {0} characters." ), 324 | minlength: $.validator.format( "Please enter at least {0} characters." ), 325 | rangelength: $.validator.format( "Please enter a value between {0} and {1} characters long." ), 326 | range: $.validator.format( "Please enter a value between {0} and {1}." ), 327 | max: $.validator.format( "Please enter a value less than or equal to {0}." ), 328 | min: $.validator.format( "Please enter a value greater than or equal to {0}." ) 329 | }, 330 | 331 | autoCreateRanges: false, 332 | 333 | prototype: { 334 | 335 | init: function() { 336 | this.labelContainer = $( this.settings.errorLabelContainer ); 337 | this.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm ); 338 | this.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer ); 339 | this.submitted = {}; 340 | this.valueCache = {}; 341 | this.pendingRequest = 0; 342 | this.pending = {}; 343 | this.invalid = {}; 344 | this.reset(); 345 | 346 | var groups = ( this.groups = {} ), 347 | rules; 348 | $.each( this.settings.groups, function( key, value ) { 349 | if ( typeof value === "string" ) { 350 | value = value.split( /\s/ ); 351 | } 352 | $.each( value, function( index, name ) { 353 | groups[ name ] = key; 354 | }); 355 | }); 356 | rules = this.settings.rules; 357 | $.each( rules, function( key, value ) { 358 | rules[ key ] = $.validator.normalizeRule( value ); 359 | }); 360 | 361 | function delegate( event ) { 362 | var validator = $.data( this[ 0 ].form, "validator" ), 363 | eventType = "on" + event.type.replace( /^validate/, "" ), 364 | settings = validator.settings; 365 | if ( settings[ eventType ] && !this.is( settings.ignore ) ) { 366 | settings[ eventType ].call( validator, this[ 0 ], event ); 367 | } 368 | } 369 | $( this.currentForm ) 370 | .validateDelegate( ":text, [type='password'], [type='file'], select, textarea, " + 371 | "[type='number'], [type='search'] ,[type='tel'], [type='url'], " + 372 | "[type='email'], [type='datetime'], [type='date'], [type='month'], " + 373 | "[type='week'], [type='time'], [type='datetime-local'], " + 374 | "[type='range'], [type='color'], [type='radio'], [type='checkbox']", 375 | "focusin focusout keyup", delegate) 376 | // Support: Chrome, oldIE 377 | // "select" is provided as event.target when clicking a option 378 | .validateDelegate("select, option, [type='radio'], [type='checkbox']", "click", delegate); 379 | 380 | if ( this.settings.invalidHandler ) { 381 | $( this.currentForm ).bind( "invalid-form.validate", this.settings.invalidHandler ); 382 | } 383 | 384 | // Add aria-required to any Static/Data/Class required fields before first validation 385 | // Screen readers require this attribute to be present before the initial submission http://www.w3.org/TR/WCAG-TECHS/ARIA2.html 386 | $( this.currentForm ).find( "[required], [data-rule-required], .required" ).attr( "aria-required", "true" ); 387 | }, 388 | 389 | // http://jqueryvalidation.org/Validator.form/ 390 | form: function() { 391 | this.checkForm(); 392 | $.extend( this.submitted, this.errorMap ); 393 | this.invalid = $.extend({}, this.errorMap ); 394 | if ( !this.valid() ) { 395 | $( this.currentForm ).triggerHandler( "invalid-form", [ this ]); 396 | } 397 | this.showErrors(); 398 | return this.valid(); 399 | }, 400 | 401 | checkForm: function() { 402 | this.prepareForm(); 403 | for ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) { 404 | this.check( elements[ i ] ); 405 | } 406 | return this.valid(); 407 | }, 408 | 409 | // http://jqueryvalidation.org/Validator.element/ 410 | element: function( element ) { 411 | var cleanElement = this.clean( element ), 412 | checkElement = this.validationTargetFor( cleanElement ), 413 | result = true; 414 | 415 | this.lastElement = checkElement; 416 | 417 | if ( checkElement === undefined ) { 418 | delete this.invalid[ cleanElement.name ]; 419 | } else { 420 | this.prepareElement( checkElement ); 421 | this.currentElements = $( checkElement ); 422 | 423 | result = this.check( checkElement ) !== false; 424 | if ( result ) { 425 | delete this.invalid[ checkElement.name ]; 426 | } else { 427 | this.invalid[ checkElement.name ] = true; 428 | } 429 | } 430 | // Add aria-invalid status for screen readers 431 | $( element ).attr( "aria-invalid", !result ); 432 | 433 | if ( !this.numberOfInvalids() ) { 434 | // Hide error containers on last error 435 | this.toHide = this.toHide.add( this.containers ); 436 | } 437 | this.showErrors(); 438 | return result; 439 | }, 440 | 441 | // http://jqueryvalidation.org/Validator.showErrors/ 442 | showErrors: function( errors ) { 443 | if ( errors ) { 444 | // add items to error list and map 445 | $.extend( this.errorMap, errors ); 446 | this.errorList = []; 447 | for ( var name in errors ) { 448 | this.errorList.push({ 449 | message: errors[ name ], 450 | element: this.findByName( name )[ 0 ] 451 | }); 452 | } 453 | // remove items from success list 454 | this.successList = $.grep( this.successList, function( element ) { 455 | return !( element.name in errors ); 456 | }); 457 | } 458 | if ( this.settings.showErrors ) { 459 | this.settings.showErrors.call( this, this.errorMap, this.errorList ); 460 | } else { 461 | this.defaultShowErrors(); 462 | } 463 | }, 464 | 465 | // http://jqueryvalidation.org/Validator.resetForm/ 466 | resetForm: function() { 467 | if ( $.fn.resetForm ) { 468 | $( this.currentForm ).resetForm(); 469 | } 470 | this.submitted = {}; 471 | this.lastElement = null; 472 | this.prepareForm(); 473 | this.hideErrors(); 474 | this.elements() 475 | .removeClass( this.settings.errorClass ) 476 | .removeData( "previousValue" ) 477 | .removeAttr( "aria-invalid" ); 478 | }, 479 | 480 | numberOfInvalids: function() { 481 | return this.objectLength( this.invalid ); 482 | }, 483 | 484 | objectLength: function( obj ) { 485 | /* jshint unused: false */ 486 | var count = 0, 487 | i; 488 | for ( i in obj ) { 489 | count++; 490 | } 491 | return count; 492 | }, 493 | 494 | hideErrors: function() { 495 | this.hideThese( this.toHide ); 496 | }, 497 | 498 | hideThese: function( errors ) { 499 | errors.not( this.containers ).text( "" ); 500 | this.addWrapper( errors ).hide(); 501 | }, 502 | 503 | valid: function() { 504 | return this.size() === 0; 505 | }, 506 | 507 | size: function() { 508 | return this.errorList.length; 509 | }, 510 | 511 | focusInvalid: function() { 512 | if ( this.settings.focusInvalid ) { 513 | try { 514 | $( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || []) 515 | .filter( ":visible" ) 516 | .focus() 517 | // manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find 518 | .trigger( "focusin" ); 519 | } catch ( e ) { 520 | // ignore IE throwing errors when focusing hidden elements 521 | } 522 | } 523 | }, 524 | 525 | findLastActive: function() { 526 | var lastActive = this.lastActive; 527 | return lastActive && $.grep( this.errorList, function( n ) { 528 | return n.element.name === lastActive.name; 529 | }).length === 1 && lastActive; 530 | }, 531 | 532 | elements: function() { 533 | var validator = this, 534 | rulesCache = {}; 535 | 536 | // select all valid inputs inside the form (no submit or reset buttons) 537 | return $( this.currentForm ) 538 | .find( "input, select, textarea" ) 539 | .not( ":submit, :reset, :image, [disabled], [readonly]" ) 540 | .not( this.settings.ignore ) 541 | .filter( function() { 542 | if ( !this.name && validator.settings.debug && window.console ) { 543 | console.error( "%o has no name assigned", this ); 544 | } 545 | 546 | // select only the first element for each name, and only those with rules specified 547 | if ( this.name in rulesCache || !validator.objectLength( $( this ).rules() ) ) { 548 | return false; 549 | } 550 | 551 | rulesCache[ this.name ] = true; 552 | return true; 553 | }); 554 | }, 555 | 556 | clean: function( selector ) { 557 | return $( selector )[ 0 ]; 558 | }, 559 | 560 | errors: function() { 561 | var errorClass = this.settings.errorClass.split( " " ).join( "." ); 562 | return $( this.settings.errorElement + "." + errorClass, this.errorContext ); 563 | }, 564 | 565 | reset: function() { 566 | this.successList = []; 567 | this.errorList = []; 568 | this.errorMap = {}; 569 | this.toShow = $( [] ); 570 | this.toHide = $( [] ); 571 | this.currentElements = $( [] ); 572 | }, 573 | 574 | prepareForm: function() { 575 | this.reset(); 576 | this.toHide = this.errors().add( this.containers ); 577 | }, 578 | 579 | prepareElement: function( element ) { 580 | this.reset(); 581 | this.toHide = this.errorsFor( element ); 582 | }, 583 | 584 | elementValue: function( element ) { 585 | var val, 586 | $element = $( element ), 587 | type = element.type; 588 | 589 | if ( type === "radio" || type === "checkbox" ) { 590 | return $( "input[name='" + element.name + "']:checked" ).val(); 591 | } else if ( type === "number" && typeof element.validity !== "undefined" ) { 592 | return element.validity.badInput ? false : $element.val(); 593 | } 594 | 595 | val = $element.val(); 596 | if ( typeof val === "string" ) { 597 | return val.replace(/\r/g, "" ); 598 | } 599 | return val; 600 | }, 601 | 602 | check: function( element ) { 603 | element = this.validationTargetFor( this.clean( element ) ); 604 | 605 | var rules = $( element ).rules(), 606 | rulesCount = $.map( rules, function( n, i ) { 607 | return i; 608 | }).length, 609 | dependencyMismatch = false, 610 | val = this.elementValue( element ), 611 | result, method, rule; 612 | 613 | for ( method in rules ) { 614 | rule = { method: method, parameters: rules[ method ] }; 615 | try { 616 | 617 | result = $.validator.methods[ method ].call( this, val, element, rule.parameters ); 618 | 619 | // if a method indicates that the field is optional and therefore valid, 620 | // don't mark it as valid when there are no other rules 621 | if ( result === "dependency-mismatch" && rulesCount === 1 ) { 622 | dependencyMismatch = true; 623 | continue; 624 | } 625 | dependencyMismatch = false; 626 | 627 | if ( result === "pending" ) { 628 | this.toHide = this.toHide.not( this.errorsFor( element ) ); 629 | return; 630 | } 631 | 632 | if ( !result ) { 633 | this.formatAndAdd( element, rule ); 634 | return false; 635 | } 636 | } catch ( e ) { 637 | if ( this.settings.debug && window.console ) { 638 | console.log( "Exception occurred when checking element " + element.id + ", check the '" + rule.method + "' method.", e ); 639 | } 640 | throw e; 641 | } 642 | } 643 | if ( dependencyMismatch ) { 644 | return; 645 | } 646 | if ( this.objectLength( rules ) ) { 647 | this.successList.push( element ); 648 | } 649 | return true; 650 | }, 651 | 652 | // return the custom message for the given element and validation method 653 | // specified in the element's HTML5 data attribute 654 | // return the generic message if present and no method specific message is present 655 | customDataMessage: function( element, method ) { 656 | return $( element ).data( "msg" + method.charAt( 0 ).toUpperCase() + 657 | method.substring( 1 ).toLowerCase() ) || $( element ).data( "msg" ); 658 | }, 659 | 660 | // return the custom message for the given element name and validation method 661 | customMessage: function( name, method ) { 662 | var m = this.settings.messages[ name ]; 663 | return m && ( m.constructor === String ? m : m[ method ]); 664 | }, 665 | 666 | // return the first defined argument, allowing empty strings 667 | findDefined: function() { 668 | for ( var i = 0; i < arguments.length; i++) { 669 | if ( arguments[ i ] !== undefined ) { 670 | return arguments[ i ]; 671 | } 672 | } 673 | return undefined; 674 | }, 675 | 676 | defaultMessage: function( element, method ) { 677 | return this.findDefined( 678 | this.customMessage( element.name, method ), 679 | this.customDataMessage( element, method ), 680 | // title is never undefined, so handle empty string as undefined 681 | !this.settings.ignoreTitle && element.title || undefined, 682 | $.validator.messages[ method ], 683 | "Warning: No message defined for " + element.name + "" 684 | ); 685 | }, 686 | 687 | formatAndAdd: function( element, rule ) { 688 | var message = this.defaultMessage( element, rule.method ), 689 | theregex = /\$?\{(\d+)\}/g; 690 | if ( typeof message === "function" ) { 691 | message = message.call( this, rule.parameters, element ); 692 | } else if ( theregex.test( message ) ) { 693 | message = $.validator.format( message.replace( theregex, "{$1}" ), rule.parameters ); 694 | } 695 | this.errorList.push({ 696 | message: message, 697 | element: element, 698 | method: rule.method 699 | }); 700 | 701 | this.errorMap[ element.name ] = message; 702 | this.submitted[ element.name ] = message; 703 | }, 704 | 705 | addWrapper: function( toToggle ) { 706 | if ( this.settings.wrapper ) { 707 | toToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) ); 708 | } 709 | return toToggle; 710 | }, 711 | 712 | defaultShowErrors: function() { 713 | var i, elements, error; 714 | for ( i = 0; this.errorList[ i ]; i++ ) { 715 | error = this.errorList[ i ]; 716 | if ( this.settings.highlight ) { 717 | this.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass ); 718 | } 719 | this.showLabel( error.element, error.message ); 720 | } 721 | if ( this.errorList.length ) { 722 | this.toShow = this.toShow.add( this.containers ); 723 | } 724 | if ( this.settings.success ) { 725 | for ( i = 0; this.successList[ i ]; i++ ) { 726 | this.showLabel( this.successList[ i ] ); 727 | } 728 | } 729 | if ( this.settings.unhighlight ) { 730 | for ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) { 731 | this.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass ); 732 | } 733 | } 734 | this.toHide = this.toHide.not( this.toShow ); 735 | this.hideErrors(); 736 | this.addWrapper( this.toShow ).show(); 737 | }, 738 | 739 | validElements: function() { 740 | return this.currentElements.not( this.invalidElements() ); 741 | }, 742 | 743 | invalidElements: function() { 744 | return $( this.errorList ).map(function() { 745 | return this.element; 746 | }); 747 | }, 748 | 749 | showLabel: function( element, message ) { 750 | var place, group, errorID, 751 | error = this.errorsFor( element ), 752 | elementID = this.idOrName( element ), 753 | describedBy = $( element ).attr( "aria-describedby" ); 754 | if ( error.length ) { 755 | // refresh error/success class 756 | error.removeClass( this.settings.validClass ).addClass( this.settings.errorClass ); 757 | // replace message on existing label 758 | error.html( message ); 759 | } else { 760 | // create error element 761 | error = $( "<" + this.settings.errorElement + ">" ) 762 | .attr( "id", elementID + "-error" ) 763 | .addClass( this.settings.errorClass ) 764 | .html( message || "" ); 765 | 766 | // Maintain reference to the element to be placed into the DOM 767 | place = error; 768 | if ( this.settings.wrapper ) { 769 | // make sure the element is visible, even in IE 770 | // actually showing the wrapped element is handled elsewhere 771 | place = error.hide().show().wrap( "<" + this.settings.wrapper + "/>" ).parent(); 772 | } 773 | if ( this.labelContainer.length ) { 774 | this.labelContainer.append( place ); 775 | } else if ( this.settings.errorPlacement ) { 776 | this.settings.errorPlacement( place, $( element ) ); 777 | } else { 778 | place.insertAfter( element ); 779 | } 780 | 781 | // Link error back to the element 782 | if ( error.is( "label" ) ) { 783 | // If the error is a label, then associate using 'for' 784 | error.attr( "for", elementID ); 785 | } else if ( error.parents( "label[for='" + elementID + "']" ).length === 0 ) { 786 | // If the element is not a child of an associated label, then it's necessary 787 | // to explicitly apply aria-describedby 788 | 789 | errorID = error.attr( "id" ).replace( /(:|\.|\[|\])/g, "\\$1"); 790 | // Respect existing non-error aria-describedby 791 | if ( !describedBy ) { 792 | describedBy = errorID; 793 | } else if ( !describedBy.match( new RegExp( "\\b" + errorID + "\\b" ) ) ) { 794 | // Add to end of list if not already present 795 | describedBy += " " + errorID; 796 | } 797 | $( element ).attr( "aria-describedby", describedBy ); 798 | 799 | // If this element is grouped, then assign to all elements in the same group 800 | group = this.groups[ element.name ]; 801 | if ( group ) { 802 | $.each( this.groups, function( name, testgroup ) { 803 | if ( testgroup === group ) { 804 | $( "[name='" + name + "']", this.currentForm ) 805 | .attr( "aria-describedby", error.attr( "id" ) ); 806 | } 807 | }); 808 | } 809 | } 810 | } 811 | if ( !message && this.settings.success ) { 812 | error.text( "" ); 813 | if ( typeof this.settings.success === "string" ) { 814 | error.addClass( this.settings.success ); 815 | } else { 816 | this.settings.success( error, element ); 817 | } 818 | } 819 | this.toShow = this.toShow.add( error ); 820 | }, 821 | 822 | errorsFor: function( element ) { 823 | var name = this.idOrName( element ), 824 | describer = $( element ).attr( "aria-describedby" ), 825 | selector = "label[for='" + name + "'], label[for='" + name + "'] *"; 826 | 827 | // aria-describedby should directly reference the error element 828 | if ( describer ) { 829 | selector = selector + ", #" + describer.replace( /\s+/g, ", #" ); 830 | } 831 | return this 832 | .errors() 833 | .filter( selector ); 834 | }, 835 | 836 | idOrName: function( element ) { 837 | return this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name ); 838 | }, 839 | 840 | validationTargetFor: function( element ) { 841 | 842 | // If radio/checkbox, validate first element in group instead 843 | if ( this.checkable( element ) ) { 844 | element = this.findByName( element.name ); 845 | } 846 | 847 | // Always apply ignore filter 848 | return $( element ).not( this.settings.ignore )[ 0 ]; 849 | }, 850 | 851 | checkable: function( element ) { 852 | return ( /radio|checkbox/i ).test( element.type ); 853 | }, 854 | 855 | findByName: function( name ) { 856 | return $( this.currentForm ).find( "[name='" + name + "']" ); 857 | }, 858 | 859 | getLength: function( value, element ) { 860 | switch ( element.nodeName.toLowerCase() ) { 861 | case "select": 862 | return $( "option:selected", element ).length; 863 | case "input": 864 | if ( this.checkable( element ) ) { 865 | return this.findByName( element.name ).filter( ":checked" ).length; 866 | } 867 | } 868 | return value.length; 869 | }, 870 | 871 | depend: function( param, element ) { 872 | return this.dependTypes[typeof param] ? this.dependTypes[typeof param]( param, element ) : true; 873 | }, 874 | 875 | dependTypes: { 876 | "boolean": function( param ) { 877 | return param; 878 | }, 879 | "string": function( param, element ) { 880 | return !!$( param, element.form ).length; 881 | }, 882 | "function": function( param, element ) { 883 | return param( element ); 884 | } 885 | }, 886 | 887 | optional: function( element ) { 888 | var val = this.elementValue( element ); 889 | return !$.validator.methods.required.call( this, val, element ) && "dependency-mismatch"; 890 | }, 891 | 892 | startRequest: function( element ) { 893 | if ( !this.pending[ element.name ] ) { 894 | this.pendingRequest++; 895 | this.pending[ element.name ] = true; 896 | } 897 | }, 898 | 899 | stopRequest: function( element, valid ) { 900 | this.pendingRequest--; 901 | // sometimes synchronization fails, make sure pendingRequest is never < 0 902 | if ( this.pendingRequest < 0 ) { 903 | this.pendingRequest = 0; 904 | } 905 | delete this.pending[ element.name ]; 906 | if ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() ) { 907 | $( this.currentForm ).submit(); 908 | this.formSubmitted = false; 909 | } else if (!valid && this.pendingRequest === 0 && this.formSubmitted ) { 910 | $( this.currentForm ).triggerHandler( "invalid-form", [ this ]); 911 | this.formSubmitted = false; 912 | } 913 | }, 914 | 915 | previousValue: function( element ) { 916 | return $.data( element, "previousValue" ) || $.data( element, "previousValue", { 917 | old: null, 918 | valid: true, 919 | message: this.defaultMessage( element, "remote" ) 920 | }); 921 | } 922 | 923 | }, 924 | 925 | classRuleSettings: { 926 | required: { required: true }, 927 | email: { email: true }, 928 | url: { url: true }, 929 | date: { date: true }, 930 | dateISO: { dateISO: true }, 931 | number: { number: true }, 932 | digits: { digits: true }, 933 | creditcard: { creditcard: true } 934 | }, 935 | 936 | addClassRules: function( className, rules ) { 937 | if ( className.constructor === String ) { 938 | this.classRuleSettings[ className ] = rules; 939 | } else { 940 | $.extend( this.classRuleSettings, className ); 941 | } 942 | }, 943 | 944 | classRules: function( element ) { 945 | var rules = {}, 946 | classes = $( element ).attr( "class" ); 947 | 948 | if ( classes ) { 949 | $.each( classes.split( " " ), function() { 950 | if ( this in $.validator.classRuleSettings ) { 951 | $.extend( rules, $.validator.classRuleSettings[ this ]); 952 | } 953 | }); 954 | } 955 | return rules; 956 | }, 957 | 958 | attributeRules: function( element ) { 959 | var rules = {}, 960 | $element = $( element ), 961 | type = element.getAttribute( "type" ), 962 | method, value; 963 | 964 | for ( method in $.validator.methods ) { 965 | 966 | // support for in both html5 and older browsers 967 | if ( method === "required" ) { 968 | value = element.getAttribute( method ); 969 | // Some browsers return an empty string for the required attribute 970 | // and non-HTML5 browsers might have required="" markup 971 | if ( value === "" ) { 972 | value = true; 973 | } 974 | // force non-HTML5 browsers to return bool 975 | value = !!value; 976 | } else { 977 | value = $element.attr( method ); 978 | } 979 | 980 | // convert the value to a number for number inputs, and for text for backwards compability 981 | // allows type="date" and others to be compared as strings 982 | if ( /min|max/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) { 983 | value = Number( value ); 984 | } 985 | 986 | if ( value || value === 0 ) { 987 | rules[ method ] = value; 988 | } else if ( type === method && type !== "range" ) { 989 | // exception: the jquery validate 'range' method 990 | // does not test for the html5 'range' type 991 | rules[ method ] = true; 992 | } 993 | } 994 | 995 | // maxlength may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs 996 | if ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) { 997 | delete rules.maxlength; 998 | } 999 | 1000 | return rules; 1001 | }, 1002 | 1003 | dataRules: function( element ) { 1004 | var method, value, 1005 | rules = {}, $element = $( element ); 1006 | for ( method in $.validator.methods ) { 1007 | value = $element.data( "rule" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() ); 1008 | if ( value !== undefined ) { 1009 | rules[ method ] = value; 1010 | } 1011 | } 1012 | return rules; 1013 | }, 1014 | 1015 | staticRules: function( element ) { 1016 | var rules = {}, 1017 | validator = $.data( element.form, "validator" ); 1018 | 1019 | if ( validator.settings.rules ) { 1020 | rules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {}; 1021 | } 1022 | return rules; 1023 | }, 1024 | 1025 | normalizeRules: function( rules, element ) { 1026 | // handle dependency check 1027 | $.each( rules, function( prop, val ) { 1028 | // ignore rule when param is explicitly false, eg. required:false 1029 | if ( val === false ) { 1030 | delete rules[ prop ]; 1031 | return; 1032 | } 1033 | if ( val.param || val.depends ) { 1034 | var keepRule = true; 1035 | switch ( typeof val.depends ) { 1036 | case "string": 1037 | keepRule = !!$( val.depends, element.form ).length; 1038 | break; 1039 | case "function": 1040 | keepRule = val.depends.call( element, element ); 1041 | break; 1042 | } 1043 | if ( keepRule ) { 1044 | rules[ prop ] = val.param !== undefined ? val.param : true; 1045 | } else { 1046 | delete rules[ prop ]; 1047 | } 1048 | } 1049 | }); 1050 | 1051 | // evaluate parameters 1052 | $.each( rules, function( rule, parameter ) { 1053 | rules[ rule ] = $.isFunction( parameter ) ? parameter( element ) : parameter; 1054 | }); 1055 | 1056 | // clean number parameters 1057 | $.each([ "minlength", "maxlength" ], function() { 1058 | if ( rules[ this ] ) { 1059 | rules[ this ] = Number( rules[ this ] ); 1060 | } 1061 | }); 1062 | $.each([ "rangelength", "range" ], function() { 1063 | var parts; 1064 | if ( rules[ this ] ) { 1065 | if ( $.isArray( rules[ this ] ) ) { 1066 | rules[ this ] = [ Number( rules[ this ][ 0 ]), Number( rules[ this ][ 1 ] ) ]; 1067 | } else if ( typeof rules[ this ] === "string" ) { 1068 | parts = rules[ this ].replace(/[\[\]]/g, "" ).split( /[\s,]+/ ); 1069 | rules[ this ] = [ Number( parts[ 0 ]), Number( parts[ 1 ] ) ]; 1070 | } 1071 | } 1072 | }); 1073 | 1074 | if ( $.validator.autoCreateRanges ) { 1075 | // auto-create ranges 1076 | if ( rules.min != null && rules.max != null ) { 1077 | rules.range = [ rules.min, rules.max ]; 1078 | delete rules.min; 1079 | delete rules.max; 1080 | } 1081 | if ( rules.minlength != null && rules.maxlength != null ) { 1082 | rules.rangelength = [ rules.minlength, rules.maxlength ]; 1083 | delete rules.minlength; 1084 | delete rules.maxlength; 1085 | } 1086 | } 1087 | 1088 | return rules; 1089 | }, 1090 | 1091 | // Converts a simple string to a {string: true} rule, e.g., "required" to {required:true} 1092 | normalizeRule: function( data ) { 1093 | if ( typeof data === "string" ) { 1094 | var transformed = {}; 1095 | $.each( data.split( /\s/ ), function() { 1096 | transformed[ this ] = true; 1097 | }); 1098 | data = transformed; 1099 | } 1100 | return data; 1101 | }, 1102 | 1103 | // http://jqueryvalidation.org/jQuery.validator.addMethod/ 1104 | addMethod: function( name, method, message ) { 1105 | $.validator.methods[ name ] = method; 1106 | $.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ]; 1107 | if ( method.length < 3 ) { 1108 | $.validator.addClassRules( name, $.validator.normalizeRule( name ) ); 1109 | } 1110 | }, 1111 | 1112 | methods: { 1113 | 1114 | // http://jqueryvalidation.org/required-method/ 1115 | required: function( value, element, param ) { 1116 | // check if dependency is met 1117 | if ( !this.depend( param, element ) ) { 1118 | return "dependency-mismatch"; 1119 | } 1120 | if ( element.nodeName.toLowerCase() === "select" ) { 1121 | // could be an array for select-multiple or a string, both are fine this way 1122 | var val = $( element ).val(); 1123 | return val && val.length > 0; 1124 | } 1125 | if ( this.checkable( element ) ) { 1126 | return this.getLength( value, element ) > 0; 1127 | } 1128 | return $.trim( value ).length > 0; 1129 | }, 1130 | 1131 | // http://jqueryvalidation.org/email-method/ 1132 | email: function( value, element ) { 1133 | // From http://www.whatwg.org/specs/web-apps/current-work/multipage/states-of-the-type-attribute.html#e-mail-state-%28type=email%29 1134 | // Retrieved 2014-01-14 1135 | // If you have a problem with this implementation, report a bug against the above spec 1136 | // Or use custom methods to implement your own email validation 1137 | return this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value ); 1138 | }, 1139 | 1140 | // http://jqueryvalidation.org/url-method/ 1141 | url: function( value, element ) { 1142 | // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/ 1143 | return this.optional( element ) || /^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test( value ); 1144 | }, 1145 | 1146 | // http://jqueryvalidation.org/date-method/ 1147 | date: function( value, element ) { 1148 | return this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() ); 1149 | }, 1150 | 1151 | // http://jqueryvalidation.org/dateISO-method/ 1152 | dateISO: function( value, element ) { 1153 | return this.optional( element ) || /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test( value ); 1154 | }, 1155 | 1156 | // http://jqueryvalidation.org/number-method/ 1157 | number: function( value, element ) { 1158 | return this.optional( element ) || /^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test( value ); 1159 | }, 1160 | 1161 | // http://jqueryvalidation.org/digits-method/ 1162 | digits: function( value, element ) { 1163 | return this.optional( element ) || /^\d+$/.test( value ); 1164 | }, 1165 | 1166 | // http://jqueryvalidation.org/creditcard-method/ 1167 | // based on http://en.wikipedia.org/wiki/Luhn/ 1168 | creditcard: function( value, element ) { 1169 | if ( this.optional( element ) ) { 1170 | return "dependency-mismatch"; 1171 | } 1172 | // accept only spaces, digits and dashes 1173 | if ( /[^0-9 \-]+/.test( value ) ) { 1174 | return false; 1175 | } 1176 | var nCheck = 0, 1177 | nDigit = 0, 1178 | bEven = false, 1179 | n, cDigit; 1180 | 1181 | value = value.replace( /\D/g, "" ); 1182 | 1183 | // Basing min and max length on 1184 | // http://developer.ean.com/general_info/Valid_Credit_Card_Types 1185 | if ( value.length < 13 || value.length > 19 ) { 1186 | return false; 1187 | } 1188 | 1189 | for ( n = value.length - 1; n >= 0; n--) { 1190 | cDigit = value.charAt( n ); 1191 | nDigit = parseInt( cDigit, 10 ); 1192 | if ( bEven ) { 1193 | if ( ( nDigit *= 2 ) > 9 ) { 1194 | nDigit -= 9; 1195 | } 1196 | } 1197 | nCheck += nDigit; 1198 | bEven = !bEven; 1199 | } 1200 | 1201 | return ( nCheck % 10 ) === 0; 1202 | }, 1203 | 1204 | // http://jqueryvalidation.org/minlength-method/ 1205 | minlength: function( value, element, param ) { 1206 | var length = $.isArray( value ) ? value.length : this.getLength( value, element ); 1207 | return this.optional( element ) || length >= param; 1208 | }, 1209 | 1210 | // http://jqueryvalidation.org/maxlength-method/ 1211 | maxlength: function( value, element, param ) { 1212 | var length = $.isArray( value ) ? value.length : this.getLength( value, element ); 1213 | return this.optional( element ) || length <= param; 1214 | }, 1215 | 1216 | // http://jqueryvalidation.org/rangelength-method/ 1217 | rangelength: function( value, element, param ) { 1218 | var length = $.isArray( value ) ? value.length : this.getLength( value, element ); 1219 | return this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] ); 1220 | }, 1221 | 1222 | // http://jqueryvalidation.org/min-method/ 1223 | min: function( value, element, param ) { 1224 | return this.optional( element ) || value >= param; 1225 | }, 1226 | 1227 | // http://jqueryvalidation.org/max-method/ 1228 | max: function( value, element, param ) { 1229 | return this.optional( element ) || value <= param; 1230 | }, 1231 | 1232 | // http://jqueryvalidation.org/range-method/ 1233 | range: function( value, element, param ) { 1234 | return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] ); 1235 | }, 1236 | 1237 | // http://jqueryvalidation.org/equalTo-method/ 1238 | equalTo: function( value, element, param ) { 1239 | // bind to the blur event of the target in order to revalidate whenever the target field is updated 1240 | // TODO find a way to bind the event just once, avoiding the unbind-rebind overhead 1241 | var target = $( param ); 1242 | if ( this.settings.onfocusout ) { 1243 | target.unbind( ".validate-equalTo" ).bind( "blur.validate-equalTo", function() { 1244 | $( element ).valid(); 1245 | }); 1246 | } 1247 | return value === target.val(); 1248 | }, 1249 | 1250 | // http://jqueryvalidation.org/remote-method/ 1251 | remote: function( value, element, param ) { 1252 | if ( this.optional( element ) ) { 1253 | return "dependency-mismatch"; 1254 | } 1255 | 1256 | var previous = this.previousValue( element ), 1257 | validator, data; 1258 | 1259 | if (!this.settings.messages[ element.name ] ) { 1260 | this.settings.messages[ element.name ] = {}; 1261 | } 1262 | previous.originalMessage = this.settings.messages[ element.name ].remote; 1263 | this.settings.messages[ element.name ].remote = previous.message; 1264 | 1265 | param = typeof param === "string" && { url: param } || param; 1266 | 1267 | if ( previous.old === value ) { 1268 | return previous.valid; 1269 | } 1270 | 1271 | previous.old = value; 1272 | validator = this; 1273 | this.startRequest( element ); 1274 | data = {}; 1275 | data[ element.name ] = value; 1276 | $.ajax( $.extend( true, { 1277 | url: param, 1278 | mode: "abort", 1279 | port: "validate" + element.name, 1280 | dataType: "json", 1281 | data: data, 1282 | context: validator.currentForm, 1283 | success: function( response ) { 1284 | var valid = response === true || response === "true", 1285 | errors, message, submitted; 1286 | 1287 | validator.settings.messages[ element.name ].remote = previous.originalMessage; 1288 | if ( valid ) { 1289 | submitted = validator.formSubmitted; 1290 | validator.prepareElement( element ); 1291 | validator.formSubmitted = submitted; 1292 | validator.successList.push( element ); 1293 | delete validator.invalid[ element.name ]; 1294 | validator.showErrors(); 1295 | } else { 1296 | errors = {}; 1297 | message = response || validator.defaultMessage( element, "remote" ); 1298 | errors[ element.name ] = previous.message = $.isFunction( message ) ? message( value ) : message; 1299 | validator.invalid[ element.name ] = true; 1300 | validator.showErrors( errors ); 1301 | } 1302 | previous.valid = valid; 1303 | validator.stopRequest( element, valid ); 1304 | } 1305 | }, param ) ); 1306 | return "pending"; 1307 | } 1308 | 1309 | } 1310 | 1311 | }); 1312 | 1313 | $.format = function deprecated() { 1314 | throw "$.format has been deprecated. Please use $.validator.format instead."; 1315 | }; 1316 | 1317 | // ajax mode: abort 1318 | // usage: $.ajax({ mode: "abort"[, port: "uniqueport"]}); 1319 | // if mode:"abort" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort() 1320 | 1321 | var pendingRequests = {}, 1322 | ajax; 1323 | // Use a prefilter if available (1.5+) 1324 | if ( $.ajaxPrefilter ) { 1325 | $.ajaxPrefilter(function( settings, _, xhr ) { 1326 | var port = settings.port; 1327 | if ( settings.mode === "abort" ) { 1328 | if ( pendingRequests[port] ) { 1329 | pendingRequests[port].abort(); 1330 | } 1331 | pendingRequests[port] = xhr; 1332 | } 1333 | }); 1334 | } else { 1335 | // Proxy ajax 1336 | ajax = $.ajax; 1337 | $.ajax = function( settings ) { 1338 | var mode = ( "mode" in settings ? settings : $.ajaxSettings ).mode, 1339 | port = ( "port" in settings ? settings : $.ajaxSettings ).port; 1340 | if ( mode === "abort" ) { 1341 | if ( pendingRequests[port] ) { 1342 | pendingRequests[port].abort(); 1343 | } 1344 | pendingRequests[port] = ajax.apply(this, arguments); 1345 | return pendingRequests[port]; 1346 | } 1347 | return ajax.apply(this, arguments); 1348 | }; 1349 | } 1350 | 1351 | // provides delegate(type: String, delegate: Selector, handler: Callback) plugin for easier event delegation 1352 | // handler is only called when $(event.target).is(delegate), in the scope of the jquery-object for event.target 1353 | 1354 | $.extend($.fn, { 1355 | validateDelegate: function( delegate, type, handler ) { 1356 | return this.bind(type, function( event ) { 1357 | var target = $(event.target); 1358 | if ( target.is(delegate) ) { 1359 | return handler.apply(target, arguments); 1360 | } 1361 | }); 1362 | } 1363 | }); 1364 | 1365 | })); -------------------------------------------------------------------------------- /main.css: -------------------------------------------------------------------------------- 1 | html, body, p, ul, ol, h1, h2, h3, h4, h5, h6 {margin:0; padding:0;} 2 | 3 | 4 | body{ color: #333; 5 | font-family: "Helvetica Neue",Helvetica,Arial,sans-serif; 6 | font-size: 14px; 7 | line-height: 1.42857; } 8 | .wrapper {width:100%; margin:0 auto; } 9 | .container {margin:0 auto; width:1000px;} 10 | .logo {/*float:left;*/ text-align:center;} 11 | 12 | .header {float:left; border-bottom:1px solid #000; padding-bottom:10px; width:1000px;} 13 | .header h1 {margin:50px 0 0 50px; font-size:36px; font-weight:500; font-family:inherit; text-align:center; color:#387cb7} 14 | 15 | .form {float:left; margin:50px 0 0 350px; } 16 | 17 | .first {font-weight:bold; float:left; margin:0 25px 0 0;} 18 | .name {float:left; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; border:1px solid #000; width:200px; height:20px;} 19 | 20 | .second {font-weight:bold; float:left; margin:0 53px 0 0;} 21 | .button {width:500px; float:left;} 22 | .module {float:left; -webkit-border-radius: 3px; -moz-border-radius: 3px; border-radius: 3px; border:1px solid #000; width:200px; height:20px;} 23 | .messagestyle {float:left;margin:30px 0px;} 24 | 25 | .submit {background-color:#428bca; width:100px; height:35px; cursor:pointer; font-size:14px; color:#fff; -moz-border-radius: 3px; border-radius: 4px; margin:20px 0 0 70px; border:1px solid #2b669a; 26 | 27 | background-image: linear-gradient(to bottom, #428bca 0px, #2d6ca2 100%); 28 | background-repeat: repeat-x; 29 | border-color: #2b669a;} 30 | 31 | form.cmxform label.error, label.error {/* remove the next line when you have trouble in IE6 with labels in list */color: red;font-style: italic;font-weight:600} 32 | 33 | form.cmxform label.error {margin-left: 50px;width: 220px;} 34 | 35 | #message ul{padding:5px 30px;} 36 | #newmodule {width: 670px;} --------------------------------------------------------------------------------