728 lines
22 KiB
Text
728 lines
22 KiB
Text
|
<?php namespace ProcessWire;
|
||
|
|
||
|
/**
|
||
|
* ProcessWire Edit Link Process
|
||
|
*
|
||
|
* Provides the link capability as used by the rich text editor.
|
||
|
*
|
||
|
* ProcessWire 3.x, Copyright 2023 by Ryan Cramer
|
||
|
* https://processwire.com
|
||
|
*
|
||
|
* @property string $relOptions
|
||
|
* @property string $classOptions
|
||
|
* @property string $targetOptions
|
||
|
* @property int $urlType
|
||
|
* @property int $extLinkRel
|
||
|
* @property string $extLinkTarget
|
||
|
* @property string $extLinkClass
|
||
|
* @property int $noLinkTextEdit 3.0.211+
|
||
|
*
|
||
|
* @method InputfieldForm buildForm($currentValue, $currentText)
|
||
|
* @method array getFilesPage(Page $page, $prefix = '') Hookable only in 3.0.222+
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
class ProcessPageEditLink extends Process implements ConfigurableModule {
|
||
|
|
||
|
public static function getModuleInfo() {
|
||
|
return array(
|
||
|
'title' => '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() . "<p class='detail ui-priority-secondary'><code id='link_markup'></code></p>";
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get class options string
|
||
|
*
|
||
|
* This gets class options specified with module and those specified in input.get[class].
|
||
|
*
|
||
|
* @return string Newline separated string of class options
|
||
|
* @since 3.0.212
|
||
|
*
|
||
|
*/
|
||
|
protected function getClassOptions() {
|
||
|
|
||
|
$sanitizer = $this->wire()->sanitizer;
|
||
|
$inputClass = $this->wire()->input->get->text('class');
|
||
|
|
||
|
if(empty($inputClass)) return $this->classOptions;
|
||
|
|
||
|
$inputClass = $sanitizer->htmlClasses($inputClass, true);
|
||
|
|
||
|
if(!count($inputClass)) return $this->classOptions;
|
||
|
|
||
|
sort($inputClass);
|
||
|
|
||
|
$inputClasses = $inputClass;
|
||
|
$inputClass = implode(' ', $inputClass);
|
||
|
$classOptions = array();
|
||
|
|
||
|
if($this->classOptions) {
|
||
|
foreach(explode("\n", $this->classOptions) as $line) {
|
||
|
$value = ltrim(trim($line), '+');
|
||
|
if(strpos($value, '=')) {
|
||
|
list($value, /*$label*/) = explode('=', $value, 2);
|
||
|
}
|
||
|
if(strpos($value, ' ')) {
|
||
|
$value = $sanitizer->htmlClasses($value, true);
|
||
|
sort($value);
|
||
|
$value = implode(' ', $value);
|
||
|
}
|
||
|
$classOptions[$value] = $line;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(isset($classOptions[$inputClass])) {
|
||
|
// class already appears as-is, i.e. "uk-text-muted" or "uk-text-muted uk-text-small", etc.
|
||
|
} else {
|
||
|
// add new classes from input
|
||
|
foreach($inputClasses as $class) {
|
||
|
if(!isset($classOptions[$class])) $classOptions[$class] = $class;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return count($classOptions) ? implode("\n", $classOptions) : '';
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @param InputfieldSelect $field
|
||
|
* @param $attrName
|
||
|
* @param $optionsText
|
||
|
*
|
||
|
*/
|
||
|
protected function addSelectOptions(InputfieldSelect $field, $attrName, $optionsText) {
|
||
|
|
||
|
$input = $this->wire()->input;
|
||
|
$isExisting = $input->get('href') != '';
|
||
|
$existingValueStr = $this->wire()->sanitizer->text($input->get($attrName));
|
||
|
$existingValueArray = strlen($existingValueStr) ? explode(' ', $existingValueStr) : array();
|
||
|
$values = array();
|
||
|
|
||
|
if($field instanceof InputfieldRadios) {
|
||
|
$field->addOption('', $this->_('None'));
|
||
|
}
|
||
|
|
||
|
foreach(explode("\n", $optionsText) as $value) {
|
||
|
$value = trim($value);
|
||
|
$isDefault = strpos($value, '+') !== false;
|
||
|
if($isDefault) $value = trim($value, '+');
|
||
|
$attr = array();
|
||
|
$value = trim($value, '+ ');
|
||
|
$label = '';
|
||
|
if(strpos($value, '=') !== false) {
|
||
|
list($value, $label) = explode('=', $value, 2);
|
||
|
$value = trim($value);
|
||
|
$label = trim($label);
|
||
|
} else {
|
||
|
if($value == '_blank') $label = $this->_('open in new window');
|
||
|
if($value == 'nofollow') $label = $this->_('tell search engines not to follow');
|
||
|
}
|
||
|
if(strpos($label, '"') === 0 || strpos($label, "'") === 0) {
|
||
|
$label = trim($label, "\"'");
|
||
|
} else if($label) {
|
||
|
$label = "$value ($label)";
|
||
|
} else {
|
||
|
$label = $value;
|
||
|
}
|
||
|
|
||
|
if(($isDefault && !$isExisting) || (in_array($value, $existingValueArray) || $existingValueStr === $value)) {
|
||
|
if($field instanceof InputfieldCheckboxes) {
|
||
|
$attr['checked'] = 'checked';
|
||
|
} else {
|
||
|
$attr['selected'] = 'selected';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
$field->addOption($value, $label, $attr);
|
||
|
$values[] = $value;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Return JSON containing files list for ajax use
|
||
|
*
|
||
|
* @return string
|
||
|
* @throws WireException
|
||
|
*
|
||
|
*/
|
||
|
public function ___executeFiles() {
|
||
|
$this->setup();
|
||
|
if(!$this->page->id) throw new WireException("A page id must be specified");
|
||
|
$files = $this->getFiles();
|
||
|
return wireEncodeJSON($files);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get array of info about files attached to given Page
|
||
|
*
|
||
|
* @return array Associative array of "/url/to/file.pdf" => "Field label: basename"
|
||
|
*
|
||
|
*/
|
||
|
protected function getFiles() {
|
||
|
$files = array();
|
||
|
$page = $this->page;
|
||
|
// As the link generator might be called in a repeater, we need to find the containing page
|
||
|
$n = 0;
|
||
|
while(wireInstanceOf($page, 'RepeaterPage') && ++$n < 10) {
|
||
|
/** @var RepeaterPage $page */
|
||
|
$page = $page->getForPage();
|
||
|
}
|
||
|
if($page && $page->id) {
|
||
|
$files = $this->getFilesPage($page);
|
||
|
}
|
||
|
asort($files);
|
||
|
return $files;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get array of info about files attached to given Page, including any repeater items
|
||
|
*
|
||
|
* Hookable in 3.0.222+ only
|
||
|
*
|
||
|
* @param Page $page
|
||
|
* @param string $prefix Optional prefix to prepend to "Field label:" portion of label
|
||
|
* @return array Associative array of "/url/to/file.pdf" => "Field label: basename"
|
||
|
*
|
||
|
*/
|
||
|
protected function ___getFilesPage(Page $page, $prefix = '') {
|
||
|
$files = array();
|
||
|
foreach($page->template->fieldgroup as $field) {
|
||
|
/** @var Fieldtype $type */
|
||
|
$type = $field->type;
|
||
|
if($type instanceof FieldtypeFile) {
|
||
|
$value = $page->get($field->name);
|
||
|
if($value) foreach($page->get($field->name) as $file) {
|
||
|
$files[$file->url] = $prefix . $field->getLabel() . ': ' . $file->basename;
|
||
|
}
|
||
|
} else if(wireInstanceOf($type, 'FieldtypeRepeater')) {
|
||
|
$value = $page->get($field->name);
|
||
|
if($value) {
|
||
|
if($value instanceof Page) $value = array($value);
|
||
|
if(WireArray::iterable($value)) {
|
||
|
foreach($value as $repeaterPage) {
|
||
|
$files = array_merge($this->getFilesPage($repeaterPage, $field->getLabel() . ': '), $files);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return $files;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* @return InputfieldSelect
|
||
|
*
|
||
|
*/
|
||
|
protected function getFilesField() {
|
||
|
/** @var InputfieldSelect $field */
|
||
|
$field = $this->wire()->modules->get("InputfieldSelect");
|
||
|
$field->label = $this->_("Select File");
|
||
|
$field->attr('id+name', 'link_page_file');
|
||
|
$files = $this->getFiles();
|
||
|
$field->addOption('');
|
||
|
$field->addOptions($files);
|
||
|
$field->collapsed = Inputfield::collapsedYes;
|
||
|
if($this->page && $this->page->id) $field->notes = $this->_('Showing files on page:') . ' **' . $this->page->url . '**';
|
||
|
$field->description =
|
||
|
$this->_('Select the file from this page that you want to link to.') . ' ' .
|
||
|
$this->_("To select a file from another page, click 'Select Page' above and choose the page you want to select a file from."); // Instruction on how to select a file from another page
|
||
|
$field->icon = 'file-text-o';
|
||
|
return $field;
|
||
|
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Module configuration
|
||
|
*
|
||
|
* @param InputfieldWrapper $inputfields
|
||
|
*
|
||
|
*/
|
||
|
public function getModuleConfigInputfields(InputfieldWrapper $inputfields) {
|
||
|
|
||
|
$modules = $this->wire()->modules;
|
||
|
|
||
|
/** @var InputfieldFieldset $fieldset */
|
||
|
$fieldset = $modules->get('InputfieldFieldset');
|
||
|
$fieldset->label = $this->_('Attribute options');
|
||
|
$fieldset->description =
|
||
|
$this->_('Enter one of attribute `value`, `value=label`, or `value="label"` per line (see notes for details).') . ' ' .
|
||
|
$this->_('The user will be able to select these as options when adding links.') . ' ' .
|
||
|
$this->_('To make an option selected by default (for new links), precede the value with a plus “+”.');
|
||
|
$fieldset->detail =
|
||
|
$this->_('To include labels, specify `value=label` to show **“value (label)”** for each selectable option.') . ' ' .
|
||
|
$this->_('Or specify `value="label"` (label in quotes) to show just **“label”** (hiding the value) for each selectable option.');
|
||
|
$fieldset->icon = 'sliders';
|
||
|
|
||
|
/** @var InputfieldTextarea $f */
|
||
|
$f = $modules->get('InputfieldTextarea');
|
||
|
$f->attr('name', 'classOptions');
|
||
|
$f->label = 'class';
|
||
|
$f->attr('value', $this->classOptions);
|
||
|
$f->columnWidth = 34;
|
||
|
$fieldset->add($f);
|
||
|
|
||
|
/** @var InputfieldTextarea $f */
|
||
|
$f = $modules->get('InputfieldTextarea');
|
||
|
$f->attr('name', 'relOptions');
|
||
|
$f->label = 'rel';
|
||
|
$f->attr('value', $this->relOptions);
|
||
|
$f->columnWidth = 33;
|
||
|
$fieldset->add($f);
|
||
|
|
||
|
/** @var InputfieldTextarea $f */
|
||
|
$f = $modules->get('InputfieldTextarea');
|
||
|
$f->attr('name', 'targetOptions');
|
||
|
$f->label = 'target';
|
||
|
$f->attr('value', $this->targetOptions);
|
||
|
$f->columnWidth = 33;
|
||
|
$fieldset->add($f);
|
||
|
$inputfields->add($fieldset);
|
||
|
|
||
|
/** @var InputfieldFieldset $fieldset */
|
||
|
$fieldset = $modules->get('InputfieldFieldset');
|
||
|
$fieldset->label = $this->_('External link attributes');
|
||
|
$fieldset->description = $this->_('Specify the default selected attributes that will be automatically populated when an external link is detected.');
|
||
|
$fieldset->description .= ' ' . $this->_('If used, the value must be one you have predefined above.');
|
||
|
$fieldset->icon = 'external-link';
|
||
|
$fieldset->collapsed = Inputfield::collapsedBlank;
|
||
|
|
||
|
/** @var InputfieldText $f */
|
||
|
$f = $modules->get('InputfieldText');
|
||
|
$f->attr('name', 'extLinkClass');
|
||
|
$f->label = 'class';
|
||
|
$f->attr('value', $this->extLinkClass);
|
||
|
$f->required = false;
|
||
|
$f->columnWidth = 34;
|
||
|
$fieldset->add($f);
|
||
|
|
||
|
/** @var InputfieldText $f */
|
||
|
$f = $modules->get('InputfieldText');
|
||
|
$f->attr('name', 'extLinkRel');
|
||
|
$f->notes = $this->_('Example: Specifying **nofollow** would make external links default to be not followed by search engines.');
|
||
|
$f->label = 'rel';
|
||
|
$f->required = false;
|
||
|
$f->attr('value', $this->extLinkRel);
|
||
|
$f->columnWidth = 33;
|
||
|
$fieldset->add($f);
|
||
|
|
||
|
/** @var InputfieldName $f */
|
||
|
$f = $modules->get('InputfieldName');
|
||
|
$f->attr('name', 'extLinkTarget');
|
||
|
$f->label = 'target';
|
||
|
$f->notes = $this->_('Example: Specifying **_blank** would make external links default to open in a new window.');
|
||
|
$f->attr('value', $this->extLinkTarget);
|
||
|
$f->required = false;
|
||
|
$f->columnWidth = 33;
|
||
|
$fieldset->add($f);
|
||
|
$inputfields->add($fieldset);
|
||
|
|
||
|
/** @var InputfieldRadios $f */
|
||
|
$f = $modules->get('InputfieldRadios');
|
||
|
$f->attr('name', 'urlType');
|
||
|
$f->label = $this->_('URL type for page links');
|
||
|
$f->addOption(self::urlTypeAbsolute, $this->_('Full/absolute path from root (default)'));
|
||
|
$f->addOption(self::urlTypeRelativeBranch, $this->_('Relative URLs in the same branches only') . '*');
|
||
|
$f->addOption(self::urlTypeRelativeAll, $this->_('Relative URLs always') . '*');
|
||
|
$f->attr('value', $this->urlType ? $this->urlType : self::urlTypeAbsolute);
|
||
|
$f->notes = $this->_('*Currently experimental');
|
||
|
$f->collapsed = Inputfield::collapsedYes;
|
||
|
$inputfields->add($f);
|
||
|
|
||
|
/** @var InputfieldCheckbox $f */
|
||
|
$f = $modules->get('InputfieldCheckbox');
|
||
|
$f->attr('name', 'noLinkTextEdit');
|
||
|
$f->label = $this->_('Disable link text edit feature?');
|
||
|
$f->description = $this->_('Disables the “Edit Link Text” feature, enabling you to support links that can contain existing markup.');
|
||
|
if($this->noLinkTextEdit) {
|
||
|
$f->attr('checked', 'checked');
|
||
|
} else {
|
||
|
$f->collapsed = Inputfield::collapsedYes;
|
||
|
}
|
||
|
$inputfields->add($f);
|
||
|
}
|
||
|
}
|