356 lines
11 KiB
Text
356 lines
11 KiB
Text
|
<?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;
|
|||
|
}
|