Skip to content

Instantly share code, notes, and snippets.

@ajshort
Created October 3, 2009 02:53
Show Gist options
  • Select an option

  • Save ajshort/200362 to your computer and use it in GitHub Desktop.

Select an option

Save ajshort/200362 to your computer and use it in GitHub Desktop.
@@ -30,61 +30,80 @@ class HtmlEditorField extends TextareaField {
/**
* @return string
*/
function Field() {
+ // mark up broken links
+ $value = new SS_HTMLValue($this->value);
+ $parser = ShortcodeParser::get_active();
+
+ if($links = $value->getElementsByTagName('a')) foreach($links as $link) {
+ $matches = array();
+
+ if(preg_match('/\[sitetree_link id=([0-9]+)\]/i', $link->getAttribute('href'), $matches)) {
+ if(!DataObject::get_by_id('SiteTree', $matches[1])) {
+ $class = $link->getAttribute('class');
+ $link->setAttribute('class', ($class ? "$class ss-broken" : 'ss-broken'));
+ }
+ }
+ }
+
return $this->createTag (
'textarea',
array (
'class' => $this->extraClass(),
'rows' => $this->rows,
'cols' => $this->cols,
- 'style' => "width: 97%; height: " . ($this->rows * 16) . "px", // Prevents horizontal scrollbars
+ 'style' => 'width: 97%; height: ' . ($this->rows * 16) . 'px', // prevents horizontal scrollbars
'tinymce' => 'true',
'id' => $this->id(),
'name' => $this->name
),
- htmlentities($this->value, ENT_COMPAT, 'UTF-8')
+ htmlentities($value->getContent(), ENT_COMPAT, 'UTF-8')
);
}
public function saveInto($record) {
if($record->escapeTypeForField($this->name) != 'xml') {
throw new Exception (
'HtmlEditorField->saveInto(): This field should save into a HTMLText or HTMLVarchar field.'
);
}
- $value = $this->value ? $this->value : '<p></p>';
- $value = preg_replace('/src="([^\?]*)\?r=[0-9]+"/i', 'src="$1"', $value);
-
$linkedPages = array();
$linkedFiles = array();
- $document = new DOMDocument(null, 'UTF-8');
- $document->strictErrorChecking = false;
- $document->loadHTML($value);
+ $htmlValue = new SS_HTMLValue($this->value);
+ $parser = ShortcodeParser::get_active();
// Populate link tracking for internal links & links to asset files.
- if($links = $document->getElementsByTagName('a')) foreach($links as $link) {
- $link = Director::makeRelative($link->getAttribute('href'));
+ if($links = $htmlValue->getElementsByTagName('a')) foreach($links as $link) {
+ $href = Director::makeRelative($link->getAttribute('href'));
- if(preg_match('/\[sitetree_link id=([0-9]+)\]/i', $link, $matches)) {
+ if(preg_match('/\[sitetree_link id=([0-9]+)\]/i', $href, $matches)) {
$ID = $matches[1];
+ // clear out any broken link classes
+ if($class = $link->getAttribute('class')) {
+ $link->setAttribute('class', preg_replace('/(^ss-broken|ss-broken$| ss-broken )/', null, $class));
+ }
+
if($page = DataObject::get_by_id('SiteTree', $ID)) {
$linkedPages[] = $page->ID;
} else {
$record->HasBrokenLink = true;
}
- } elseif($link[0] != '/' && $file = File::find($link)) {
+ } elseif($href[0] != '/' && $file = File::find($href)) {
$linkedFiles[] = $file->ID;
}
}
// Resample images, add default attributes and add to assets tracking.
- if($images = $document->getElementsByTagName('img')) foreach($images as $img) {
+ if($images = $htmlValue->getElementsByTagName('img')) foreach($images as $img) {
+ // strip any ?r=n data from the src attribute
+ $img->setAttribute('src', preg_replace('/([^\?]*)\?r=[0-9]+$/i', '$1', $img->getAttribute('src')));
+
if(!$image = File::find($path = Director::makeRelative($img->getAttribute('src')))) {
if(substr($path, 0, strlen(ASSETS_DIR) + 1) == ASSETS_DIR . '/') {
$record->HasBrokenFile = true;
}
@@ -114,11 +133,11 @@ class HtmlEditorField extends TextareaField {
if($record->ID && $record->many_many('ImageTracking') && $tracker = $record->ImageTracking()) {
$tracker->setByIDList($linkedFiles);
}
- $record->{$this->name} = substr(simplexml_import_dom($document)->body->asXML(), 6, -7);
+ $record->{$this->name} = $htmlValue->getContent();
}
/**
* @return HtmlEditorField_Readonly
*/
<?php
/**
* This class acts as a wrapper around the built in DOMDocument class in order to use it to manage a HTML snippet,
* rather than a whole document, while still exposing the DOMDocument API.
*
* @package sapphire
* @subpackage integration
*/
class SS_HTMLValue extends ViewableData {
/**
* @var DOMDocument
*/
protected $document;
/**
* @param string $content
*/
public function __construct($content = null) {
$this->document = new DOMDocument('1.0', 'UTF-8');
$this->document->scrictErrorChecking = false;
$this->setContent($content);
parent::__construct();
}
/**
* @return string
*/
public function getContent() {
// saveXML is used to allow for XHTML-compliant output
$xml = $this->getDocument()->saveXML($this->getDocument()->documentElement->lastChild);
if(substr($xml, 0, 6) != '<body>') {
return null;
} else {
// as DOMDocument adds enclosing body tags by default, these need to be stripped
return substr($xml, 6, -7);
}
}
/**
* @param string $content
* @return bool
*/
public function setContent($content) {
return $this->getDocument()->loadHTML(sprintf (
'<meta http-equiv="content-type" content="text/html; charset=utf-8"><body>%s</body>', $content
));
}
/**
* @return DOMDocument
*/
public function getDocument() {
return $this->document;
}
/**
* A simple convinience wrapper around DOMDocument::getElementsByTagName().
*
* @param string $name
* @return DOMNodeList
*/
public function getElementsByTagName($name) {
return $this->getDocument()->getElementsByTagName($name);
}
/**
* @see HTMLValue::getContent()
*/
public function forTemplate() {
return $this->getContent();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment