diff --git a/mod/item.php b/mod/item.php index 7cb2849a89..40c01da20f 100644 --- a/mod/item.php +++ b/mod/item.php @@ -40,6 +40,8 @@ use Friendica\Util\Emailer; use Friendica\Util\Security; use Friendica\Util\Strings; +require_once 'include/items.php'; + function item_post(App $a) { if (!local_user() && !remote_user()) { return 0; @@ -188,6 +190,40 @@ function item_post(App $a) { $categories = ''; $postopts = ''; $emailcc = ''; + $body = defaults($_REQUEST, 'body', ''); + $has_attachment = defaults($_REQUEST, 'has_attachment', 0); + + // If we have a speparate attachment, we need to add it to the body. + if (!empty($has_attachment)) { + $attachment_type = defaults($_REQUEST, 'attachment_type', ''); + $attachment_title = defaults($_REQUEST, 'attachment_title', ''); + $attachment_text = defaults($_REQUEST, 'attachment_text', ''); + + $attachment_url = hex2bin(defaults($_REQUEST, 'attachment_url', '')); + $attachment_img_src = hex2bin(defaults($_REQUEST, 'attachment_img_src', '')); + + $attachment_img_width = defaults($_REQUEST, 'attachment_img_width', 0); + $attachment_img_height = defaults($_REQUEST, 'attachment_img_height', 0); + $attachment = [ + 'type' => $attachment_type, + 'title' => $attachment_title, + 'text' => $attachment_text, + 'url' => $attachment_url, + ]; + + if (!empty($attachment_img_src)) { + $attachment['images'] = [ + 0 => [ + 'src' => $attachment_img_src, + 'width' => $attachment_img_width, + 'height' => $attachment_img_height + ] + ]; + } + + $att_bbcode = add_page_info_data($attachment); + $body .= $att_bbcode; + } if (!empty($orig_post)) { $str_group_allow = $orig_post['allow_gid']; @@ -201,7 +237,7 @@ function item_post(App $a) { $app = $orig_post['app']; $categories = $orig_post['file']; $title = Strings::escapeTags(trim($_REQUEST['title'])); - $body = Strings::escapeHtml(trim($_REQUEST['body'])); + $body = Strings::escapeHtml(trim($body)); $private = $orig_post['private']; $pubmail_enabled = $orig_post['pubmail']; $network = $orig_post['network']; @@ -237,7 +273,7 @@ function item_post(App $a) { $coord = Strings::escapeTags(trim(defaults($_REQUEST, 'coord' , ''))); $verb = Strings::escapeTags(trim(defaults($_REQUEST, 'verb' , ''))); $emailcc = Strings::escapeTags(trim(defaults($_REQUEST, 'emailcc' , ''))); - $body = Strings::escapeHtml(trim(defaults($_REQUEST, 'body' , ''))); + $body = Strings::escapeHtml(trim($body)); $network = Strings::escapeTags(trim(defaults($_REQUEST, 'network' , Protocol::DFRN))); $guid = System::createUUID(); diff --git a/mod/parse_url.php b/mod/parse_url.php index b982ccf084..3b2522ab12 100644 --- a/mod/parse_url.php +++ b/mod/parse_url.php @@ -12,6 +12,7 @@ use Friendica\App; use Friendica\Core\Hook; use Friendica\Core\Logger; +use Friendica\Core\System; use Friendica\Util\Network; use Friendica\Util\ParseUrl; @@ -19,6 +20,8 @@ function parse_url_content(App $a) { $text = null; $str_tags = ''; + $format = ''; + $ret= ['success' => false, 'contentType' => '']; $br = "\n"; @@ -43,6 +46,10 @@ function parse_url_content(App $a) } } + if (isset($_GET['format']) && $_GET['format'] == 'json') { + $format = 'json'; + } + // Add url scheme if it is missing $arrurl = parse_url($url); if (empty($arrurl['scheme'])) { @@ -73,23 +80,36 @@ function parse_url_content(App $a) } } $type = null; + $content_type = ''; + $bbcode = ''; if (array_key_exists('Content-Type', $hdrs)) { $type = $hdrs['Content-Type']; } if ($type) { if (stripos($type, 'image/') !== false) { - echo $br . '[img]' . $url . '[/img]' . $br; - exit(); + $content_type = 'image'; + $bbcode = $br . '[img]' . $url . '[/img]' . $br; } if (stripos($type, 'video/') !== false) { - echo $br . '[video]' . $url . '[/video]' . $br; - exit(); + $content_type = 'video'; + $bbcode = $br . '[video]' . $url . '[/video]' . $br; } if (stripos($type, 'audio/') !== false) { - echo $br . '[audio]' . $url . '[/audio]' . $br; - exit(); + $content_type = 'audio'; + $bbcode = $br . '[audio]' . $url . '[/audio]' . $br; } } + if (!empty($content_type)) { + if ($format == 'json') { + $ret['contentType'] = $content_type; + $ret['data'] = ['url' => $url]; + $ret['success'] = true; + System::jsonExit($ret); + } + + echo $bbcode; + exit(); + } } @@ -130,6 +150,14 @@ function parse_url_content(App $a) exit(); } + if ($format == 'json') { + $ret['data'] = $siteinfo; + $ret['contentType'] = 'attachment'; + $ret['success'] = true; + + System::jsonExit($ret); + } + // Format it as BBCode attachment $info = add_page_info_data($siteinfo); diff --git a/view/js/linkPreview.js b/view/js/linkPreview.js new file mode 100644 index 0000000000..ae2f0af5ab --- /dev/null +++ b/view/js/linkPreview.js @@ -0,0 +1,877 @@ +/** + * Copyright (c) 2014 Leonardo Cardoso (http://leocardz.com) + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * Restructured by Rabzuarus (https://friendica.kommune4.de/profile/rabuzarus) + * to use it in the decentralized social network Friendica (https://friendi.ca). + * + * Version: 1.4.0 + */ +(function ($) { + $.fn.linkPreview = function (options) { + var opts = jQuery.extend({}, $.fn.linkPreview.defaults, options); + + var selector = $(this).selector; + selector = selector.substr(1); + + var previewTpl = '\ +
\ + {1}\ + \ + \ + \ +
'; + + var attachmentTpl = '\ +
\ +
\ + \ +
\ +
\ +
\ + \ +
\ +
\ +
\ + \ + \ + \ + \ +
\ +
\ +

\ +
\ +
\ + \ +
\ +
\ +
'; + var text; + var urlRegex = /(https?\:\/\/|\s)[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})(\/+[a-z0-9_.\:\;-]*)*(\?[\&\%\|\+a-z0-9_=,\.\:\;-]*)?([\&\%\|\+&a-z0-9_=,\:\;\.-]*)([\!\#\/\&\%\|\+a-z0-9_=,\:\;\.-]*)}*/i; + var binurl; + var block = false; + var blockTitle = false; + var blockDescription = false; + var cache = {}; + var images = ""; + var isExtern = false; + var photoNumber = 0; + var firstPosted = false; + var isActive = false; + var isCrawling = false; + var defaultTitle = opts.defaultTitle; + var defaultDescription = opts.defaultDescription; + + /** + * Initialize the plugin + * + * @returns {void} + */ + var init = function() { + $('#' + selector).bind({ + paste: function () { + setTimeout(function () { + crawlText(); + }, 100); + }, + keyup: function (e) { + // on enter, space, ctrl + if ((e.which === 13 || e.which === 32 || e.which === 17)) { + crawlText(); + } + } + }); + + // Check if we have already attachment bbcode in the textarea + // and add it to the attachment preview. + var content = $('#' + selector).val(); + addBBCodeToPreview(content); + }; + + /** + * Reset some values. + * + * @returns {void} + */ + var resetPreview = function() { + $('#hasAttachment_' + selector).val(0); + photoNumber = 0; + images = ""; + }; + + /** + * Crawl a text string if it contains an url and try + * to attach it. + * + * If no text is passed to crawlText() we take + * the previous word before the cursor of the textarea. + * + * @param {string} text (optional) + * @returns {void} + */ + var crawlText = function (text) { + block = false; + images = ''; + isExtern = false; + + // If no text is passed to crawlText() we + // take the previous word before the cursor. + if (typeof text === 'undefined') { + text = getPrevWord(selector); + } else { + isExtern = true; + } + + // Don't procces the textarea input if we have already + // an attachment preview. + if (!isExtern && isActive) { + return; + } + + if (trim(text) !== "") { + if (block === false && urlRegex.test(text)) { + binurl = bin2hex(text); + block = true; + + isCrawling = true; + $('#profile-rotator').show(); + + if (binurl in cache) { + isCrawling = false; + processContentData(cache[binurl]); + } else { + getContentData(binurl, processContentData); + } + } + } + }; + + /** + * Process the attachment data according to + * its content type (image, audio, video, attachment) + * + * @param {object} result + * @returns {void} + */ + var processContentData = function(result) { + if (result.contentType === 'image') { + insertImage(result.data); + } + if (result.contentType === 'audio') { + insertAudio(result.data); + } + if (result.contentType === 'video') { + insertVideo(result.data); + } + if (result.contentType === 'attachment') { + insertAttachment(result.data); + } + $('#profile-rotator').hide(); + }; + + /** + * Fetch the content of link which should be attached. + * + * @param {string} binurl Link which should be attached as hexadecimal string. + * @param {type} callback + * @returns {void} + */ + var getContentData = function(binurl, callback) { + $.get('parse_url?binurl='+ binurl + '&format=json', function (answer) { + obj = sanitizeInputData(answer); + + // Put the data into a cache + cache[binurl] = obj; + + callback(obj); + + isCrawling = false; + }); + }; + + /* + * Add a [img] bbtag with the image url to the jot editor. + * + * @param {type} data + * @returns {void} + */ + var insertImage = function(data) { + if (!isExtern) { + return; + } + var bbcode = '\n[img]' + data.url + '[/img]\n'; + addeditortext(bbcode); + }; + + /* + * Add a [audio] bbtag with the audio url to the jot editor. + * + * @param {type} data + * @returns {void} + */ + var insertAudio = function(data) { + if (!isExtern) { + return; + } + var bbcode = '\n[audio]' + data.url + '[/audio]\n'; + addeditortext(bbcode); + }; + + /* + * Add a [video] bbtag with the video url to the jot editor. + * + * @param {type} data + * @returns {void} + */ + var insertVideo = function(data) { + if (!isExtern) { + return; + } + var bbcode = '\n[video]' + json.url + '[/video]\n'; + addeditortext(bbcode); + }; + + /** + * Proccess all attachment data and show up a html + * attachment preview. + * + * @param {obj} data Attachment data. + * @returns {void} + */ + var insertAttachment = function(data) { + // If we have already a preview, leaver here. + // Note: if we finish the Preview of other media content type, + // we can move this condition to the beggining of crawlText(); + if (isActive) { + $('#profile-rotator').hide(); + return; + } + + if (data.type !== 'link' && data.type !== 'video' && data.type !== 'photo' || data.url === data.title) { + $('#profile-rotator').hide(); + return; + } + + $('#photoNumber_' + selector).val(0); + resetPreview(); + + processAttachmentTpl(data, 'type-' + data.type); + addTitleDescription(data); + addHostToAttachment(data.url); + addImagesToAttachment(data.images); + + processEventListener(); + $('#profile-rotator').hide(); + }; + + /** + * Construct the attachment html from the attachment template and + * add it to the DOM. + * + * @param {object} data Attachment data. + * @returns {void} + */ + var processAttachmentTpl = function(data) { + // Load and add the template if it isn't allready loaded. + if ($('#preview_' + selector).length === 0) { + var tpl = previewTpl.format( + 'type-' + data.type, + attachmentTpl, + 1, + bin2hex(data.url), + data.type + ); + $('#' + selector).after(tpl); + } + + isActive = true; + }; + + /** + * Add the attachment title and the description + * to the attachment preview. + * + * @param {object} data Attachment data. + * @returns {void} + */ + var addTitleDescription = function(data) { + var description = data.text; + + if (description === '') { + description = defaultDescription; + } + + $('#previewTitle_' + selector).html("\ + " + escapeHTML(data.title) + "\ + " + ); + + $('#previewDescription_' + selector).html("\ + " + escapeHTML(description) + "\n\ + " + ); + }; + + /** + * Add the host to the attachment preview. + * + * @param {string} url The url of the link attachment. + * @returns {void} + */ + var addHostToAttachment = function(url) { + if (url) { + var regexpr = "(https?://)([^:^/]*)(:\\d*)?(.*)?"; + var regResult = url.match(regexpr); + var urlHost = regResult[1] + regResult[2]; + $('#previewUrl_' + selector).html("" + urlHost + ""); + } + }; + + /** + * Add preview images to the attachment. + * + * @param {array} images + * + * @returns {void} + */ + var addImagesToAttachment = function(images) { + var imageClass = 'attachment-preview'; + + if (Array.isArray(images)) { + $('#previewImages_' + selector).show(); + $('#attachmentImageSrc_' + selector).val(bin2hex(images[photoNumber].src)); + $('#attachmentImageWidth_' + selector).val(images[photoNumber].width); + $('#attachmentImageHeight_' + selector).val(images[photoNumber].height); + } else { + $('#previewImages_' + selector).hide(); + } + + images.length = parseInt(images.length); + var appendImage = ""; + + for (i = 0; i < images.length; i++) { + // For small preview images we use a smaller attachment format. + ///@todo here we need to add a check for !Config::get('system', 'always_show_preview'). + if (images[i].width >= 500 && images[i].width >= images[i].height) { + imageClass = 'attachment-image'; + } + + if (i === 0) { + appendImage += ""; + } else { + appendImage += ""; + } + } + + $('#previewImage_' + selector).html(appendImage + ""); + + // More than just one image. + if (images.length > 1) { + // Enable the the button to change the preview pictures. + $('#previewChangeImg_' + selector).show(); + + if (firstPosted === false) { + firstPosted = true; + + $('#previewChangeImg_' + selector).unbind('click').click(function (e) { + e.stopPropagation(); + if (images.length > 1) { + $('#imagePreview_' + selector + '_' + photoNumber).css({ + 'display': 'none' + }); + photoNumber += 1; + + // If have reached the last image, begin with the first image. + if (photoNumber === images.length) { + photoNumber = 0; + } + + $('#imagePreview_' + selector + '_' + photoNumber).css({ + 'display': 'block' + }); + $('#photoNumber_' + selector).val(photoNumber); + $('#attachmentImageSrc_' + selector).val(bin2hex(images[photoNumber].src)); + $('#attachmentImageWidth_' + selector).val(images[photoNumber].width); + $('#attachmentImageHeight_' + selector).val(images[photoNumber].height); + } + }); + } + } + }; + + /** + * Add event listener to control the attachment preview. + * + * @returns {void} + */ + var processEventListener = function() { + $('#previewSpanTitle_' + selector).unbind('click').click(function (e) { + e.stopPropagation(); + if (blockTitle === false) { + blockTitle = true; + $('#previewSpanTitle_' + selector).hide(); + $('#previewInputTitle_' + selector).show(); + $('#previewInputTitle_' + selector).val($('#previewInputTitle_' + selector).val()); + $('#previewInputTitle_' + selector).focus().select(); + } + }); + + $('#previewInputTitle_' + selector).blur(function () { + blockTitle = false; + $('#previewSpanTitle_' + selector).html($('#previewInputTitle_' + selector).val()); + $('#previewSpanTitle_' + selector).show(); + $('#previewInputTitle_' + selector).hide(); + }); + + $('#previewInputTitle_' + selector).keypress(function (e) { + if (e.which === 13) { + blockTitle = false; + $('#previewSpanTitle_' + selector).html($('#previewInputTitle_' + selector).val()); + $('#previewSpanTitle_' + selector).show(); + $('#previewInputTitle_' + selector).hide(); + } + }); + + $('#previewSpanDescription_' + selector).unbind('click').click(function (e) { + e.stopPropagation(); + if (blockDescription === false) { + blockDescription = true; + $('#previewSpanDescription_' + selector).hide(); + $('#previewInputDescription_' + selector).show(); + $('#previewInputDescription_' + selector).val($('#previewInputDescription_' + selector).val()); + $('#previewInputDescription_' + selector).focus().select(); + } + }); + + $('#previewInputDescription_' + selector).blur(function () { + blockDescription = false; + $('#previewSpanDescription_' + selector).html($('#previewInputDescription_' + selector).val()); + $('#previewSpanDescription_' + selector).show(); + $('#previewInputDescription_' + selector).hide(); + }); + + $('#previewInputDescription_' + selector).keypress(function (e) { + if (e.which === 13) { + blockDescription = false; + $('#previewSpanDescription_' + selector).html($('#previewInputDescription_' + selector).val()); + $('#previewSpanDescription_' + selector).show(); + $('#previewInputDescription_' + selector).hide(); + } + }); + + $('#previewSpanTitle_' + selector).mouseover(function () { + $('#previewSpanTitle_' + selector).css({ + "background-color": "#ff9" + }); + }); + + $('#previewSpanTitle_' + selector).mouseout(function () { + $('#previewSpanTitle_' + selector).css({ + "background-color": "transparent" + }); + }); + + $('#previewSpanDescription_' + selector).mouseover(function () { + $('#previewSpanDescription_' + selector).css({ + "background-color": "#ff9" + }); + }); + + $('#previewSpanDescription_' + selector).mouseout(function () { + $('#previewSpanDescription_' + selector).css({ + "background-color": "transparent" + }); + }); + + $('#closePreview_' + selector).unbind('click').click(function (e) { + e.stopPropagation(); + block = false; + images = ''; + isActive = false; + firstPosted = false; + $('#preview_' + selector).fadeOut("fast", function () { + $('#preview_' + selector).remove(); + $('#profile-rotator').hide(); + $('#' + selector).focus(); + }); + + }); + }; + + /** + * Convert attachmant bbcode into an array. + * + * @param {string} content Text content with the attachment bbcode. + * @returns {object || null} + */ + var getAttachmentData = function(content) { + var data = {}; + + var match = content.match(/(.*)\[attachment(.*?)\](.*?)\[\/attachment\](.*)/ism); + if (match === null || match.length < 5) { + return null; + } + + var attributes = match[2]; + data.text = trim(match[1]); + + var type = ''; + var matches = attributes.match(/type='(.*?)'/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + type = matches[1].toLowerCase(); + } + + matches = attributes.match(/type="(.*?)"/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + type = matches[1].toLowerCase(); + } + + if (type === '') { + return null; + } + + if ( + type !== 'link' + && type !== 'audio' + && type !== 'photo' + && type !== 'video') + { + return null; + } + + if (type !== '') { + data.type = type; + } + + var url = ''; + + matches = attributes.match(/url='(.*?)'/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + url = matches[1].toLowerCase(); + } + + matches = attributes.match(/url="(.*?)"/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + url = matches[1].toLowerCase(); + } + + if(url !== '') { + data.url = escapeHTML(url); + } + + var title = ''; + + matches = attributes.match(/title='(.*?)'/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + title = matches[1].toLowerCase(); + } + + matches = attributes.match(/title="(.*?)"/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + title = matches[1].toLowerCase(); + } + + if (title !== '') { + data.title = escapeHTML(title); + } + + var image = ''; + + matches = attributes.match(/image='(.*?)'/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + image = matches[1].toLowerCase(); + } + + matches = attributes.match(/image="(.*?)"/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + image = matches[1].toLowerCase(); + } + + if (image !== '') { + data.image = escapeHTML(image); + } + + var preview = ''; + + matches = attributes.match(/preview='(.*?)'/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + preview = matches[1].toLowerCase(); + } + + matches = attributes.match(/preview="(.*?)"/ism); + if (matches !== null && typeof matches[1] !== 'undefined') { + preview = matches[1].toLowerCase(); + } + + if (preview !== '') { + data.preview = escapeHTML(preview); + } + + data.text = trim(match[3]); + data.after = trim(match[4]); + + return data; + }; + + /** + * Process txt content and if it contains attachment bbcode + * add it to the attachment preview . + * + * @param {string} content + * @returns {void} + */ + var addBBCodeToPreview =function(content) { + var attachmentData = getAttachmentData(content); + if (attachmentData) { + reAddAttachment(attachmentData); + // Remove the attachment bbcode from the textarea. + var content = content.replace(/\[attachment.*\[\/attachment]/ism, ''); + $('#' + selector).val(content); + $('#' + selector).focus(); + } + }; + + /** + * Add an Attachment with data from an old bbcode + * generated attachment. + * + * @param {object} json The attachment data. + * @returns {void} + */ + var reAddAttachment = function(json) { + if (isActive) { + $('#profile-rotator').hide(); + return; + } + + if (json.type !== 'link' && json.type !== 'video' && json.type !== 'photo' || json.url === json.title) { + $('#profile-rotator').hide(); + return; + } + + var obj = {data: json}; + obj = sanitizeInputData(obj); + + var data = obj.data; + + resetPreview(); + + processAttachmentTpl(data); + addTitleDescription(data); + addHostToAttachment(data.url); + + // Since we don't have an array of image data, + // we need to add the preview images in a different way + // than in function addImagesToAttachment(). + var imageClass = 'attachment-preview'; + var image = ''; + + if (data.image !== '') { + imageClass = 'attachment-image'; + image = data.image; + } else { + image = data.preview; + } + + if (image !== '') { + var appendImage = "" + $('#previewImage_' + selector).html(appendImage); + $('#attachmentImageSrc_' + selector).val(bin2hex(image)); + + // We need to add the image widht and height when it is + // loaded. + $('' ,{ + load : function(){ + $('#attachmentImageWidth_' + selector).val(this.width); + $('#attachmentImageHeight_' + selector).val(this.height); + }, + src : image + }); + } + + processEventListener(); + $('#profile-rotator').hide(); + }; + + /** + * Add missing default properties to the input data object. + * + * @param {object} obj Input data. + * @returns {object} + */ + var sanitizeInputData = function(obj) { + if (typeof obj.contentType === 'undefined' + || obj.contentType === null) + { + obj.contentType = ""; + } + if (typeof obj.data.url === 'undefined' + || obj.data.url === null) + { + obj.data.url = ""; + } + if (typeof obj.data.title === 'undefined' + || obj.data.title === null + || obj.data.title === "") + { + obj.data.title = defaultTitle; + } + if (typeof obj.data.text === 'undefined' + || obj.data.text === null + || obj.data.text === "") + { + obj.data.text = ""; + } + if (typeof obj.data.images === 'undefined' + || obj.data.images === null) + { + obj.data.images = ""; + } + + if (typeof obj.data.image === 'undefined' + || obj.data.image === null) + { + obj.data.image = ""; + } + + if (typeof obj.data.preview === 'undefined' + || obj.data.preview === null) + { + obj.data.preview = ""; + } + + return obj; + }; + + /** + * Destroy the plugin. + * + * @returns {void} + */ + var destroy = function() { + $('#' + selector).unbind(); + $('#preview_' + selector).remove(); + binurl; + block = false; + blockTitle = false; + blockDescription = false; + cache = {}; + images = ""; + isExtern = false; + photoNumber = 0; + firstPosted = false; + isActive = false; + isCrawling = false; + selector = ""; + }; + + var trim = function(str) { + return str.replace(/^\s+|\s+$/g, ""); + }; + var escapeHTML = function(unsafe_str) { + return unsafe_str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/\"/g, '"') + .replace(/\[/g, '[') + .replace(/\]/g, ']') + .replace(/\'/g, '''); // ''' is not valid HTML 4 + }; + + // Initialize LinkPreview + init(); + + return { + // make crawlText() accessable from the outside. + crawlText: function(text) { + crawlText(text); + }, + addBBCodeToPreview: function(content) { + addBBCodeToPreview(content); + }, + destroy: function() { + destroy(); + } + }; + }; + + $.fn.linkPreview.defaults = { + defaultDescription: "Enter a description", + defaultTitle: "Enter a title" + }; + + /** + * Get in a textarea the previous word before the cursor. + * + * @param {object} text Textarea elemet. + * @param {integer} caretPos Cursor position. + * + * @returns {string} Previous word. + */ + function returnWord(text, caretPos) { + var index = text.indexOf(caretPos); + var preText = text.substring(0, caretPos); + // If the last charachter is a space or enter remove it + // We need this in friendica for the url preview. + var lastChar = preText.slice(-1) + if ( lastChar === " " + || lastChar === "\n" + || lastChar === "\r" + ) + { + preText = preText.substring(0, preText.length -1); + } + + // Replace new line with space. + preText = preText.replace(/\n/g, " "); + + if (preText.indexOf(" ") > 0) { + var words = preText.split(" "); + return words[words.length - 1]; //return last word + } + else { + return preText; + } + } + + /** + * Get in a textarea the previous word before the cursor. + * + * @param {string} id The ID of a textarea element. + * @returns {sting|null} Previous word or null if no word is available. + */ + function getPrevWord(id) { + var text = document.getElementById(id); + var caretPos = getCaretPosition(text); + var word = returnWord(text.value, caretPos); + if (word != null) { + return word + } + + } + + /** + * Get the cursor posiotion in an text element. + * + * @param {object} ctrl Textarea elemet. + * @returns {integer} Position of the cursor. + */ + function getCaretPosition(ctrl) { + var CaretPos = 0; // IE Support + if (document.selection) { + ctrl.focus(); + var Sel = document.selection.createRange(); + Sel.moveStart('character', -ctrl.value.length); + CaretPos = Sel.text.length; + } + // Firefox support + else if (ctrl.selectionStart || ctrl.selectionStart == '0') { + CaretPos = ctrl.selectionStart; + } + return (CaretPos); + } +})(jQuery); diff --git a/view/theme/frio/css/style.css b/view/theme/frio/css/style.css index d45d7c47a9..c2ad62d3c3 100644 --- a/view/theme/frio/css/style.css +++ b/view/theme/frio/css/style.css @@ -1326,6 +1326,29 @@ section #jotOpen { .jothidden { /*display: none;*/ } +.modal #jot-sections { + max-height: calc(100vh - 22px); +} +@media (min-width: 768px) { + .modal #jot-sections { + max-height: calc(100vh - 62px); + } +} +#jot-modal #jot-sections, +#jot-modal #jot-modal-body, +#jot-modal #profile-jot-form, +#jot-modal #profile-jot-wrapper, +#jot-modal #jot-text-wrap, +#jot-modal #jot-preview-content, +#jot-modal #tread-wrapper--1, +#jot-modal #item-Q0, +#jot-modal #profile-jot-acl-wrapper, +#jot-modal #acl-wrapper { + overflow: hidden; + display: flex; + flex: auto; + flex-direction: column; +} #jot-modal .modal-header a, #jot-modal .modal-header .btn-link, #profile-jot-submit-wrapper a, #profile-jot-submit-wrapper .btn-link { color: #555; @@ -1342,6 +1365,69 @@ section #jotOpen { } #jot-text-wrap textarea { min-height: 100px; + overflow-y: auto !important; + overflow-y: overlay !important; +} +/*#jot-attachment-preview { + display: none; +}*/ +#jot-text-wrap .preview textarea { + width: 100%; +} +#preview_profile-jot-text { + position: relative; + padding: 0px 10px; + margin-top: -2px; + border: 2px solid #ededed; + border-top: none; + box-shadow: none; + border-radius: 0 0 4px 4px; + background: #fff; + color: #555; +} +textarea#profile-jot-text:focus + #preview_profile-jot-text { + border: 2px solid #6fdbe8; + border-top: none; +} +.preview hr.previewseparator { + margin-top: 0px; + border-color: #D2D2D2; +} +#previewImgBtn_profile-jot-text, +.closePreview { + position: absolute; + top: 15px; +} +.closePreview { + right: 15px; + z-index: 1; +} +.previewImgBtn { + left: 15px; +} +.preview button.previewActionBtn { + display:block; + height: 25px; + width: 25px; + border-radius: 50%; + color: #fff; + border: 2px solid #fff; + box-shadow: 0 0 3px gray; + background: #777; + text-align: center; + line-height: 2px; + text-decoration: none; + padding: 0 0 1px 1px; + opacity: 0.7; +} +.preview button.previewActionBtn:hover { + opacity: 1; +} +.preview .closePreview button.previewActionBtn { + font-size: 25px; +} +#previewInputTitle_profile-jot-text { + width: 100%; } #profile-jot-wrapper button#profile-jot-submit { margin-top: 5px; @@ -1349,7 +1435,10 @@ section #jotOpen { #profile-jot-wrapper #character-counter { padding: 10px 15px; } - +.modal .wall-item-container.preview { + overflow-y: auto; + overflow-y: overlay; +} /* ACL */ /*#jot-modal-body { height: auto; @@ -1357,7 +1446,7 @@ section #jotOpen { overflow-y: hidden; }*/ #acl-search { - margin-top: 20px; + /*margin-top: 20px;*/ /*padding: 8px;*/ /*border: 1px solid #ccc;*/ width: 100%; @@ -1365,7 +1454,6 @@ section #jotOpen { #acl-list { display: block; border: 1px solid #ccc; - overflow: auto; clear: both; min-height: 62px; margin-top: 20px; @@ -1373,10 +1461,10 @@ section #jotOpen { -webkit-border-radius: 4px; -moz-border-radius: 4px; border-radius: 4px; + overflow-y: auto; } #acl-list-content { - overflow-y: auto; - max-height: calc(100vh - 330px); + overflow-y: hidden; height: auto !important; } .acl-list-item { diff --git a/view/theme/frio/js/jot.js b/view/theme/frio/js/jot.js new file mode 100644 index 0000000000..d55e5098a2 --- /dev/null +++ b/view/theme/frio/js/jot.js @@ -0,0 +1,39 @@ +// We append the linkPreview to a global Variable to make linkPreview +// accessable on other places. Note: search on other places before you +// delete or move the variable. +var linkPreview; + +/** + * Insert a link into friendica jot. + * + * @returns {void} + */ +function jotGetLink() { + var currentText = $("#profile-jot-text").val(); + var noAttachment = ''; + reply = prompt(aStr.linkurl); + if(reply && reply.length) { + // There should be only one attachment per post. + // So we need to remove the old one. + $('#jot-attachment-preview').empty(); + $('#profile-rotator').show(); + if (currentText.includes("[attachment") && currentText.includes("[/attachment]")) { + noAttachment = '&noAttachment=1'; + } + + // We use the linkPreview library to have a preview + // of the attachments. + if (typeof linkPreview === 'object') { + linkPreview.crawlText(reply + noAttachment); + + // Fallback: insert the attachment bbcode directly into the textarea + // if the attachment live preview isn't available + } else { + $.get('parse_url?binurl=' + bin2hex(reply) + noAttachment, function(data) { + addeditortext(data); + $('#profile-rotator').hide(); + }); + } + autosize.update($("#profile-jot-text")); + } +} diff --git a/view/theme/frio/js/modal.js b/view/theme/frio/js/modal.js index 80694b64da..1c5314c4b4 100644 --- a/view/theme/frio/js/modal.js +++ b/view/theme/frio/js/modal.js @@ -22,6 +22,10 @@ $(document).ready(function(){ $("#jot-content").append(jotcache); // Clear the jotcache. jotcache = ''; + // Destroy the attachment linkPreviw for Jot. + if (typeof linkPreview === 'object') { + linkPreview.destroy(); + } }); // Add Colorbox for viewing Network page images. @@ -292,6 +296,7 @@ function editpost(url) { modal.show(); $("#jot-popup").show(); + linkPreview = $('#profile-jot-text').linkPreview(); } }); } diff --git a/view/theme/frio/js/textedit.js b/view/theme/frio/js/textedit.js index 76a04a32f2..e0c06af581 100644 --- a/view/theme/frio/js/textedit.js +++ b/view/theme/frio/js/textedit.js @@ -46,34 +46,34 @@ function commentGetLink(id, prompttext) { } function addCommentText(data, id) { - // get the textfield - var textfield = document.getElementById("comment-edit-text-" + id); - // check if the textfield does have the default-value - commentOpenUI(textfield, id); - // save already existent content - var currentText = $("#comment-edit-text-" + id).val(); - //insert the data as new value - textfield.value = currentText + data; - autosize.update($("#comment-edit-text-" + id)); + // get the textfield + var textfield = document.getElementById("comment-edit-text-" + id); + // check if the textfield does have the default-value + commentOpenUI(textfield, id); + // save already existent content + var currentText = $("#comment-edit-text-" + id).val(); + //insert the data as new value + textfield.value = currentText + data; + autosize.update($("#comment-edit-text-" + id)); } function commentLinkDrop(event, id) { - var reply = event.dataTransfer.getData("text/uri-list"); - event.target.textContent = reply; - event.preventDefault(); - if (reply && reply.length) { - reply = bin2hex(reply); - $.get('parse_url?noAttachment=1&binurl=' + reply, function(data) { + var reply = event.dataTransfer.getData("text/uri-list"); + event.target.textContent = reply; + event.preventDefault(); + if (reply && reply.length) { + reply = bin2hex(reply); + $.get('parse_url?noAttachment=1&binurl=' + reply, function(data) { addCommentText(data, id); - }); - } + }); + } } function commentLinkDropper(event) { - var linkFound = event.dataTransfer.types.contains("text/uri-list"); - if (linkFound) { - event.preventDefault(); - } + var linkFound = event.dataTransfer.types.contains("text/uri-list"); + if (linkFound) { + event.preventDefault(); + } } diff --git a/view/theme/frio/templates/acl_selector.tpl b/view/theme/frio/templates/acl_selector.tpl index 6a9e38eb37..49a7226eca 100644 --- a/view/theme/frio/templates/acl_selector.tpl +++ b/view/theme/frio/templates/acl_selector.tpl @@ -1,6 +1,8 @@
- + diff --git a/view/theme/frio/templates/jot-header.tpl b/view/theme/frio/templates/jot-header.tpl index 70370e42eb..ac59caed8e 100644 --- a/view/theme/frio/templates/jot-header.tpl +++ b/view/theme/frio/templates/jot-header.tpl @@ -1,5 +1,7 @@ - + + +