diff --git a/_config.php b/_config.php
index 748106b2b..fea04185e 100644
--- a/_config.php
+++ b/_config.php
@@ -32,6 +32,7 @@ Object::useCustomClass('Datetime', 'SS_Datetime', true);
define('MCE_ROOT', FRAMEWORK_DIR . '/thirdparty/tinymce/');
ShortcodeParser::get('default')->register('file_link', array('File', 'link_shortcode_handler'));
+ShortcodeParser::get('default')->register('embed', array('Oembed', 'handle_shortcode'));
/**
* The secret key that needs to be sent along with pings to /Email_BounceHandler
diff --git a/_config/Oembed.yml b/_config/Oembed.yml
new file mode 100644
index 000000000..41226d09b
--- /dev/null
+++ b/_config/Oembed.yml
@@ -0,0 +1,22 @@
+name: Oembed
+---
+Oembed:
+ providers:
+ 'http://*.youtube.com/watch*':
+ 'http://www.youtube.com/oembed/'
+ 'http://*.flickr.com/*':
+ 'http://www.flickr.com/services/oembed/'
+ 'http://*.viddler.com/*':
+ 'http://lab.viddler.com/services/oembed/'
+ 'http://*.revision3.com/*':
+ 'http://revision3.com/api/oembed/'
+ 'http://*.hulu.com/watch/*':
+ 'http://www.hulu.com/api/oembed.json'
+ 'http://*.vimeo.com/*':
+ 'http://www.vimeo.com/api/oembed.json'
+ 'https://twitter.com/*':
+ 'https://api.twitter.com/1/statuses/oembed.json'
+ 'http://twitter.com/*':
+ 'https://api.twitter.com/1/statuses/oembed.json'
+ autodiscover:
+ true
diff --git a/admin/_config.php b/admin/_config.php
index cf8c14086..6a6f1a573 100644
--- a/admin/_config.php
+++ b/admin/_config.php
@@ -20,7 +20,7 @@ HtmlEditorConfig::get('cms')->enablePlugins('media', 'fullscreen');
HtmlEditorConfig::get('cms')->enablePlugins(array('ssbuttons' => sprintf('../../../%s/tinymce_ssbuttons/editor_plugin_src.js', THIRDPARTY_DIR)));
HtmlEditorConfig::get('cms')->insertButtonsBefore('formatselect', 'styleselect');
-HtmlEditorConfig::get('cms')->addButtonsToLine(2, 'ssimage', 'ssflash', 'sslink', 'unlink', 'anchor', 'separator','code', 'fullscreen', 'separator');
+HtmlEditorConfig::get('cms')->addButtonsToLine(2, 'ssmedia', 'ssflash', 'sslink', 'unlink', 'anchor', 'separator','code', 'fullscreen', 'separator');
HtmlEditorConfig::get('cms')->removeButtons('tablecontrols');
HtmlEditorConfig::get('cms')->addButtonsToLine(3, 'tablecontrols');
diff --git a/docs/en/topics/rich-text-editing.md b/docs/en/topics/rich-text-editing.md
index f9a900100..c33027afc 100644
--- a/docs/en/topics/rich-text-editing.md
+++ b/docs/en/topics/rich-text-editing.md
@@ -111,8 +111,8 @@ so this is considered advanced usage of the field.
:::php
// File: mysite/_config.php
HtmlEditorConfig::get('cms')->disablePlugins('ssbuttons');
- HtmlEditorConfig::get('cms')->removeButtons('sslink', 'ssimage');
- HtmlEditorConfig::get('cms')->addButtonsToLine(2, 'link', 'image');
+ HtmlEditorConfig::get('cms')->removeButtons('sslink', 'ssmedia');
+ HtmlEditorConfig::get('cms')->addButtonsToLine(2, 'link', 'media');
### Developing a wrapper to use a different WYSIWYG editors with HTMLEditorField
@@ -126,4 +126,4 @@ or start your own configuration.
## Related
- * [Howto: Extend the CMS Interface](../howto/extend-cms-interface)
\ No newline at end of file
+ * [Howto: Extend the CMS Interface](../howto/extend-cms-interface)
diff --git a/forms/HtmlEditorField.php b/forms/HtmlEditorField.php
index 271da6152..8df190866 100644
--- a/forms/HtmlEditorField.php
+++ b/forms/HtmlEditorField.php
@@ -391,6 +391,13 @@ class HtmlEditorField_Toolbar extends RequestHandler {
$fromCMS->addExtraClass('content');
$selectComposite->addExtraClass('content-select');
+ $fromWeb = new CompositeField(
+ new LiteralField('headerURL', '
'),
+ $remoteURL = new TextField('RemoteURL', ''),
+ new LiteralField('addURLImage', '
')
+ );
+ $remoteURL->addExtraClass('remoteurl');
+
Requirements::css(FRAMEWORK_DIR . '/css/AssetUploadField.css');
$computerUploadField = Object::create('UploadField', 'AssetUploadField', '');
$computerUploadField->setConfig('previewMaxWidth', 40);
@@ -401,11 +408,15 @@ class HtmlEditorField_Toolbar extends RequestHandler {
$computerUploadField->setFolderName(Upload::$uploads_folder);
$tabSet = new TabSet(
- "MediaFormInsertImageTabs",
+ "MediaFormInsertMediaTabs",
new Tab(
_t('HtmlEditorField.FROMCOMPUTER','From your computer'),
$computerUploadField
),
+ new Tab(
+ _t('HtmlEditorField.FROMWEB', 'From the web'),
+ $fromWeb
+ ),
new Tab(
_t('HtmlEditorField.FROMCMS','From the CMS'),
$fromCMS
@@ -423,19 +434,19 @@ class HtmlEditorField_Toolbar extends RequestHandler {
$fields = new FieldList(
new LiteralField(
'Heading',
- sprintf('', _t('HtmlEditorField.INSERTIMAGE', 'Insert Image')).
- sprintf('', _t('HtmlEditorField.UpdateIMAGE', 'Update Image'))
+ sprintf('', _t('HtmlEditorField.INSERTMEDIA', 'Insert Media')).
+ sprintf('', _t('HtmlEditorField.UpdateMEDIA', 'Update Media'))
),
$allFields
);
$actions = new FieldList(
- FormAction::create('insertimage', _t('HtmlEditorField.BUTTONINSERT', 'Insert'))
- ->addExtraClass('ss-ui-action-constructive image-insert')
+ FormAction::create('insertmedia', _t('HtmlEditorField.BUTTONINSERT', 'Insert'))
+ ->addExtraClass('ss-ui-action-constructive media-insert')
->setAttribute('data-icon', 'accept')
->setUseButtonTag(true),
- FormAction::create('insertimage', _t('HtmlEditorField.BUTTONUpdate', 'Update'))
- ->addExtraClass('ss-ui-action-constructive image-update')
+ FormAction::create('insertmedia', _t('HtmlEditorField.BUTTONUpdate', 'Update'))
+ ->addExtraClass('ss-ui-action-constructive media-update')
->setAttribute('data-icon', 'accept')
->setUseButtonTag(true)
);
@@ -493,6 +504,8 @@ class HtmlEditorField_Toolbar extends RequestHandler {
// Instanciate file wrapper and get fields based on its type
if($file && $file->appCategory() == 'image') {
$fileWrapper = new HtmlEditorField_Image($url, $file);
+ } elseif(!Director::is_site_url($url)) {
+ $fileWrapper = new HtmlEditorField_Embed($url, $file);
} else {
$fileWrapper = new HtmlEditorField_File($url, $file);
}
@@ -516,7 +529,9 @@ class HtmlEditorField_Toolbar extends RequestHandler {
protected function getFieldsForFile($url, $file) {
$fields = $this->extend('getFieldsForFile', $url, $file);
if(!$fields) {
- if($file->Extension == 'swf') {
+ if($file instanceof HtmlEditorField_Embed) {
+ $fields = $this->getFieldsForOembed($url, $file);
+ } elseif($file->Extension == 'swf') {
$fields = $this->getFieldsForFlash($url, $file);
} else {
$fields = $this->getFieldsForImage($url, $file);
@@ -529,6 +544,75 @@ class HtmlEditorField_Toolbar extends RequestHandler {
return $fields;
}
+ /**
+ * @return FieldList
+ */
+ protected function getFieldsForOembed($url, $file) {
+ if(isset($file->Oembed->thumbnail_url)) {
+ $thumbnailURL = $file->Oembed->thumbnail_url;
+ } elseif($file->Type == 'photo') {
+ $thumbnailURL = $file->Oembed->url;
+ } else {
+ $thumbnailURL = $url;
+ }
+
+ $previewField = new LiteralField("ImageFull",
+ "
\n"
+ );
+
+ $fields = new FieldList(
+ $filePreview = CompositeField::create(
+ CompositeField::create(
+ $previewField
+ )->setName("FilePreviewImage")->addExtraClass('cms-file-info-preview'),
+ CompositeField::create(
+ CompositeField::create(
+ new ReadonlyField("FileType", _t('AssetTableField.TYPE','File type') . ':', $file->Type),
+ $urlField = new ReadonlyField('ClickableURL', _t('AssetTableField.URL','URL'),
+ sprintf('%s', $url, $url)
+ )
+ )
+ )->setName("FilePreviewData")->addExtraClass('cms-file-info-data')
+ )->setName("FilePreview")->addExtraClass('cms-file-info'),
+ new TextField('CaptionText', _t('HtmlEditorField.CAPTIONTEXT', 'Caption text')),
+ new DropdownField(
+ 'CSSClass',
+ _t('HtmlEditorField.CSSCLASS', 'Alignment / style'),
+ array(
+ 'left' => _t('HtmlEditorField.CSSCLASSLEFT', 'On the left, with text wrapping around.'),
+ 'leftAlone' => _t('HtmlEditorField.CSSCLASSLEFTALONE', 'On the left, on its own.'),
+ 'right' => _t('HtmlEditorField.CSSCLASSRIGHT', 'On the right, with text wrapping around.'),
+ 'center' => _t('HtmlEditorField.CSSCLASSCENTER', 'Centered, on its own.'),
+ )
+ ),
+ $dimensionsField = new FieldGroup(_t('HtmlEditorField.IMAGEDIMENSIONS', 'Dimensions'),
+ $widthField = new TextField('Width', _t('HtmlEditorField.IMAGEWIDTHPX', 'Width'), $file->Width),
+ $heightField = new TextField('Height', " x " . _t('HtmlEditorField.IMAGEHEIGHTPX', 'Height'), $file->Height)
+ )
+ );
+ $urlField->dontEscape = true;
+ $dimensionsField->addExtraClass('dimensions');
+ $widthField->setMaxLength(5);
+ $heightField->setMaxLength(5);
+
+ if($file->Type == 'photo') {
+ $filePreview->FieldList()->insertBefore(new TextField(
+ 'AltText',
+ _t('HtmlEditorField.IMAGEALTTEXT', 'Alternative text (alt) - shown if image cannot be displayed'),
+ $file->Title,
+ 80
+ ), 'CaptionText');
+ $filePreview->FieldList()->insertBefore(new TextField(
+ 'Title',
+ _t('HtmlEditorField.IMAGETITLE', 'Title text (tooltip) - for additional information about the image')
+ ), 'CaptionText');
+ }
+
+ $this->extend('updateFieldsForImage', $fields, $url, $file);
+
+ return $fields;
+ }
+
/**
* @return FieldList
*/
@@ -552,8 +636,8 @@ class HtmlEditorField_Toolbar extends RequestHandler {
* @return FieldList
*/
protected function getFieldsForImage($url, $file) {
- if($file instanceof Image) {
- $formattedImage = $file->FormattedImage('SetWidth', Image::$asset_preview_width);
+ if($file->File instanceof Image) {
+ $formattedImage = $file->File->generateFormattedImage('SetWidth', Image::$asset_preview_width);
$thumbnailURL = $formattedImage ? $formattedImage->URL : $url;
} else {
$thumbnailURL = $url;
@@ -719,6 +803,52 @@ class HtmlEditorField_File extends ViewableData {
}
+class HtmlEditorField_Embed extends HtmlEditorField_File {
+ protected $oembed;
+
+ public function __construct($url, $file = null) {
+ parent::__construct($url, $file);
+ $this->oembed = Oembed::get_oembed_from_url($url);
+ if(!$this->oembed) {
+ return Controller::curr()->httpError(404, 'The URL ' . $url . ' could not be turned into a media resource.');
+ }
+ }
+
+ public function getWidth() {
+ return $this->oembed->Width;
+ }
+
+ public function getHeight() {
+ return $this->oembed->Height;
+ }
+
+ public function getPreview() {
+ if(isset($this->oembed->thumbnail_url)) {
+ return sprintf('
', $this->oembed->thumbnail_url);
+ }
+ }
+
+ public function getName() {
+ if(isset($this->oembed->title)) {
+ return $this->oembed->title;
+ } else {
+ return parent::getName();
+ }
+ }
+
+ public function getType() {
+ return $this->oembed->type;
+ }
+
+ public function getOembed() {
+ return $this->oembed;
+ }
+
+ public function appCategory() {
+ return 'embed';
+ }
+}
+
class HtmlEditorField_Image extends HtmlEditorField_File {
protected $width;
diff --git a/javascript/HtmlEditorField.js b/javascript/HtmlEditorField.js
index 84da7e25b..e9ff08725 100644
--- a/javascript/HtmlEditorField.js
+++ b/javascript/HtmlEditorField.js
@@ -683,7 +683,7 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
var self = this, ed = this.getEditor(), node = $(ed.getSelectedNode());
// TODO Depends on managed mime type
if(node.is('img')) {
- this.showFileView(node.attr('src'), function() {
+ this.showFileView(node.data('url') || node.attr('src'), function() {
$(this).updateFromNode(node);
self.toggleCloseButton();
self.redraw();
@@ -711,9 +711,9 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
var updateExisting = Boolean(this.find('.ss-htmleditorfield-file').length);
this.find('.htmleditorfield-mediaform-heading.insert')[updateExisting ? 'hide' : 'show']();
- this.find('.Actions .image-insert')[updateExisting ? 'hide' : 'show']();
+ this.find('.Actions .media-insert')[updateExisting ? 'hide' : 'show']();
this.find('.htmleditorfield-mediaform-heading.update')[updateExisting ? 'show' : 'hide']();
- this.find('.Actions .image-update')[updateExisting ? 'show' : 'hide']();
+ this.find('.Actions .media-update')[updateExisting ? 'show' : 'hide']();
},
resetFields: function() {
var ed = this.getEditor(), node = $(ed.getSelectedNode());
@@ -796,6 +796,21 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
});
+ /**
+ * Show the second step after adding a URL
+ */
+ $('form.htmleditorfield-form.htmleditorfield-mediaform img.add-url').entwine({
+ onclick: function(e) {
+ var form = this.closest('form');
+
+ var urlField = this.closest('.CompositeField').find('input.remoteurl');
+
+ form.showFileView(urlField.val());
+ form.redraw();
+ }
+
+ });
+
/**
* Represents a single selected file, together with a set of form fields to edit its properties.
* Overload this based on the media type to determine how the HTML should be created.
@@ -985,6 +1000,60 @@ ss.editorWrappers['default'] = ss.editorWrappers.tinyMCE;
}
});
+
+ /**
+ * Insert an oembed object tag into the content.
+ * Requires the 'media' plugin for serialization of tags into
placeholders.
+ */
+ $('form.htmleditorfield-mediaform .ss-htmleditorfield-file.embed').entwine({
+ getAttributes: function() {
+ var width = this.find(':input[name=Width]').val(),
+ height = this.find(':input[name=Height]').val();
+ return {
+ 'src' : this.find('.thumbnail-preview').attr('src'),
+ 'width' : width ? parseInt(width, 10) : null,
+ 'height' : height ? parseInt(height, 10) : null,
+ 'class' : this.find(':input[name=CSSClass]').val()
+ };
+ },
+ getExtraData: function() {
+ var width = this.find(':input[name=Width]').val(),
+ height = this.find(':input[name=Height]').val();
+ return {
+ 'CaptionText': this.find(':input[name=CaptionText]').val(),
+ 'Url': this.find(':input[name=URL]').val(),
+ 'thumbnail': this.find('.thumbnail-preview').attr('src'),
+ 'width' : width ? parseInt(width, 10) : null,
+ 'height' : height ? parseInt(height, 10) : null,
+ 'cssclass': this.find(':input[name=CSSClass]').val()
+ };
+ },
+ getHTML: function() {
+ var el,
+ attrs = this.getAttributes(),
+ extraData = this.getExtraData(),
+ // imgEl = $('
');
+ imgEl = $('
').attr(attrs).addClass('ss-htmleditorfield-file embed');
+
+ $.each(extraData, function (key, value) {
+ imgEl.attr('data-' + key, value)
+ });
+
+ if(extraData.CaptionText) {
+ el = $('' + extraData.CaptionText + '
').prepend(imgEl);
+ } else {
+ el = imgEl;
+ }
+ return $('').append(el).html(); // Little hack to get outerHTML string
+ },
+ updateFromNode: function(node) {
+ this.find(':input[name=Width]').val(node.width());
+ this.find(':input[name=Height]').val(node.height());
+ this.find(':input[name=Title]').val(node.attr('title'));
+ this.find(':input[name=CSSClass]').val(node.data('cssclass'));
+ }
+ });
+
$('form.htmleditorfield-mediaform .ss-htmleditorfield-file .dimensions :input').entwine({
OrigVal: null,
onmatch: function () {
diff --git a/lang/en.yml b/lang/en.yml
index 0bc966800..2bcd97fc9 100644
--- a/lang/en.yml
+++ b/lang/en.yml
@@ -255,7 +255,7 @@ en:
IMAGEHEIGHTPX: Height
IMAGETITLE: 'Title text (tooltip) - for additional information about the image'
IMAGEWIDTHPX: Width
- INSERTIMAGE: 'Insert Image'
+ INSERTMEDIA: 'Insert Media'
LINK: 'Insert Link'
LINKANCHOR: 'Anchor on this page'
LINKDESCR: 'Link description'
diff --git a/oembed/Oembed.php b/oembed/Oembed.php
new file mode 100644
index 000000000..8609dfeb3
--- /dev/null
+++ b/oembed/Oembed.php
@@ -0,0 +1,192 @@
+get('Oembed', 'autodiscover');
+ }
+
+ public static function get_providers() {
+ return Config::inst()->get('Oembed', 'providers');
+ }
+
+ protected static function match_url($url) {
+ foreach(self::get_providers() as $scheme=>$endpoint) {
+ if(self::match_scheme($url, $scheme)) {
+ return $endpoint;
+ }
+ }
+ return false;
+ }
+
+ protected static function match_scheme($url, $scheme) {
+ $urlInfo = parse_url($url);
+ $schemeInfo = parse_url($scheme);
+ foreach($schemeInfo as $k=>$v) {
+ if(!array_key_exists($k, $urlInfo)) {
+ return false;
+ }
+ if(strpos($v, '*') !== false) {
+ $v = preg_quote($v, '/');
+ $v = str_replace('\*', '.*', $v);
+ if($k == 'host') {
+ $v = str_replace('*\.', '*', $v);
+ }
+ if(!preg_match('/' . $v . '/', $urlInfo[$k])) {
+ return false;
+ }
+ } elseif(strcasecmp($urlInfo[$k], $v)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ protected static function autodiscover_from_url($url) {
+ $service = new RestfulService($url);
+ $body = $service->request();
+ if(!$body || $body->isError()) {
+ return false;
+ }
+ $body = $body->getBody();
+
+ if(preg_match_all('#]+?(?:href=[\'"](.+?)[\'"][^>]+?)?type=["\']application/json\+oembed["\'](?:[^>]+?href=[\'"](.+?)[\'"])?#', $body, $matches, PREG_SET_ORDER)) {
+ $match = $matches[0];
+ if(!empty($match[1])) {
+ return html_entity_decode($match[1]);
+ }
+ if(!empty($match[2])) {
+ return html_entity_decode($match[2]);
+ }
+ }
+ return false;
+ }
+
+ public static function get_oembed_from_url($url, $type = false, Array $options = array()) {
+ $endpoint = self::match_url($url);
+ $ourl = false;
+ if(!$endpoint) {
+ if(self::get_autodiscover()) {
+ $ourl = self::autodiscover_from_url($url);
+ }
+ } elseif($endpoint === true) {
+ $ourl = self::autodiscover_from_url($url);
+ } else {
+ $ourl = Controller::join_links($endpoint, '?format=json&url=' . rawurlencode($url));
+ }
+ if($ourl) {
+ if($options) {
+ if(isset($options['width']) && !isset($options['maxwidth'])) {
+ $options['maxwidth'] = $options['width'];
+ }
+ if(isset($options['height']) && !isset($options['maxheight'])) {
+ $options['maxheight'] = $options['height'];
+ }
+ $ourl = Controller::join_links($ourl, '?' . http_build_query($options, '', '&'));
+ }
+ return new Oembed_Result($ourl, $url, $type, $options);
+ }
+ return false;
+ }
+
+ public static function handle_shortcode($arguments, $url, $parser, $shortcode) {
+ if(isset($arguments['type'])) {
+ $type = $arguments['type'];
+ unset($arguments['type']);
+ } else {
+ $type = false;
+ }
+ $oembed = self::get_oembed_from_url($url, $type, $arguments);
+ if($oembed && $oembed->exists()) {
+ return $oembed->forTemplate();
+ } else {
+ return '' . $url . '';
+ }
+ }
+}
+
+class Oembed_Result extends ViewableData {
+ protected $data = false;
+ protected $origin = false;
+ protected $type = false;
+ protected $url;
+ protected $extraClass;
+
+ public static $casting = array(
+ 'html' => 'HTMLText',
+ );
+
+ public function __construct($url, $origin = false, $type = false, Array $options = array()) {
+ $this->url = $url;
+ $this->origin = $origin;
+ $this->type = $type;
+
+ if(isset($options['class'])) {
+ $this->extraClass = $options['class'];
+ }
+
+ parent::__construct();
+ }
+
+ protected function loadData() {
+ if($this->data !== false) {
+ return;
+ }
+ $service = new RestfulService($this->url);
+ $body = $service->request();
+ if(!$body || $body->isError()) {
+ $this->data = array();
+ return;
+ }
+ $body = $body->getBody();
+ $data = json_decode($body, true);
+ if(!$data) {
+ $data = array();
+ }
+ foreach($data as $k=>$v) {
+ unset($data[$k]);
+ $data[strtolower($k)] = $v;
+ }
+ if($this->type && $this->type != $data['type']) {
+ $data = array();
+ }
+ $this->data = $data;
+ }
+
+ public function hasField($field) {
+ $this->loadData();
+ return array_key_exists(strtolower($field), $this->data);
+ }
+
+ public function getField($field) {
+ $field = strtolower($field);
+ if($this->hasField($field)) {
+ return $this->data[$field];
+ }
+ }
+
+ public function forTemplate() {
+ $this->loadData();
+ switch($this->Type) {
+ case 'video':
+ case 'rich':
+ if($this->extraClass) {
+ return "";
+ } else {
+ return $this->HTML;
+ }
+ break;
+ case 'link':
+ return '';
+ break;
+ case 'photo':
+ return "";
+ break;
+ }
+ }
+
+ public function exists() {
+ $this->loadData();
+ return count($this->data) > 0;
+ }
+}
+
diff --git a/thirdparty/tinymce/plugins/fullscreen/fullscreen.htm b/thirdparty/tinymce/plugins/fullscreen/fullscreen.htm
index ffe528e41..f9d87a6d8 100644
--- a/thirdparty/tinymce/plugins/fullscreen/fullscreen.htm
+++ b/thirdparty/tinymce/plugins/fullscreen/fullscreen.htm
@@ -23,7 +23,7 @@
// Patch callbacks, make them point to window.opener
patchCallback(settings, 'urlconverter_callback');
patchCallback(settings, 'insertlink_callback');
- patchCallback(settings, 'insertimage_callback');
+ patchCallback(settings, 'insertmedia_callback');
patchCallback(settings, 'setupcontent_callback');
patchCallback(settings, 'save_callback');
patchCallback(settings, 'onchange_callback');
diff --git a/thirdparty/tinymce_ssbuttons/editor_plugin_src.js b/thirdparty/tinymce_ssbuttons/editor_plugin_src.js
index 195972305..c73fa2ff1 100644
--- a/thirdparty/tinymce_ssbuttons/editor_plugin_src.js
+++ b/thirdparty/tinymce_ssbuttons/editor_plugin_src.js
@@ -29,13 +29,13 @@
init : function(ed, url) {
ed.addButton('sslink', {title : ed.getLang('tinymce_ssbuttons.insertlink'), cmd : 'sslink', 'class' : 'mce_link'});
- ed.addButton('ssimage', {title : ed.getLang('tinymce_ssbuttons.insertimage'), cmd : 'ssimage', 'class' : 'mce_image'});
+ ed.addButton('ssmedia', {title : ed.getLang('tinymce_ssbuttons.insertmedia'), cmd : 'ssmedia', 'class' : 'mce_image'});
ed.addCommand('sslink', function(ed) {
jQuery('#' + this.id).entwine('ss').openLinkDialog();
});
- ed.addCommand('ssimage', function(ed) {
+ ed.addCommand('ssmedia', function(ed) {
jQuery('#' + this.id).entwine('ss').openMediaDialog();
});
@@ -44,6 +44,63 @@
cm.setDisabled('sslink', co && n.nodeName != 'A');
cm.setActive('sslink', n.nodeName == 'A' && !n.name);
});
+
+ ed.onSaveContent.add(function(ed, o) {
+ var content = jQuery(o.content);
+ content.find('.ss-htmleditorfield-file.embed').each(function() {
+ var el = jQuery(this);
+ var shortCode = '[embed width=' + el.data('width')
+ + ' height=' + el.data('height')
+ + ' class=' + el.data('cssclass')
+ + ' thumbnail=' + el.data('thumbnail')
+ + ']' + el.data('url')
+ + '[/embed]';
+ el.replaceWith(shortCode);
+ });
+ o.content = jQuery('').append(content).html(); // Little hack to get outerHTML string
+ });
+
+ var shortTagRegex = /(.?)\[embed(.*?)\](.+?)\[\/\s*embed\s*\](.?)/gi;
+ ed.onBeforeSetContent.add(function(ed, o) {
+ var matches = null, content = o.content;
+ var prefix, suffix, attributes, attributeString, url;
+ var attrs, attr;
+ var imgEl;
+ while((matches = shortTagRegex.exec(content))) {
+ prefix = matches[1];
+ suffix = matches[4];
+ if(prefix === '[' && suffix === ']') {
+ continue;
+ }
+ attributes = {};
+ attributeString = matches[2].replace(/['"]/g, '').replace(/(^\s+|\s+$)/g, '');
+ attrs = attributeString.split(/\s+/);
+ for(attribute in attrs) {
+ attr = attrs[attribute].split('=');
+ if(attr.length == 1) {
+ attributes[attr[0]] = attr[0];
+ } else {
+ attributes[attr[0]] = attr[1];
+ }
+ }
+ attributes.cssclass = attributes.class;
+ url = matches[3];
+ imgEl = jQuery('
').attr({
+ 'src': attributes.thumbnail,
+ 'width': attributes.width,
+ 'height': attributes.height,
+ 'class': attributes.cssclass,
+ 'data-url': url,
+ }).addClass('ss-htmleditorfield-file embed');
+
+ jQuery.each(attributes, function (key, value) {
+ imgEl.attr('data-' + key, value);
+ });
+
+ content = content.replace(matches[0], prefix + (jQuery('').append(imgEl).html()) + suffix);
+ }
+ o.content = content;
+ });
}
});
diff --git a/thirdparty/tinymce_ssbuttons/langs/de.js b/thirdparty/tinymce_ssbuttons/langs/de.js
index 0948d6ff2..f0579dba6 100644
--- a/thirdparty/tinymce_ssbuttons/langs/de.js
+++ b/thirdparty/tinymce_ssbuttons/langs/de.js
@@ -1,5 +1,5 @@
tinyMCE.addI18n('de.tinymce_ssbuttons',{
insertlink: 'Link einfügen',
-insertimage: 'Bild einfügen',
+insertmedia: 'Bild einfügen',
insertflash: 'Flash Objekt einfügen'
-});
\ No newline at end of file
+});
diff --git a/thirdparty/tinymce_ssbuttons/langs/en.js b/thirdparty/tinymce_ssbuttons/langs/en.js
index 91ed8fb0d..c3deae81b 100644
--- a/thirdparty/tinymce_ssbuttons/langs/en.js
+++ b/thirdparty/tinymce_ssbuttons/langs/en.js
@@ -1,5 +1,5 @@
tinyMCE.addI18n('en.tinymce_ssbuttons', {
insertlink: 'Insert Link',
-insertimage: 'Insert Image',
+insertmedia: 'Insert Media',
insertflash: 'Insert Flash Object'
-});
\ No newline at end of file
+});