Skip to content
Browse files

ENHANCEMENT Replaced client side URL filtering in CMS with ajax callb…

…acks to new SiteTreeURLSegmentField, in order to align with extended server side logic (and avoid pre-filtering values too heavily before passing them to the server). Removed suggestions from client side user confirmation.
  • Loading branch information...
1 parent 0b5d205 commit e649082830e64a0679d1f05d8b4b951b23c177a4 @chillu chillu committed Nov 14, 2011
Showing with 77 additions and 56 deletions.
  1. +42 −0 code/forms/SiteTreeURLSegmentField.php
  2. +3 −3 code/model/SiteTree.php
  3. +32 −53 javascript/CMSMain.EditForm.js
View
42 code/forms/SiteTreeURLSegmentField.php
@@ -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');
+ }
+}
View
6 code/model/SiteTree.php
@@ -1385,7 +1385,7 @@ protected function onBeforeWrite() {
if((!$this->URLSegment || $this->URLSegment == 'new-page') && $this->Title) {
$this->URLSegment = $this->generateURLSegment($this->Title);
} else if($this->isChanged('URLSegment')) {
- $filter = Object::create('URLPathFilter');
+ $filter = Object::create('URLSegmentFilter');
$this->URLSegment = $filter->filter($this->URLSegment);
// If after sanitising there is no URLSegment, give it a reasonable default
if(!$this->URLSegment) $this->URLSegment = "page-$this->ID";
@@ -1578,7 +1578,7 @@ public function validURLSegment() {
* @return string Generated url segment
*/
function generateURLSegment($title){
- $filter = Object::create('URLPathFilter');
+ $filter = Object::create('URLSegmentFilter');
$t = $filter->filter($title);
// Fallback to generic page name if path is empty (= no valid, convertable characters)
@@ -1828,7 +1828,7 @@ function getCMSFields() {
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
),
View
85 javascript/CMSMain.EditForm.js
@@ -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
- */
- 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
+ * (Function) callback
*/
- 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');
}
}
});

0 comments on commit e649082

Please sign in to comment.
Something went wrong with that request. Please try again.