mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
Merge pull request #38 from chillu/multibyte-urlsegment
Multibyte urlsegment
This commit is contained in:
commit
23f1c8b669
42
code/forms/SiteTreeURLSegmentField.php
Normal file
42
code/forms/SiteTreeURLSegmentField.php
Normal file
@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* @package cms
|
||||
* @subpackage forms
|
||||
*/
|
||||
|
||||
/**
|
||||
* Used to edit the SiteTree->URLSegment property, and suggest input based on the serverside rules
|
||||
* defined through {@link SiteTree->generateURLSegment()} and {@link URLSegmentFilter}.
|
||||
*
|
||||
* Note: The actual conversion for saving the value takes place in the model layer.
|
||||
*/
|
||||
class SiteTreeURLSegmentField extends TextField {
|
||||
|
||||
static $allowed_actions = array(
|
||||
'suggest'
|
||||
);
|
||||
|
||||
function suggest($request) {
|
||||
if(!$request->getVar('value')) return $this->httpError(405);
|
||||
$page = $this->getPage();
|
||||
|
||||
// Same logic as SiteTree->onBeforeWrite
|
||||
$page->URLSegment = $page->generateURLSegment($request->getVar('value'));
|
||||
$count = 2;
|
||||
while(!$page->validURLSegment()) {
|
||||
$page->URLSegment = preg_replace('/-[0-9]+$/', null, $page->URLSegment) . '-' . $count;
|
||||
$count++;
|
||||
}
|
||||
|
||||
Controller::curr()->getResponse()->addHeader('Content-Type', 'application/json');
|
||||
return Convert::raw2json(array('value' => $page->URLSegment));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return SiteTree
|
||||
*/
|
||||
function getPage() {
|
||||
$idField = $this->getForm()->dataFieldByName('ID');
|
||||
return ($idField && $idField->Value()) ? DataObject::get_by_id('SiteTree', $idField->Value()) : singleton('SiteTree');
|
||||
}
|
||||
}
|
@ -1385,15 +1385,10 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
|
||||
if((!$this->URLSegment || $this->URLSegment == 'new-page') && $this->Title) {
|
||||
$this->URLSegment = $this->generateURLSegment($this->Title);
|
||||
} else if($this->isChanged('URLSegment')) {
|
||||
// Make sure the URLSegment is valid for use in a URL
|
||||
$segment = ereg_replace('[^A-Za-z0-9]+','-',$this->URLSegment);
|
||||
$segment = ereg_replace('-+','-',$segment);
|
||||
|
||||
$filter = Object::create('URLSegmentFilter');
|
||||
$this->URLSegment = $filter->filter($this->URLSegment);
|
||||
// If after sanitising there is no URLSegment, give it a reasonable default
|
||||
if(!$segment) {
|
||||
$segment = "page-$this->ID";
|
||||
}
|
||||
$this->URLSegment = $segment;
|
||||
if(!$this->URLSegment) $this->URLSegment = "page-$this->ID";
|
||||
}
|
||||
|
||||
// Ensure that this object has a non-conflicting URLSegment value.
|
||||
@ -1583,11 +1578,11 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
|
||||
* @return string Generated url segment
|
||||
*/
|
||||
function generateURLSegment($title){
|
||||
$t = Convert::raw2url($title);
|
||||
$filter = Object::create('URLSegmentFilter');
|
||||
$t = $filter->filter($title);
|
||||
|
||||
if(!$t || $t == '-' || $t == '-1') {
|
||||
$t = "page-$this->ID";
|
||||
}
|
||||
// Fallback to generic page name if path is empty (= no valid, convertable characters)
|
||||
if(!$t || $t == '-' || $t == '-1') $t = "page-$this->ID";
|
||||
|
||||
// Hook for extensions
|
||||
$this->extend('updateURLSegment', $t, $title);
|
||||
@ -1833,7 +1828,7 @@ class SiteTree extends DataObject implements PermissionProvider,i18nEntityProvid
|
||||
new HtmlEditorField("Content", _t('SiteTree.HTMLEDITORTITLE', "Content", PR_MEDIUM, 'HTML editor title'))
|
||||
),
|
||||
$tabMeta = new Tab('Metadata',
|
||||
new TextField("URLSegment", $this->fieldLabel('URLSegment') . $urlHelper),
|
||||
new SiteTreeURLSegmentField("URLSegment", $this->fieldLabel('URLSegment') . $urlHelper),
|
||||
new LiteralField('LinkChangeNote', self::nested_urls() && count($this->Children()) ?
|
||||
'<p>' . $this->fieldLabel('LinkChangeNote'). '</p>' : null
|
||||
),
|
||||
|
@ -21,23 +21,6 @@
|
||||
* Input validation on the URLSegment field
|
||||
*/
|
||||
$('.cms-edit-form input[name=URLSegment]').entwine({
|
||||
/**
|
||||
* Property: FilterRegex
|
||||
* Regex
|
||||
*/
|
||||
FilterRegex: /[^A-Za-z0-9-]+/,
|
||||
|
||||
/**
|
||||
* Property: ValidationMessage
|
||||
* String
|
||||
*/
|
||||
ValidationMessage: ss.i18n._t('CMSMAIN.URLSEGMENTVALIDATION'),
|
||||
|
||||
/**
|
||||
* Property: MaxLength
|
||||
* Int
|
||||
*/
|
||||
MaxLength: 50,
|
||||
|
||||
/**
|
||||
* Constructor: onmatch
|
||||
@ -47,42 +30,41 @@
|
||||
|
||||
// intercept change event, do our own writing
|
||||
this.bind('change', function(e) {
|
||||
if(!self.validate()) {
|
||||
jQuery.noticeAdd(self.getValidationMessage());
|
||||
}
|
||||
self.val(self.suggestValue(e.target.value));
|
||||
return false;
|
||||
if(!self.val()) return;
|
||||
|
||||
self.attr('disabled', 'disabled').parents('.field:first').addClass('loading');
|
||||
var oldVal = self.val();
|
||||
self.suggest(oldVal, function(data) {
|
||||
self.removeAttr('disabled').parents('.field:first').removeClass('loading');
|
||||
var newVal = decodeURIComponent(data.value);
|
||||
self.val(newVal);
|
||||
|
||||
if(oldVal != newVal) {
|
||||
jQuery.noticeAdd(ss.i18n._t('The URL has been changed'));
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
this._super();
|
||||
},
|
||||
|
||||
/**
|
||||
* Function: suggestValue
|
||||
* Function: suggest
|
||||
*
|
||||
* Return a value matching the criteria.
|
||||
*
|
||||
* Parameters:
|
||||
* (String) val
|
||||
*
|
||||
* Returns:
|
||||
* String
|
||||
* (Function) callback
|
||||
*/
|
||||
suggestValue: function(val) {
|
||||
// TODO Do we want to enforce lowercasing in URLs?
|
||||
return val.substr(0, this.getMaxLength()).replace(this.getFilterRegex(), '').toLowerCase();
|
||||
},
|
||||
|
||||
/**
|
||||
* Function: validate
|
||||
*
|
||||
* Returns:
|
||||
* Boolean
|
||||
*/
|
||||
validate: function() {
|
||||
return (
|
||||
this.val().length > this.getMaxLength()
|
||||
|| this.val().match(this.getFilterRegex())
|
||||
suggest: function(val, callback) {
|
||||
$.get(
|
||||
this.parents('form:first').attr('action') +
|
||||
'/field/URLSegment/suggest/?value=' + encodeURIComponent(this.val()),
|
||||
function(data) {
|
||||
callback.apply(this, arguments);
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
@ -114,24 +96,21 @@
|
||||
*/
|
||||
updateURLSegment: function(field) {
|
||||
if(!field || !field.length) return;
|
||||
|
||||
// TODO The new URL value is determined asynchronously,
|
||||
// which means we need to come up with an alternative system
|
||||
// to ask user permission to change it.
|
||||
|
||||
// TODO language/logic coupling
|
||||
var isNew = this.val().indexOf("new") == 0;
|
||||
var suggestion = field.entwine('ss').suggestValue(this.val());
|
||||
var confirmMessage = ss.i18n.sprintf(
|
||||
ss.i18n._t(
|
||||
'UPDATEURL.CONFIRM',
|
||||
'Would you like me to change the URL to:\n\n'
|
||||
+ '%s/\n\nClick Ok to change the URL, '
|
||||
+ 'click Cancel to leave it as:\n\n%s'
|
||||
),
|
||||
suggestion,
|
||||
field.val()
|
||||
var confirmMessage = ss.i18n._t(
|
||||
'UPDATEURL.CONFIRMSIMPLE',
|
||||
'Do you want to update the URL from your new page title?'
|
||||
);
|
||||
|
||||
// don't ask for replacement if record is considered 'new' as defined by its title
|
||||
if(isNew || (suggestion != field.val() && confirm(confirmMessage))) {
|
||||
field.val(suggestion);
|
||||
if(isNew || confirm(confirmMessage)) {
|
||||
field.val(this.val()).trigger('change');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user