artabro/wire/modules/Inputfield/InputfieldPageName/InputfieldPageName.module

356 lines
11 KiB
Text
Raw Normal View History

2024-08-27 11:35:37 +02:00
<?php namespace ProcessWire;
/**
* An Inputfield for handling ProcessWire "name" fields
*
* @property Page|null $parentPage
* @property Page|null $editPage
* @property string $sanitizeMethod Default = 'pageName'
* @property string $languageSupportLabel
* @property bool|int $slashUrls whether a trailing slash should be shown in the URL preview (default=1)
*
* optional checkbox associated with the input, for use with language support
* @property string $checkboxName Leave blank to disable
* @property string $checkboxLabel
* @property string $checkboxValue
* @property string $checkboxSuffix
* @property bool $checkboxChecked
*
*/
class InputfieldPageName extends InputfieldName implements ConfigurableModule {
public static function getModuleInfo() {
return array(
'title' => 'Page Name',
'version' => 106,
'summary' => 'Text input validated as a ProcessWire Page name field',
'permanent' => true,
);
}
public static $defaultReplacements = array(
'æ' => 'ae',
'å' => 'a',
'ä' => 'a',
'ã' => 'a',
'ß' => 'ss',
'ö' => 'o',
'ü' => 'u',
'đ' => 'dj',
'ж' => 'zh',
'х' => 'kh',
'ц' => 'tc',
'ч' => 'ch',
'ш' => 'sh',
'щ' => 'shch',
'ю' => 'iu',
'я' => 'ia',
':' => '-',
',' => '-',
'à' => 'a',
'á' => 'a',
'â' => 'a',
'è' => 'e',
'é' => 'e',
'ë' => 'e',
'ê' => 'e',
'ě' => 'e',
'ì' => 'i',
'í' => 'i',
'ï' => 'i',
'î' => 'i',
'ı' => 'i',
'İ' => 'i',
'ğ' => 'g',
'õ' => 'o',
'ò' => 'o',
'ó' => 'o',
'ô' => 'o',
'ø' => 'o',
'ù' => 'u',
'ú' => 'u',
'û' => 'u',
'ů' => 'u',
'ñ' => 'n',
'ç' => 'c',
'č' => 'c',
'ć' => 'c',
'Ç' => 'c',
'ď' => 'd',
'ĺ' => 'l',
'ľ' => 'l',
'ń' => 'n',
'ň' => 'n',
'ŕ' => 'r',
'ř' => 'r',
'š' => 's',
'ş' => 's',
'Ş' => 's',
'ť' => 't',
'ý' => 'y',
'ž' => 'z',
'а' => 'a',
'б' => 'b',
'в' => 'v',
'г' => 'g',
'д' => 'd',
'е' => 'e',
'ё' => 'e',
'з' => 'z',
'и' => 'i',
'й' => 'i',
'к' => 'k',
'л' => 'l',
'м' => 'm',
'н' => 'n',
'о' => 'o',
'п' => 'p',
'р' => 'r',
'с' => 's',
'т' => 't',
'у' => 'u',
'ф' => 'f',
'ы' => 'y',
'э' => 'e',
'ę' => 'e',
'ą' => 'a',
'ś' => 's',
'ł' => 'l',
'ż' => 'z',
'ź' => 'z',
);
/**
* Whether or not the system has LanguageSupportPageNames module installed
*
* @var bool
*
*/
protected $hasLanguagePageNames = false;
public function init() {
parent::init();
$this->label = $this->_('Name'); // Field label for 'Name'
$this->icon = 'angle-double-right';
$this->set('editPage', null); // page being edited, when available
$this->set('parentPage', null); // parent of page being edited, when available
$this->set('languageSupportLabel', '');
$this->set('slashUrls', 1); // whether a trailing slash should be shown in the URL preview
// disable autocomplete for page name with custom attribute value
$this->attr('autocomplete', 'pw-page-name');
// optional checkbox associated with the input, for use with language support
$this->set('checkboxName', ''); // leave blank to disable
$this->set('checkboxLabel', '');
$this->set('checkboxValue', '');
$this->set('checkboxChecked', false);
$this->set('checkboxSuffix', '');
if($this->wire('config')->pageNameCharset === 'UTF8') {
// no need to indicate input limitations
$this->set('sanitizeMethod', 'pageNameUTF8');
$this->description = '';
} else {
$this->description = $this->_("Any combination of letters (a-z), numbers (0-9), dashes or underscores (no spaces)."); // Field description describing what characters are allowed
$this->set('sanitizeMethod', 'pageName');
}
$this->hasLanguagePageNames = $this->wire()->modules->isInstalled('LanguageSupportPageNames');
$this->removeClass('InputfieldNoBorder', 'wrapClass');
}
public function ___render() {
$config = $this->wire()->config;
$url = '';
$out = '';
$box = '';
$user = $this->wire()->user;
$languages = $this->wire()->languages;
$sanitizer = $this->wire()->sanitizer;
$editable = $this->attr('disabled') ? false : true;
$template = $this->editPage ? $this->editPage->template : null;
$noLang = $template && $template->noLang;
if($this->parentPage) {
if($noLang && $languages && !$user->language->isDefault()) {
// if noLang active for page edited by non-default user, ensure we use default language url
$languages->setDefault();
$url = $this->parentPage->path;
$languages->unsetDefault();
} else {
$url = $this->parentPage->path;
}
if($this->hasLanguagePageNames && $this->parentPage->id == $config->rootPageID) {
if($user->language->isDefault()) {
$parentName = $this->parentPage->name;
if(!trim($url, '/')) $url = ($parentName === Pages::defaultRootName ? "" : $parentName);
}
}
}
if($noLang) $languages = false;
if($editable && $languages && $this->hasLanguagePageNames && !$languages->editable($user->language)) $editable = false;
if($this->languageSupportLabel) {
if($this->checkboxName) {
$checked = $this->checkboxChecked ? " checked='checked'" : '';
$disabled = $editable ? '' : " disabled='disabled'";
$name = $sanitizer->entities($this->checkboxName);
$value = $sanitizer->entities($this->checkboxValue);
$label = $sanitizer->entities($this->checkboxLabel);
$adminTheme = $this->wire()->adminTheme;
$checkboxClass = $adminTheme ? $adminTheme->getClass('input-checkbox') : '';
$box =
"<label class='checkbox detail'>" .
"<input type='checkbox' class='$checkboxClass' name='$name{$this->checkboxSuffix}' value='$value'$checked$disabled /> $label" .
"</label>";
}
$label = $sanitizer->entities($this->languageSupportLabel);
if(!$editable) $label = "<s>$label</s>";
$id = $sanitizer->entities($this->attr('id'));
$out .= "<div class='LanguageSupport'>" .
"<label for='$id' class='LanguageSupportLabel detail'>$label</label>";
}
$value = $this->attr('value');
$link = '';
$slashUrls = (int) $this->slashUrls;
if(strlen($value) && $this->hasLanguagePageNames) {
$link = trim($url, '/') . "/$value" . ($slashUrls ? '/' : '');
$link = $config->urls->root . ltrim($link, '/');
$link = "<a href='$link'>";
}
$p = "\n<p id='{$this->id}_path' data-slashUrls='$slashUrls' class='InputfieldPageNameURL'>";
if($link) $p .= $link;
$p .= rtrim($url, '/') . "/<strong></strong>";
if($link) $p .= "</a>";
$p .= "</p>";
$out .= $p;
$disabled = $this->attr('disabled');
if(!$editable) $this->attr('disabled', 'disabled');
$out .= parent::___render();
if(!$editable && !$disabled) $this->removeAttr('disabled'); // restore previous state
if($this->languageSupportLabel) $out .= $box . "</div>";
// make the replacements part of the JS config
$charset = $config->pageNameCharset;
if($charset == 'UTF8') {
$replacements = array(':' => '-', ',' => '-');
$whitelist = $this->config->pageNameWhitelist;
} else {
$replacements = empty($this->replacements) ? self::$defaultReplacements : $this->replacements;
$whitelist = '';
}
$config->js($this->className(), array(
'replacements' => $replacements,
'charset' => $charset,
'whitelist' => $whitelist
));
return $out;
}
public function ___processInput(WireInputData $input) {
if($this->attr('disabled')) return $this;
$languages = $this->wire()->languages;
if($this->editPage && $this->editPage->template->noLang) $languages = false;
if($languages && $this->hasLanguagePageNames) {
$user = $this->wire()->user;
if(!$languages->editable($user->language)) return $this;
$return = parent::___processInput($input);
$process = $this->wire()->process;
if($process instanceof WirePageEditor && $process->getPage()->id == $this->wire()->config->rootPageID) {
if(!strlen($this->attr('value'))) {
$this->attr('value', Pages::defaultRootName);
}
}
} else {
$return = parent::___processInput($input);
}
return $return;
}
static public function replacementStringToArray($str) {
$r = preg_split('/[\r\n]+/', $str);
$a = array();
foreach($r as $value) {
if(!strpos($value, '=')) continue;
list($k, $v) = explode('=', $value);
$a[trim($k)] = trim($v);
}
return $a;
}
static public function replacementArrayToString(array $a) {
$str = '';
foreach($a as $k => $v) $str .= "$k=$v\n";
return rtrim($str);
}
public function getModuleConfigInputfields(array $data) {
$modules = $this->wire()->modules;
$fields = $this->wire(new InputfieldWrapper());
if($this->wire()->config->pageNameCharset === 'UTF8') {
$this->message($this->_('Character replacements configuration is disabled because $config->pageNameCharset is UTF8.'));
return $fields;
}
$modules->addHookBefore('saveModuleConfigData', null, 'InputfieldPageName_saveModuleConfigData');
$name = 'replacements';
if(empty($data[$name])) $data[$name] = self::$defaultReplacements;
if(is_array($data[$name])) {
// data already in right save format, but need it to be a string for editing
$replacements = self::replacementArrayToString($data[$name]);
} else {
// data is a string so they must have just saved, but we want to save the array version instead
$replacements = $data[$name];
$data[$name] = self::replacementStringToArray($replacements);
}
/** @var InputfieldTextarea $field */
$field = $modules->get("InputfieldTextarea");
$field->attr('name', $name);
$field->attr('value', $replacements);
$field->attr('rows', 15);
$field->label = $this->_('Character replacements');
$field->description = $this->_('Enter the replacements that will occur when a user is entering characters into a page name field. Enter one replacement per line in key=value format. Meaning, on each new line, enter the character(s) you want to replace followed by an equals sign "=" and the ascii character(s) you want to replace with.'); // Character replacements description
$field->notes = $this->_('The replacement value for each must be one or more of: a-z, 0-9, dash, underscore or period.'); // Character replacements notes
$fields->append($field);
return $fields;
}
/**
* Get default replacements setting
*
* @return array
* @since 3.0.170
*
*/
public static function getDefaultReplacements() {
return self::$defaultReplacements;
}
}
function InputfieldPageName_saveModuleConfigData(HookEvent $event) {
$arguments = $event->arguments;
if($arguments[0] != 'InputfieldPageName') return;
$data = $arguments[1];
$name = 'replacements';
if(!is_array($data[$name])) $data[$name] = InputfieldPageName::replacementStringToArray($data[$name]);
$arguments[1] = $data;
$event->arguments = $arguments;
}