Skip to content

Commit

Permalink
More improvements to image handling in HTML compose editor
Browse files Browse the repository at this point in the history
- Send discrete data to browser instead of HTML IMG tag
- Support pasting and image uploading along with drag/drop
- Ensure that we are only allowed to drop images in HTML window.
  • Loading branch information
slusarz committed Dec 10, 2013
1 parent 9b5538b commit 4fd14f6
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 46 deletions.
62 changes: 35 additions & 27 deletions imp/js/ckeditor/pasteattachment.js
Expand Up @@ -18,36 +18,47 @@ CKEDITOR.plugins.add('pasteattachment', {
if (r.success) {
iframe = editor.getThemeSpace('contents').$.down('IFRAME');
Prototype.Selector.select('[dropatc_id=' + r.file_id + ']', iframe.contentDocument || iframe.contentWindow.document).each(function(elt) {
var img = new Element('span').insert(r.img).down();
var img = new Element('IMG');
img.onload = function() {
elt.parentNode.replaceChild(img, elt);
};
img.writeAttribute('src', r.img.src);
img.writeAttribute(r.img.related[0], r.img.related[1]);
if (r.img.height) {
img.writeAttribute('height', r.img.height);
img.writeAttribute('width', r.img.width);
}
});
}
};

editor.on('contentDom', function(e1) {
e1.editor.document.on('drop', function(e2) {
var f = DimpCompose.uploadAttachmentAjax(
e2.data.$.dataTransfer.files,
{ img_tag: 1 },
attachCallback
);

f.each(function(file) {
var fr = new FileReader();
fr.onload = function(e3) {
var elt = new CKEDITOR.dom.element('img');
elt.setAttributes({
dropatc_id: file.key,
src: e3.target.result
});
e1.editor.insertElement(elt);
};
fr.readAsDataURL(file.value);
});
function uploadAtc(files)
{
DimpCompose.uploadAttachmentAjax(
files,
{ img_data: 1 },
attachCallback
).each(function(file) {
var fr = new FileReader();
fr.onload = function(e) {
var elt = new CKEDITOR.dom.element('img');
elt.setAttributes({
dropatc_id: file.key,
src: e.target.result
});
editor.insertElement(elt);
};
fr.readAsDataURL(file.value);
});
};

e2.data.preventDefault();
editor.on('contentDom', function(e1) {
editor.document.on('drop', function(e2) {
/* Only support images for now. */
if (e2.data.$.dataTransfer.files[0].type.startsWith('image/')) {
uploadAtc(e2.data.$.dataTransfer.files);
e2.data.preventDefault();
}
});
});

Expand All @@ -57,6 +68,7 @@ CKEDITOR.plugins.add('pasteattachment', {
a = [],
span = new Element('SPAN').insert(ev.data.html).down();

/* Only support images for now. */
if (span && span.match('IMG')) {
data = span.readAttribute('src').split(',', 2);
data[1] = atob(data[1]);
Expand All @@ -66,11 +78,7 @@ CKEDITOR.plugins.add('pasteattachment', {
a[i] = data[1].charCodeAt(i);
}

DimpCompose.uploadAttachmentAjax(
[ new Blob([ new Uint8Array(a) ], { type: data[0].split(':')[1].split(';')[0] }) ],
{ img_tag: 1 },
attachCallback
);
uploadAtc([ new Blob([ new Uint8Array(a) ], { type: data[0].split(':')[1].split(';')[0] }) ]);

ev.data.html = '';
} else {
Expand Down
35 changes: 16 additions & 19 deletions imp/lib/Ajax/Application/Handler/ComposeAttach.php
Expand Up @@ -28,15 +28,15 @@ class IMP_Ajax_Application_Handler_ComposeAttach extends Horde_Core_Ajax_Applica
* Variables used:
* - composeCache: (string) The IMP_Compose cache identifier.
* - file_id: (integer) Browser ID of file.
* - img_tag: (boolean) If true, return related image tag.
* - img_data: (boolean) If true, return image data.
* - json_return: (boolean) If true, returns JSON. Otherwise, JSON-HTML.
*
* @return object False on failure, or an object with the following
* properties:
* - action: (string) The action.
* - file_id: (integer) Browser ID of file.
* - img: (string) The image tag to replace the data with, if 'img_tag'
* is set.
* - img: (object) Image data, if 'img_data' is set. Properties:
* height, related, src, width
* - success: (integer) 1 on success (at least one successful attached
* file), 0 on failure.
*/
Expand Down Expand Up @@ -68,28 +68,25 @@ public function addAttachment()

/* This currently only occurs when
* pasting/dropping image into HTML editor. */
if ($this->vars->img_tag) {
$dom_doc = new DOMDocument();
$img = $dom_doc->createElement('img');
$img->setAttribute('src', strval($val->viewUrl()->setRaw(true)));
$imp_compose->addRelatedAttachment($val, $img, 'src');
if ($this->vars->img_data) {
$result->img = new stdClass;
$result->img->src = strval($val->viewUrl()->setRaw(true));

$temp1 = new DOMDocument();
$temp2 = $temp1->createElement('span');
$imp_compose->addRelatedAttachment($val, $temp2, 'src');
$result->img->related = array(
$imp_compose::RELATED_ATTR,
$temp2->getAttribute($imp_compose::RELATED_ATTR)
);

try {
$img_ob = $injector->getInstance('Horde_Core_Factory_Image')->create();
$img_ob->loadString($val->storage->read()->getString(0));
$d = $img_ob->getDimensions();
$img->setAttribute('height', $d['height']);
$img->setAttribute('width', $d['width']);
$result->img->height = $d['height'];
$result->img->width = $d['width'];
} catch (Exception $e) {}

/* Complicated to grab single element from a
* DOMDocument object, so build tag
* ourselves. */
$img_tag = '<img';
foreach ($img->attributes as $node) {
$img_tag .= ' ' . $node->name . '="' . htmlspecialchars($node->value) . '"';
}
$result->img = $img_tag . '/>';
} else {
$this->_base->queue->attachment($val);
$notification->push(sprintf(_("Added \"%s\" as an attachment."), $val->getPart()->getName()), 'horde.success');
Expand Down

0 comments on commit 4fd14f6

Please sign in to comment.