mirror of
https://github.com/silverstripe/silverstripe-cms
synced 2024-10-22 08:05:56 +02:00
Merge pull request #1083 from mateusz/fix-link-tracking
API Change broken link hihglighting to write to database.
This commit is contained in:
commit
23e70009d8
@ -4,6 +4,3 @@ LeftAndMain:
|
|||||||
Security:
|
Security:
|
||||||
extensions:
|
extensions:
|
||||||
- ErrorPageControllerExtension
|
- ErrorPageControllerExtension
|
||||||
HtmlEditorField:
|
|
||||||
extensions:
|
|
||||||
- SiteTreeLinkTracking_Highlighter
|
|
||||||
|
@ -37,15 +37,39 @@ class SiteTreeLinkTracking extends DataExtension {
|
|||||||
"ImageTracking" => array("FieldName" => "Varchar")
|
"ImageTracking" => array("FieldName" => "Varchar")
|
||||||
);
|
);
|
||||||
|
|
||||||
function trackLinksInField($field) {
|
public function trackLinksInField($fieldName) {
|
||||||
$record = $this->owner;
|
$record = $this->owner;
|
||||||
|
|
||||||
$linkedPages = array();
|
$linkedPages = array();
|
||||||
$linkedFiles = array();
|
$linkedFiles = array();
|
||||||
|
|
||||||
$htmlValue = Injector::inst()->create('HTMLValue', $record->$field);
|
$htmlValue = Injector::inst()->create('HTMLValue', $record->$fieldName);
|
||||||
$links = $this->parser->process($htmlValue);
|
$links = $this->parser->process($htmlValue);
|
||||||
|
|
||||||
|
// Highlight broken links in the content.
|
||||||
|
foreach ($links as $link) {
|
||||||
|
$classStr = trim($link['DOMReference']->getAttribute('class'));
|
||||||
|
if (!$classStr) {
|
||||||
|
$classes = array();
|
||||||
|
} else {
|
||||||
|
$classes = explode(' ', $classStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add or remove the broken class from the link, depending on the link status.
|
||||||
|
if ($link['Broken']) {
|
||||||
|
$classes = array_unique(array_merge($classes, array('ss-broken')));
|
||||||
|
} else {
|
||||||
|
$classes = array_diff($classes, array('ss-broken'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($classes)) {
|
||||||
|
$link['DOMReference']->setAttribute('class', implode(' ', $classes));
|
||||||
|
} else {
|
||||||
|
$link['DOMReference']->removeAttribute('class');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$record->$fieldName = $htmlValue->getContent();
|
||||||
|
|
||||||
// Populate link tracking for internal links & links to asset files.
|
// Populate link tracking for internal links & links to asset files.
|
||||||
foreach ($links as $link) {
|
foreach ($links as $link) {
|
||||||
switch ($link['Type']) {
|
switch ($link['Type']) {
|
||||||
@ -88,13 +112,13 @@ class SiteTreeLinkTracking extends DataExtension {
|
|||||||
if($record->ID && $record->many_many('LinkTracking') && $tracker = $record->LinkTracking()) {
|
if($record->ID && $record->many_many('LinkTracking') && $tracker = $record->LinkTracking()) {
|
||||||
$tracker->removeByFilter(sprintf(
|
$tracker->removeByFilter(sprintf(
|
||||||
'"FieldName" = \'%s\' AND "%s" = %d',
|
'"FieldName" = \'%s\' AND "%s" = %d',
|
||||||
$field,
|
$fieldName,
|
||||||
$tracker->getForeignKey(),
|
$tracker->getForeignKey(),
|
||||||
$record->ID
|
$record->ID
|
||||||
));
|
));
|
||||||
|
|
||||||
if($linkedPages) foreach($linkedPages as $item) {
|
if($linkedPages) foreach($linkedPages as $item) {
|
||||||
$tracker->add($item, array('FieldName' => $field));
|
$tracker->add($item, array('FieldName' => $fieldName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,18 +126,18 @@ class SiteTreeLinkTracking extends DataExtension {
|
|||||||
if($record->ID && $record->many_many('ImageTracking') && $tracker = $record->ImageTracking()) {
|
if($record->ID && $record->many_many('ImageTracking') && $tracker = $record->ImageTracking()) {
|
||||||
$tracker->removeByFilter(sprintf(
|
$tracker->removeByFilter(sprintf(
|
||||||
'"FieldName" = \'%s\' AND "%s" = %d',
|
'"FieldName" = \'%s\' AND "%s" = %d',
|
||||||
$field,
|
$fieldName,
|
||||||
$tracker->getForeignKey(),
|
$tracker->getForeignKey(),
|
||||||
$record->ID
|
$record->ID
|
||||||
));
|
));
|
||||||
|
|
||||||
if($linkedFiles) foreach($linkedFiles as $item) {
|
if($linkedFiles) foreach($linkedFiles as $item) {
|
||||||
$tracker->add($item, array('FieldName' => $field));
|
$tracker->add($item, array('FieldName' => $fieldName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function augmentSyncLinkTracking() {
|
public function augmentSyncLinkTracking() {
|
||||||
// Reset boolean broken flags
|
// Reset boolean broken flags
|
||||||
$this->owner->HasBrokenLink = false;
|
$this->owner->HasBrokenLink = false;
|
||||||
$this->owner->HasBrokenFile = false;
|
$this->owner->HasBrokenFile = false;
|
||||||
@ -134,51 +158,6 @@ class SiteTreeLinkTracking extends DataExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension for enabling highlighting of broken links in the HtmlEditorFields.
|
|
||||||
*/
|
|
||||||
class SiteTreeLinkTracking_Highlighter extends Extension {
|
|
||||||
|
|
||||||
public $parser;
|
|
||||||
|
|
||||||
private static $dependencies = array(
|
|
||||||
'parser' => '%$SiteTreeLinkTracking_Parser'
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an ability to highlight broken links in the content.
|
|
||||||
* It reuses the parser the SiteTreeLinkTracking uses for maintaining the references and the "broken" flags
|
|
||||||
* to make sure all pages listed in the BrokenLinkChecker highlight these in their content.
|
|
||||||
*/
|
|
||||||
public function onBeforeRender($field) {
|
|
||||||
// Handle situation when the field has been customised, i.e. via $properties on the HtmlEditorField::Field call.
|
|
||||||
$obj = $this->owner->getCustomisedObj() ?: $this->owner;
|
|
||||||
$value = $obj->value;
|
|
||||||
|
|
||||||
// Parse the text as DOM.
|
|
||||||
$htmlValue = Injector::inst()->create('HTMLValue', $value);
|
|
||||||
$links = $this->parser->process($htmlValue);
|
|
||||||
|
|
||||||
foreach ($links as $link) {
|
|
||||||
$classStr = $link['DOMReference']->getAttribute('class');
|
|
||||||
$classes = explode(' ', $classStr);
|
|
||||||
|
|
||||||
// Add or remove the broken class from the link, depending on the link status.
|
|
||||||
if ($link['Broken']) {
|
|
||||||
$classes = array_unique(array_merge($classes, array('ss-broken')));
|
|
||||||
} else {
|
|
||||||
$classes = array_diff($classes, array('ss-broken'));
|
|
||||||
}
|
|
||||||
$link['DOMReference']->setAttribute('class', implode(' ', $classes));
|
|
||||||
}
|
|
||||||
|
|
||||||
$obj->customise(array(
|
|
||||||
'Value' => htmlentities($htmlValue->getContent(), ENT_COMPAT, 'UTF-8')
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A helper object for extracting information about links.
|
* A helper object for extracting information about links.
|
||||||
*/
|
*/
|
||||||
|
@ -292,13 +292,6 @@ class SiteTreeBrokenLinksTest extends SapphireTest {
|
|||||||
$this->assertFalse((bool)$vp->HasBrokenLink);
|
$this->assertFalse((bool)$vp->HasBrokenLink);
|
||||||
$this->assertFalse((bool)$rp->HasBrokenLink);
|
$this->assertFalse((bool)$rp->HasBrokenLink);
|
||||||
|
|
||||||
// However, the page isn't marked as modified on stage
|
|
||||||
$this->assertFalse($p2->IsModifiedOnStage);
|
|
||||||
$this->assertFalse($rp->IsModifiedOnStage);
|
|
||||||
|
|
||||||
// This is something that we know to be broken
|
|
||||||
//$this->assertFalse($vp->IsModifiedOnStage);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testBrokenAnchorLinksInAPage() {
|
public function testBrokenAnchorLinksInAPage() {
|
||||||
|
@ -166,37 +166,4 @@ class SiteTreeHtmlEditorFieldTest extends FunctionalTest {
|
|||||||
$this->assertFalse((bool) $sitetree->HasBrokenFile);
|
$this->assertFalse((bool) $sitetree->HasBrokenFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testBrokenLinkHighlighting() {
|
|
||||||
$sitetree = new SiteTree();
|
|
||||||
$editor = new HtmlEditorField('Content');
|
|
||||||
|
|
||||||
// SiteTree link highlighting
|
|
||||||
$editor->setValue('<a href="[sitetree_link,id=0]">Broken Link</a>');
|
|
||||||
|
|
||||||
$element = new SimpleXMLElement(html_entity_decode((string) new SimpleXMLElement($editor->Field())));
|
|
||||||
$this->assertContains('ss-broken', (string) $element['class'], 'A broken SiteTree link is highlighted');
|
|
||||||
|
|
||||||
$editor->setValue(sprintf (
|
|
||||||
'<a href="[sitetree_link,id=%d]">Working Link</a>',
|
|
||||||
$this->idFromFixture('SiteTree', 'home')
|
|
||||||
));
|
|
||||||
|
|
||||||
$element = new SimpleXMLElement(html_entity_decode((string) new SimpleXMLElement($editor->Field())));
|
|
||||||
$this->assertNotContains('ss-broken', (string) $element['class']);
|
|
||||||
|
|
||||||
// File link highlighting
|
|
||||||
$editor->setValue('<a href="[file_link,id=0]">Broken Link</a>');
|
|
||||||
|
|
||||||
$element = new SimpleXMLElement(html_entity_decode((string) new SimpleXMLElement($editor->Field())));
|
|
||||||
$this->assertContains('ss-broken', (string) $element['class'], 'A broken File link is highlighted');
|
|
||||||
|
|
||||||
$editor->setValue(sprintf (
|
|
||||||
'<a href="[file_link,id=%d]">Working Link</a>',
|
|
||||||
$this->idFromFixture('File', 'example_file')
|
|
||||||
));
|
|
||||||
|
|
||||||
$element = new SimpleXMLElement(html_entity_decode((string) new SimpleXMLElement($editor->Field())));
|
|
||||||
$this->assertNotContains('ss-broken', (string) $element['class']);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -35,10 +35,10 @@ class SiteTreeLinkTrackingTest extends SapphireTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function highlight($content) {
|
function highlight($content) {
|
||||||
$field = new SiteTreeLinkTrackingTest_Field('Test');
|
$page = new Page();
|
||||||
$field->setValue($content);
|
$page->Content = $content;
|
||||||
$newContent = html_entity_decode($field->Field(), ENT_COMPAT, 'UTF-8');
|
$page->write();
|
||||||
return $newContent;
|
return $page->Content;
|
||||||
}
|
}
|
||||||
|
|
||||||
function testHighlighter() {
|
function testHighlighter() {
|
||||||
@ -49,20 +49,15 @@ class SiteTreeLinkTrackingTest extends SapphireTest {
|
|||||||
$content = $this->highlight('<a href="[sitetree_link,id=123]">link</a>');
|
$content = $this->highlight('<a href="[sitetree_link,id=123]">link</a>');
|
||||||
$this->assertEquals(substr_count($content, 'ss-broken'), 1, 'ss-broken class is added to the broken link.');
|
$this->assertEquals(substr_count($content, 'ss-broken'), 1, 'ss-broken class is added to the broken link.');
|
||||||
|
|
||||||
$page = new Page();
|
$otherPage = new Page();
|
||||||
$page->Content = '';
|
$otherPage->Content = '';
|
||||||
$page->write();
|
$otherPage->write();
|
||||||
|
|
||||||
$content = $this->highlight(
|
$content = $this->highlight(
|
||||||
"<a href=\"[sitetree_link,id=$page->ID]\" class=\"existing-class ss-broken ss-broken\">link</a>"
|
"<a href=\"[sitetree_link,id=$otherPage->ID]\" class=\"existing-class ss-broken ss-broken\">link</a>"
|
||||||
);
|
);
|
||||||
$this->assertEquals(substr_count($content, 'ss-broken'), 0, 'All ss-broken classes are removed from good link');
|
$this->assertEquals(substr_count($content, 'ss-broken'), 0, 'All ss-broken classes are removed from good link');
|
||||||
$this->assertEquals(substr_count($content, 'existing-class'), 1, 'Existing class is not removed.');
|
$this->assertEquals(substr_count($content, 'existing-class'), 1, 'Existing class is not removed.');
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
class SiteTreeLinkTrackingTest_Field extends HtmlEditorField implements TestOnly {
|
|
||||||
private static $extensions = array(
|
|
||||||
'SiteTreeLinkTracking_Highlighter'
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -29,12 +29,12 @@ class MigrateSiteTreeLinkingTaskTest extends SapphireTest {
|
|||||||
$hashID = $this->idFromFixture('SiteTree', 'hash_link');
|
$hashID = $this->idFromFixture('SiteTree', 'hash_link');
|
||||||
|
|
||||||
$homeContent = sprintf (
|
$homeContent = sprintf (
|
||||||
'<a href="[sitetree_link,id=%d]">About</a><a href="[sitetree_link,id=%d]">Staff</a><a href="http://silverstripe.org/">External Link</a>',
|
'<a href="[sitetree_link,id=%d]">About</a><a href="[sitetree_link,id=%d]">Staff</a><a href="http://silverstripe.org/">External Link</a><a name="anchor"></a>',
|
||||||
$aboutID,
|
$aboutID,
|
||||||
$staffID
|
$staffID
|
||||||
);
|
);
|
||||||
$aboutContent = sprintf (
|
$aboutContent = sprintf (
|
||||||
'<a href="[sitetree_link,id=%d]">Home</a><a href="[sitetree_link,id=%d]">Staff</a>',
|
'<a href="[sitetree_link,id=%d]">Home</a><a href="[sitetree_link,id=%d]">Staff</a><a name="second-anchor"></a>',
|
||||||
$homeID,
|
$homeID,
|
||||||
$staffID
|
$staffID
|
||||||
);
|
);
|
||||||
|
@ -2,11 +2,11 @@ SiteTree:
|
|||||||
home:
|
home:
|
||||||
Title: Home Page
|
Title: Home Page
|
||||||
URLSegment: home
|
URLSegment: home
|
||||||
Content: '<a href="about/">About</a><a href="staff">Staff</a><a href="http://silverstripe.org/">External Link</a>'
|
Content: '<a href="about/">About</a><a href="staff">Staff</a><a href="http://silverstripe.org/">External Link</a><a name="anchor"></a>'
|
||||||
about:
|
about:
|
||||||
Title: About Us
|
Title: About Us
|
||||||
URLSegment: about
|
URLSegment: about
|
||||||
Content: '<a href="home">Home</a><a href="staff/">Staff</a>'
|
Content: '<a href="home">Home</a><a href="staff/">Staff</a><a name="second-anchor"></a>'
|
||||||
staff:
|
staff:
|
||||||
Title: Staff
|
Title: Staff
|
||||||
URLSegment: staff
|
URLSegment: staff
|
||||||
|
Loading…
Reference in New Issue
Block a user