stream image link inserting

This commit is contained in:
yuri
2018-09-26 16:12:03 +03:00
parent 673c18a5ce
commit 7b65cba5e4
5 changed files with 227 additions and 25 deletions

View File

@@ -41,4 +41,18 @@ class Attachment extends \Espo\Core\Controllers\Record
}
return parent::actionList($params, $data, $request);
}
public function postActionGetAttachmentFromImageUrl($params, $data)
{
if (empty($data->url)) throw new BadRequest();
return $this->getRecordService()->getAttachmentFromImageUrl($data->url)->getValueMap();
}
public function postActionGetCopiedAttachment($params, $data)
{
if (empty($data->id)) throw new BadRequest();
return $this->getRecordService()->getCopiedAttachment($data->id)->getValueMap();
}
}

View File

@@ -34,6 +34,7 @@ use \Espo\ORM\Entity;
use \Espo\Core\Exceptions\BadRequest;
use \Espo\Core\Exceptions\Forbidden;
use \Espo\Core\Exceptions\Error;
use \Espo\Core\Exceptions\NotFound;
class Attachment extends Record
{
@@ -166,5 +167,111 @@ class Attachment extends Record
$entity->clear('storage');
}
}
}
public function getCopiedAttachment($id)
{
$attachment = $this->getEntity($id);
if (!$attachment) throw new NotFound();
$copied = $this->getRepository()->getCopiedAttachment($attachment);
return $copied;
}
public function getAttachmentFromImageUrl($url)
{
$attachment = $this->getEntity();
$data = $this->getImageDataByUrl($url);
if (!$data) throw new Error('Attachment::getAttachmentFromImageUrl: Bad image data.');
$type = $data['type'];
$contents = $data['contents'];
$attachment->set([
'name' => $url,
'type' => $type,
'contents' => $contents,
'role' => 'Attachment'
]);
$this->getRepository()->save($attachment);
$attachment->clear('contents');
return $attachment;
}
protected function getImageDataByUrl($url)
{
$type = null;
if (function_exists('curl_init')) {
$opts = [];
$httpHeaders = [];
$httpHeaders[] = 'Expect:';
$opts[\CURLOPT_URL] = $url;
$opts[\CURLOPT_HTTPHEADER] = $httpHeaders;
$opts[\CURLOPT_CONNECTTIMEOUT] = 10;
$opts[\CURLOPT_TIMEOUT] = 10;
$opts[\CURLOPT_HEADER] = true;
$opts[\CURLOPT_BINARYTRANSFER] = true;
$opts[\CURLOPT_VERBOSE] = true;
$opts[\CURLOPT_SSL_VERIFYPEER] = false;
$opts[\CURLOPT_SSL_VERIFYHOST] = 2;
$opts[\CURLOPT_RETURNTRANSFER] = true;
$opts[\CURLOPT_FOLLOWLOCATION] = true;
$opts[\CURLOPT_MAXREDIRS] = 2;
$opts[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V4;
$ch = curl_init();
curl_setopt_array($ch, $opts);
$response = curl_exec($ch);
$headerSize = curl_getinfo($ch, \CURLINFO_HEADER_SIZE);
$header = substr($response, 0, $headerSize);
$body = substr($response, $headerSize);
$headLineList = explode("\n", $header);
foreach ($headLineList as $i => $line) {
if ($i === 0) continue;
if (strpos(strtolower($line), strtolower('Content-Type:')) === 0) {
$part = trim(substr($line, 13));
if ($part) {
$type = trim(explode(";", $part)[0]);
}
}
}
if (!$type) {
$extTypeMap = [
'png' => 'image/png',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif'
];
$extension = preg_replace('#\?.*#', '', pathinfo($url, \PATHINFO_EXTENSION));
if (isset($extTypeMap[$extension])) {
$type = $extTypeMap[$extension];
}
}
if (!$type) return;
if (!in_array($type, ['image/png', 'image/jpeg', 'image/gif'])) {
return;
}
return [
'type' => $type,
'contents' => $body
];
curl_close($ch);
}
return null;
}
}

View File

@@ -1,5 +1,5 @@
<div class="form-group post-container{{#if postDisabled}} hidden{{/if}}">
<textarea class="note form-control" rows="1" cols="10" placeholder="{{placeholderText}}"></textarea>
<div class="textarea-container">{{{postField}}}</div>
<div class="buttons-panel margin hide floated-row clearfix">
<div>
<button class="btn btn-primary post">{{translate 'Post'}}</button>

View File

@@ -38,10 +38,20 @@ Espo.define('views/note/fields/post', ['views/fields/text', 'lib!Textcomplete'],
'input textarea': function (e) {
this.controlTextareaHeight();
},
'paste textarea': function (e) {
if (!e.originalEvent.clipboardData) return;
var text = e.originalEvent.clipboardData.getData('text/plain');
if (!text) return;
text = text.trim();
if (!text) return;
this.handlePastedText(text);
}
}, Dep.prototype.events),
setup: function () {
Dep.prototype.setup.call(this);
this.insertedImagesData = {};
},
controlTextareaHeight: function (lastHeight) {
@@ -62,7 +72,8 @@ Espo.define('views/note/fields/post', ['views/fields/text', 'lib!Textcomplete'],
afterRender: function () {
Dep.prototype.afterRender.call(this);
this.$element.attr('placeholder', this.translate('writeMessage', 'messages', 'Note'));
var placeholderText = this.options.placeholderText || this.translate('writeMessage', 'messages', 'Note');
this.$element.attr('placeholder', placeholderText);
this.$textarea = this.$element;
var $textarea = this.$textarea;
@@ -143,6 +154,81 @@ Espo.define('views/note/fields/post', ['views/fields/text', 'lib!Textcomplete'],
return Dep.prototype.validateRequired.call(this);
},
handlePastedText: function (text) {
if (/^http(s){0,1}\:\/\//.test(text)) {
var imageExtensionList = ['jpg', 'jpeg', 'png', 'gif'];
var regExpString = '.+\\.(' + imageExtensionList.join('|') + ')(/?.*){0,1}$';
var regExp = new RegExp(regExpString, 'i');
var url = text;
var siteUrl = this.getConfig().get('siteUrl').replace(/\/$/, '');
var attachmentIdList = this.model.get('attachmentsIds') || [];
if (regExp.test(text)) {
var insertedId = this.insertedImagesData[url];
if (insertedId) {
if (~attachmentIdList.indexOf(insertedId)) return;
}
this.ajaxPostRequest('Attachment/action/getAttachmentFromImageUrl', {
url: url
}).then(function (attachment) {
var attachmentIdList = Espo.Utils.clone(this.model.get('attachmentsIds') || []);
var attachmentNames = Espo.Utils.clone(this.model.get('attachmentsNames') || {});
var attachmentTypes = Espo.Utils.clone(this.model.get('attachmentsTypes') || {});
attachmentIdList.push(attachment.id);
attachmentNames[attachment.id] = attachment.name;
attachmentTypes[attachment.id] = attachment.type;
this.insertedImagesData[url] = attachment.id;
this.model.set({
attachmentsIds: attachmentIdList,
attachmentsNames: attachmentNames,
attachmentsTypes: attachmentTypes
});
}.bind(this)).fail(function (xhr) {
xhr.errorIsHandled = true;
});
} else if (/\?entryPoint\=image\&/.test(text) && text.indexOf(siteUrl) === 0) {
url = text.replace(/[\&]{0,1}size\=[a-z\-]*/, '');
var match = /\&{0,1}id\=([a-z0-9A-Z]*)/g.exec(text)
if (match.length === 2) {
var id = match[1];
if (~attachmentIdList.indexOf(id)) return;
var insertedId = this.insertedImagesData[id];
if (insertedId) {
if (~attachmentIdList.indexOf(insertedId)) return;
}
this.ajaxPostRequest('Attachment/action/getCopiedAttachment', {
id: id
}).then(function (attachment) {
var attachmentIdList = Espo.Utils.clone(this.model.get('attachmentsIds') || []);
var attachmentNames = Espo.Utils.clone(this.model.get('attachmentsNames') || {});
var attachmentTypes = Espo.Utils.clone(this.model.get('attachmentsTypes') || {});
attachmentIdList.push(attachment.id);
attachmentNames[attachment.id] = attachment.name;
attachmentTypes[attachment.id] = attachment.type;
this.insertedImagesData[id] = attachment.id;
this.model.set({
attachmentsIds: attachmentIdList,
attachmentsNames: attachmentNames,
attachmentsTypes: attachmentTypes
});
}.bind(this)).fail(function (xhr) {
xhr.errorIsHandled = true;
});
}
}
}
}
});

View File

@@ -37,7 +37,7 @@ Espo.define('views/stream/panel', ['views/record/panels/relationship', 'lib!Text
postDisabled: false,
events: _.extend({
'focus textarea.note': function (e) {
'focus textarea[name="post"]': function (e) {
this.enablePostingMode();
},
'click button.post': function () {
@@ -55,7 +55,7 @@ Espo.define('views/stream/panel', ['views/record/panels/relationship', 'lib!Text
}
},
'keypress textarea.note': function (e) {
'keypress textarea[name="post"]': function (e) {
if ((e.keyCode == 10 || e.keyCode == 13) && e.ctrlKey) {
this.post();
} else if (e.keyCode == 9) {
@@ -64,10 +64,7 @@ Espo.define('views/stream/panel', ['views/record/panels/relationship', 'lib!Text
this.disablePostingMode();
}
}
},
'input textarea.note': function (e) {
this.controlTextareaHeight();
},
}
}, Dep.prototype.events),
data: function () {
@@ -78,26 +75,12 @@ Espo.define('views/stream/panel', ['views/record/panels/relationship', 'lib!Text
return data;
},
controlTextareaHeight: function (lastHeight) {
var scrollHeight = this.$textarea.prop('scrollHeight');
var clientHeight = this.$textarea.prop('clientHeight');
if (clientHeight === lastHeight) return;
if (scrollHeight > clientHeight + 1) {
this.$textarea.attr('rows', this.$textarea.prop('rows') + 1);
this.controlTextareaHeight(clientHeight);
}
if (this.$textarea.val().length === 0) {
this.$textarea.attr('rows', 1);
}
},
enablePostingMode: function () {
this.$el.find('.buttons-panel').removeClass('hide');
if (!this.postingMode) {
if (this.$textarea.val() && this.$textarea.val().length) {
this.controlTextareaHeight();
this.getView('postField').controlTextareaHeight();
}
$('body').on('click.stream-panel', function (e) {
var $target = $(e.target);
@@ -169,6 +152,18 @@ Espo.define('views/stream/panel', ['views/record/panels/relationship', 'lib!Text
attachmentsNames: storedAttachments.names
});
}
this.createView('postField', 'views/note/fields/post', {
el: this.getSelector() + ' .textarea-container',
name: 'post',
mode: 'edit',
params: {
required: true,
rows: 1
},
model: this.seed,
placeholderText: this.placeholderText
});
this.createCollection(function () {
this.wait(false);
}, this);
@@ -213,7 +208,7 @@ Espo.define('views/stream/panel', ['views/record/panels/relationship', 'lib!Text
},
afterRender: function () {
this.$textarea = this.$el.find('textarea.note');
this.$textarea = this.$el.find('textarea[name="post"]');
this.$attachments = this.$el.find('div.attachments');
this.$postContainer = this.$el.find('.post-container');