'Page Edit Link', 'summary' => 'Provides a link capability as used by some Fieldtype modules (like rich text editors).', 'version' => 112, 'permanent' => true, 'permission' => 'page-edit', 'icon' => 'link', ); } /** * URL type: Absolute path from root (no relative paths) * */ const urlTypeAbsolute = 0; /** * URL type: Relative path in same branch only * */ const urlTypeRelativeBranch = 1; /** * URL type: Relative path always * */ const urlTypeRelativeAll = 2; /** * @var Page|null * */ protected $page = null; /** * The "choose page" start label * * @var string * */ protected $startLabel = ''; /** * Language ID * * @var int * */ protected $langID = 0; /** * Get default configuration settings * * @return array * */ public static function getDefaultSettings() { return array( 'classOptions' => "", 'relOptions' => "nofollow", 'targetOptions' => "_blank", 'urlType' => self::urlTypeAbsolute, 'extLinkRel' => '', 'extLinkTarget' => '', 'extLinkClass' => '', 'noLinkTextEdit' => 0, ); } /** * Construct * */ public function __construct() { parent::__construct(); foreach(self::getDefaultSettings() as $key => $value) { parent::set($key, $value); } } /** * Setup for execute methods * */ public function setup() { $sanitizer = $this->wire()->sanitizer; $modules = $this->wire()->modules; $pages = $this->wire()->pages; $input = $this->wire()->input; /** @var ProcessPageList $pageList */ $pageList = $modules->get('ProcessPageList'); $pageList->renderReady(); $this->startLabel = $this->_('Choose page'); $id = (int) $input->get('id'); $this->langID = (int) $input->get('lang'); if($id) $this->page = $pages->get($id); if($this->page && $this->page->id && !$this->wire()->user->hasPermission("page-view", $this->page)) { throw new WireException("You don't have access to this page"); } if(!$this->page) $this->page = $pages->newNullPage(); $this->wire()->config->js('ProcessPageEditLink', array( 'selectStartLabel' => $this->startLabel, 'langID' => $this->langID, 'pageID' => $id, 'pageUrl' => $this->page->url, 'pageName' => $this->page->name, 'rootParentUrl' => $this->page->rootParent->url, 'slashUrls' => $this->page->template ? $this->page->template->slashUrls : 1, 'urlType' => $this->urlType, 'extLinkRel' => $sanitizer->names($this->extLinkRel), 'extLinkTarget' => $this->extLinkTarget, 'extLinkClass' => $sanitizer->names($this->extLinkClass), 'noLinkTextEdit' => (int) $this->noLinkTextEdit )); } /** * Set * * @param string $key * @param string|int|array $value * @return self * */ public function set($key, $value) { if($key === 'classOptions' || $key === 'relOptions' || $key === 'targetOptions') { $value = $this->sanitizeOptions($value); } else if($key === 'extLinkRel' || $key === 'extLinkClass') { $value = $this->wire()->sanitizer->htmlClasses($value); } else if($key === 'extLinkTarget') { $value = $this->wire()->sanitizer->htmlClass($value); } return parent::set($key, $value); } /** * Sanitize single option 'value', 'value=label', or 'value="label"' * * @param string $value * @return string * */ protected function sanitizeOption($value) { $sanitizer = $this->wire()->sanitizer; $value = trim($value); $plus = strpos($value, '+') === 0 ? '+' : ''; if($plus) $value = ltrim($value, '+'); if(strpos($value, '=') === false) return $plus . $sanitizer->htmlClasses($value); // value=label or value="label" list($value, $label) = explode('=', $value, 2); $value = trim($value); $label = trim($label); $value = $sanitizer->htmlClasses($value); if(!strlen($value)) return ''; $quote = strpos($label, '"') === 0 ? '"' : ''; $label = str_replace('"', '', $label); $label = $sanitizer->text($label); $value = strlen($label) ? "$plus$value=$quote$label$quote" : "$value"; return $value; } /** * Sanitize multiple newline separated options * * @param string $value * @return string * */ protected function sanitizeOptions($value) { $value = trim($value); if(!strlen($value)) return ''; if(strpos($value, "\n") === false) return $this->sanitizeOption($value); $lines = array(); foreach(explode("\n", $value) as $line) { $line = $this->sanitizeOption($line); if(strlen($line)) $lines[] = $line; } return implode("\n", $lines); } /** * Build the edit link form * * @param string Current href value $currentValue * @param string Current linked text $currentText * @since 3.0.217 * */ protected function ___buildForm($currentValue, $currentText) { $sanitizer = $this->wire()->sanitizer; $modules = $this->wire()->modules; $config = $this->wire()->config; $input = $this->wire()->input; /** @var InputfieldForm $form */ $form = $modules->get("InputfieldForm"); $form->attr('id', 'ProcessPageEditLinkForm'); $modules->get('JqueryWireTabs'); /** @var InputfieldWrapper $fieldset */ $fieldset = $this->wire(new InputfieldWrapper()); $fieldset->attr('title', $this->_('Link')); $fieldset->addClass('WireTab'); $form->add($fieldset); if($this->noLinkTextEdit) { // link text editing disabled } else if($currentText) { /** @var InputfieldText $field */ $field = $modules->get("InputfieldText"); $field->label = $this->_('Link text'); $field->icon = 'pencil-square'; $field->attr('id+name', 'link_text'); $field->val($currentText); $fieldset->add($field); } /** @var InputfieldPageAutocomplete $field */ $field = $modules->get("InputfieldPageAutocomplete"); $field->label = $this->_('Link to URL'); $field->attr('id+name', 'link_page_url'); $field->icon = 'external-link-square'; $field->description = $this->_('Enter a URL, email address, anchor, or enter word(s) to find a page.'); $field->labelFieldName = 'url'; if($modules->isInstalled('PagePaths') && !$this->wire('languages')) { $field->searchFields = 'path title'; } else { $field->searchFields = 'name title'; } if($this->langID) $field->lang_id = $this->langID; $field->maxSelectedItems = 1; $field->useList = false; $field->allowAnyValue = true; $field->disableChars = '/:.#'; $field->useAndWords = true; $field->findPagesSelector = "has_parent!=" . $config->adminRootPageID . ", " . "id!=" . $config->http404PageID; if($currentValue) $field->attr('value', $currentValue); $fieldset->add($field); if(is_array($input->get('anchors'))) { $field->columnWidth = 60; /** @var InputfieldSelect $field */ $field = $modules->get('InputfieldSelect'); $field->columnWidth = 40; $field->attr('id+name', 'link_page_anchor'); $field->label = $this->_('Select Anchor'); $field->description = $this->_('Anchors found in the text you are editing.'); $field->icon = 'flag'; foreach($input->get->array('anchors') as $anchor) { $anchor = '#' . $sanitizer->text($anchor); if(strlen($anchor)) $field->addOption($anchor); if($currentValue && $currentValue == $anchor) $field->attr('value', $currentValue); } $fieldset->add($field); } /** @var InputfieldInteger $field */ $field = $modules->get('InputfieldInteger'); $field->attr('id+name', 'link_page_id'); $field->label = $this->_("Select Page"); $field->set('startLabel', $this->startLabel); $field->collapsed = Inputfield::collapsedYes; $field->icon = 'sitemap'; $fieldset->add($field); if($this->page->numChildren) { /** @var InputfieldInteger $field */ $field = $modules->get('InputfieldInteger'); $field->attr('id+name', 'child_page_id'); $field->label = $this->_("Select Child Page"); $field->description = $this->_('This is the same as "Select Page" above, but may quicker to use if linking to children of the current page.'); $field->set('startLabel', $this->startLabel); $field->collapsed = Inputfield::collapsedYes; $field->icon = 'sitemap'; $fieldset->append($field); } $fieldset->append($this->getFilesField()); /** @var InputfieldWrapper $fieldset */ $fieldset = $this->wire(new InputfieldWrapper()); $fieldset->attr('title', $this->_('Attributes')); $fieldset->attr('id', 'link_attributes'); $fieldset->addClass('WireTab'); $form->append($fieldset); /** @var InputfieldText $field */ $field = $modules->get('InputfieldText'); $field->attr('id+name', 'link_title'); $field->label = $this->_('Title'); $field->description = $this->_('Additional text to describe link.'); if($input->get('title')) { $field->attr('value', $sanitizer->unentities($sanitizer->text($input->get('title')))); } $fieldset->add($field); if($this->targetOptions) { /** @var InputfieldSelect $field */ $field = $modules->get('InputfieldSelect'); $field->attr('id+name', 'link_target'); $field->label = $this->_('Target'); $field->description = $this->_('Where this link will open.'); $this->addSelectOptions($field, 'target', $this->targetOptions); if($this->relOptions) $field->columnWidth = 50; $fieldset->add($field); if($this->extLinkTarget) { $options = $field->getOptions(); if(!isset($options[$this->extLinkTarget])) $field->addOption($this->extLinkTarget); } } if($this->relOptions || $this->extLinkRel) { /** @var InputfieldSelect $field */ $field = $modules->get('InputfieldSelect'); $field->attr('id+name', 'link_rel'); $field->label = $this->_('Rel'); $field->description = $this->_('Relationship of link to document.'); if($this->targetOptions) $field->columnWidth = 50; $this->addSelectOptions($field, 'rel', $this->relOptions); $fieldset->add($field); if($this->extLinkRel) { $options = $field->getOptions(); if(!isset($options[$this->extLinkRel])) $field->addOption($this->extLinkRel); } } $classOptions = $this->getClassOptions(); if($classOptions) { /** @var InputfieldCheckboxes $field */ $field = $modules->get('InputfieldCheckboxes'); $field->attr('id+name', 'link_class'); $field->label = $this->_('Class'); $field->description = $this->_('Additional classes that can affect the look or behavior of the link.'); $field->optionColumns = 1; $this->addSelectOptions($field, 'class', $classOptions); if($this->extLinkClass) { $options = $field->getOptions(); if(!isset($options[$this->extLinkClass])) $field->addOption($this->extLinkClass); } $fieldset->add($field); } if($this->wire()->user->isSuperuser()) $fieldset->notes = sprintf( $this->_('You may customize available attributes shown above in the %s module settings.'), "[ProcessPageEditLink](" . $config->urls->admin . "module/edit?name=ProcessPageEditLink)" ); return $form; } /** * Primary execute * * @return string * */ public function ___execute() { $sanitizer = $this->wire()->sanitizer; $input = $this->wire()->input; $this->setup(); if($input->get('href')) { $currentValue = $sanitizer->url($input->get('href'), array( 'stripQuotes' => false, 'allowIDN' => true, )); } else { $currentValue = ''; } $currentText = $input->get('text'); $currentText = $currentText === null ? '' : $this->wire()->sanitizer->text($currentText); $form = $this->buildForm($currentValue, $currentText); return $form->render() . "