attachment preview: handle content with attachment bbcode inside (show preview of...
authorrabuzarus <rabuzarus@t-online.de>
Sat, 2 Feb 2019 22:06:11 +0000 (23:06 +0100)
committerrabuzarus <rabuzarus@t-online.de>
Sat, 2 Feb 2019 22:06:11 +0000 (23:06 +0100)
view/js/linkPreview.js

index afbb453..763386f 100644 (file)
@@ -3,8 +3,8 @@
  * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)\r
  * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.\r
  * \r
- * restructured from rabzuarus (https://friendica.kommune4.de/profile/rabuzarus)\r
- * for the decental social network Friendica.\r
+ * Restructured from Rabzuarus (https://friendica.kommune4.de/profile/rabuzarus)\r
+ * to use it for the decental social network Friendica (https://friendi.ca).\r
  * \r
  * Version: 1.4.0\r
  */\r
                var defaultTitle = opts.defaultTitle;\r
                var defaultDescription = opts.defaultDescription;\r
 \r
+               /**\r
+                * Initialize the plugin\r
+                * \r
+                * @returns {void}\r
+                */\r
                var init = function() {\r
                        $('#' + selector).bind({\r
                                paste: function () {\r
                                        }\r
                                }\r
                        });\r
+\r
+                       // Check if we have already attachment bbcode in the textarea\r
+                       // and add it to the attachment preview.\r
+                       var content = $('#' + selector).val();\r
+                       addBBCodeToPreview(content);\r
                };\r
+\r
+               /**\r
+                * Reset some values.\r
+                * \r
+                * @returns {void}\r
+                */\r
                var resetPreview = function() {\r
                        $('#hasAttachment_' + selector).val(0);\r
                        photoNumber = 0;\r
                        images = "";\r
-               }\r
+               };\r
 \r
+               /**\r
+                * Crawl a text string if it contains an url and try\r
+                * to attach it.\r
+                * \r
+                * If no text is passed to crawlText() we take\r
+                * the previous word before the cursor of the textarea.\r
+                * \r
+                * @param {string} text (optional)\r
+                * @returns {void}\r
+                */\r
                var crawlText = function (text) {\r
                        block = false;\r
                        images = '';\r
                        isExtern = false;\r
 \r
+                       // If no text is passed to crawlText() we \r
+                       // take the previous word before the cursor.\r
                        if (typeof text === 'undefined') {\r
                                text = getPrevWord(selector);\r
                        } else {\r
                        }\r
                };\r
 \r
+               /**\r
+                * Process the attachment data according to\r
+                * its content type (image, audio, video, attachment)\r
+                * \r
+                * @param {object} result\r
+                * @returns {void}\r
+                */\r
                var processContentData = function(result) {\r
                        if (result.contentType === 'image') {\r
                                insertImage(result.data);\r
                        }\r
+                       if (result.contentType === 'audio') {\r
+                               insertAudio(result.data);\r
+                       }\r
+                       if (result.contentType === 'video') {\r
+                               insertVideo(result.data);\r
+                       }\r
                        if (result.contentType === 'attachment') {\r
                                insertAttachment(result.data);\r
                        }\r
                        $('#profile-rotator').hide();\r
-               }\r
+               };\r
 \r
+               /**\r
+                * Fetch the content of link which should be attached.\r
+                * \r
+                * @param {string} binurl Link which should be attached as hexadecimal string.\r
+                * @param {type} callback\r
+                * @returns {void}\r
+                */\r
                var getContentData = function(binurl, callback) {\r
                        $.get('parse_url?binurl='+ binurl + '&dataType=json', function (answer) {\r
-                               if (typeof answer.contentType === 'undefined'\r
-                                       || answer.contentType === null)\r
-                               {\r
-                                       answer.contentType = "";\r
-                               }\r
-                               if (typeof answer.data.url === 'undefined'\r
-                                       || answer.data.url === null)\r
-                               {\r
-                                       answer.data.url = "";\r
-                               }\r
-                               if (typeof answer.data.title === 'undefined'\r
-                                       || answer.data.title === null\r
-                                       || answer.data.title === "")\r
-                               {\r
-                                       answer.data.title = defaultTitle;\r
-                               }\r
-                               if (typeof answer.data.text === 'undefined'\r
-                                       || answer.data.text === null\r
-                                       || answer.data.text === "")\r
-                               {\r
-                                       answer.data.text = "";\r
-                               }\r
-                               if (typeof answer.data.images === 'undefined'\r
-                                       || answer.data.images === null)\r
-                               {\r
-                                       answer.data.images = "";\r
-                               }\r
+                               obj = sanitizeInputData(answer);\r
 \r
                                // Put the data into a cache\r
-                               cache[binurl] = answer;\r
+                               cache[binurl] = obj;\r
 \r
-                               callback(answer);\r
+                               callback(obj);\r
 \r
                                isCrawling = false;\r
                        });\r
-               }\r
+               };\r
 \r
-               var insertImage = function(json) {\r
+               /*\r
+                * Add a [img] bbtag with the image url to the jot editor.\r
+                * \r
+                * @param {type} data\r
+                * @returns {void}\r
+                */\r
+               var insertImage = function(data) {\r
                        if (!isExtern) {\r
-                               return\r
+                               return;\r
                        }\r
-                       var bbcode = '\n[img]' + json.url + '[/img]\n';\r
+                       var bbcode = '\n[img]' + data.url + '[/img]\n';\r
                        addeditortext(bbcode);\r
                };\r
 \r
-               var insertAudio = function(json) {\r
+               /*\r
+                * Add a [audio] bbtag with the audio url to the jot editor.\r
+                * \r
+                * @param {type} data\r
+                * @returns {void}\r
+                */\r
+               var insertAudio = function(data) {\r
                        if (!isExtern) {\r
-                               return\r
+                               return;\r
                        }\r
-                       var bbcode = '\n[audio]' + json.url + '[/audio]\n';\r
+                       var bbcode = '\n[audio]' + data.url + '[/audio]\n';\r
                        addeditortext(bbcode);\r
                };\r
 \r
-               var insertVideo = function(json) {\r
+               /*\r
+                * Add a [video] bbtag with the video url to the jot editor.\r
+                * \r
+                * @param {type} data\r
+                * @returns {void}\r
+                */\r
+               var insertVideo = function(data) {\r
                        if (!isExtern) {\r
-                               return\r
+                               return;\r
                        }\r
                        var bbcode = '\n[video]' + json.url + '[/video]\n';\r
                        addeditortext(bbcode);\r
                };\r
 \r
-               var insertAttachment = function(json) {\r
+               /**\r
+                * Proccess all attachment data and show up a html\r
+                * attachment preview.\r
+                * \r
+                * @param {obj} data Attachment data.\r
+                * @returns {void}\r
+                */\r
+               var insertAttachment = function(data) {\r
                        // If we have already a preview, leaver here.\r
                        // Note: if we finish the Preview of other media content type,\r
                        // we can move this condition to the beggining of crawlText();\r
                                return;\r
                        }\r
 \r
-                       if (json.type != 'link' && json.type != 'video' && json.type != 'photo' || json.url == json.title) {\r
+                       if (data.type !== 'link' && data.type !== 'video' && data.type !== 'photo' || data.url === data.title) {\r
                                $('#profile-rotator').hide();\r
                                return;\r
                        }\r
                        $('#photoNumber_' + selector).val(0);\r
                        resetPreview();\r
 \r
-                       var typeClass = 'type-' + json.type;\r
-                       var imageClass = 'attachment-preview';\r
-                       var urlHost = "";\r
-                       var description = json.text;\r
+                       processAttachmentTpl(data, 'type-' + data.type);\r
+                       addTitleDescription(data);\r
+                       addHostToAttachment(data.url);\r
+                       addImagesToAttachment(data.images);\r
+\r
+                       processEventListener();\r
+                       $('#profile-rotator').hide();\r
+               };\r
 \r
+               /**\r
+                * Construct the attachment html from the attachment template and\r
+                * add it to the DOM.\r
+                * \r
+                * @param {object} data Attachment data.\r
+                * @returns {void}\r
+                */\r
+               var processAttachmentTpl = function(data) {\r
                        // Load and add the template if it isn't allready loaded.\r
-                       if ($('#preview_' + selector).length == 0) {\r
+                       if ($('#preview_' + selector).length === 0) {\r
                                var tpl = previewTpl.format(\r
-                                       typeClass,\r
+                                       'type-' + data.type,\r
                                        attachmentTpl,\r
                                        1,\r
-                                       bin2hex(json.url),\r
-                                       json.type\r
+                                       bin2hex(data.url),\r
+                                       data.type\r
                                );\r
                                $('#' + selector).after(tpl);\r
                        }\r
 \r
                        isActive = true;\r
+               };\r
+\r
+               /**\r
+                * Add the attachment title and the description\r
+                * to the attachment preview.\r
+                * \r
+                * @param {object} data Attachment data.\r
+                * @returns {void}\r
+                */\r
+               var addTitleDescription = function(data) {\r
+                       var description = data.text;\r
 \r
                        if (description === '') {\r
                                description = defaultDescription;\r
                        }\r
 \r
                        $('#previewTitle_' + selector).html("\\r
-                               <span id='previewSpanTitle_" + selector + "' class='previewSpanTitle' >" + escapeHTML(json.title) + "</span>\\r
-                               <input type='text' name='attachment_title' value='" + escapeHTML(json.title) + "' id='previewInputTitle_" + selector + "' class='previewInputTitle inputPreview' style='display: none;'/>"\r
+                               <span id='previewSpanTitle_" + selector + "' class='previewSpanTitle' >" + escapeHTML(data.title) + "</span>\\r
+                               <input type='text' name='attachment_title' value='" + escapeHTML(data.title) + "' id='previewInputTitle_" + selector + "' class='previewInputTitle inputPreview' style='display: none;'/>"\r
                        );\r
 \r
                        $('#previewDescription_' + selector).html("\\r
                                <span id='previewSpanDescription_" + selector + "' class='previewSpanDescription' >" + escapeHTML(description) + "</span>\n\\r
-                               <textarea id='previewInputDescription_" + selector + "' name='attachment_text' class='previewInputDescription' style='display: none;' class='inputPreview' >" + escapeHTML(json.text) + "</textarea>"\r
+                               <textarea id='previewInputDescription_" + selector + "' name='attachment_text' class='previewInputDescription' style='display: none;' class='inputPreview' >" + escapeHTML(data.text) + "</textarea>"\r
                        );\r
+               };\r
 \r
-                       if (json.url) {\r
+               /**\r
+                * Add the host to the attachment preview.\r
+                * \r
+                * @param {string} url The url of the link attachment.\r
+                * @returns {void}\r
+                */\r
+               var addHostToAttachment = function(url) {\r
+                       if (url) {\r
                                var regexpr = "(https?://)([^:^/]*)(:\\d*)?(.*)?";\r
-                               var regResult = json.url.match(regexpr);\r
+                               var regResult = url.match(regexpr);\r
                                var urlHost = regResult[1] + regResult[2];\r
-                               $('#previewUrl_' + selector).html("<a href='" + json.url + "'>" + urlHost + "</a>");\r
+                               $('#previewUrl_' + selector).html("<a href='" + url + "'>" + urlHost + "</a>");\r
                        }\r
+               };\r
 \r
-                       images = json.images;\r
-\r
+               /**\r
+                * Add preview images to the attachment.\r
+                * \r
+                * @param {array} images\r
+                * \r
+                * @returns {void}\r
+                */\r
+               var addImagesToAttachment = function(images) {\r
+                       var imageClass = 'attachment-preview';\r
+       \r
                        if (Array.isArray(images)) {\r
                                $('#previewImages_' + selector).show();\r
                                $('#attachmentImageSrc_' + selector).val(bin2hex(images[photoNumber].src));\r
 \r
                        for (i = 0; i < images.length; i++) {\r
                                // For small preview images we use a smaller attachment format.\r
-//                             if (Array.isArray(images) && typeof images[i].width !== 'undefined') {\r
-                                       ///@todo here we need to add a check for !Config::get('system', 'always_show_preview').\r
-                                       if (images[i].width >= 500 && images[i].width >= images[i].height) {\r
-                                                       imageClass = 'attachment-image';\r
-                                       }\r
-//                             }\r
+                               ///@todo here we need to add a check for !Config::get('system', 'always_show_preview').\r
+                               if (images[i].width >= 500 && images[i].width >= images[i].height) {\r
+                                               imageClass = 'attachment-image';\r
+                               }\r
+\r
                                if (i === 0) {\r
                                        appendImage += "<img id='imagePreview_" + selector + "_" + i + "' src='" + images[i].src + "' class='" + imageClass + "' ></img>";\r
                                } else {\r
                                        });\r
                                }\r
                        }\r
-\r
-                       processEventListener();\r
-                       $('#profile-rotator').hide();\r
                };\r
 \r
+               /**\r
+                * Add event listener to control the attachment preview.\r
+                * \r
+                * @returns {void}\r
+                */\r
                var processEventListener = function() {\r
                        $('#previewSpanTitle_' + selector).unbind('click').click(function (e) {\r
                                e.stopPropagation();\r
                                $('#preview_' + selector).fadeOut("fast", function () {\r
                                        $('#preview_' + selector).remove();\r
                                        $('#profile-rotator').hide();\r
+                                       $('#' + selector).focus();\r
                                });\r
 \r
                        });\r
                };\r
 \r
+               /**\r
+                * Convert attachmant bbcode into an array.\r
+                * \r
+                * @param {string} content Text content with the attachment bbcode.\r
+                * @returns {object || null}\r
+                */\r
+               var getAttachmentData = function(content) {\r
+                       var data = {};\r
+\r
+                       var match = content.match(/(.*)\[attachment(.*?)\](.*?)\[\/attachment\](.*)/ism);\r
+                       if (match === null || match.length < 5) {\r
+                               return null;\r
+                       }\r
+\r
+                       var attributes = match[2];\r
+                       data.text = trim(match[1]);\r
+\r
+                       var type = '';\r
+                       var matches = attributes.match(/type='(.*?)'/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               type = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       matches = attributes.match(/type="(.*?)"/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               type = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       if (type === '') {\r
+                               return null;\r
+                       }\r
+\r
+                       if (\r
+                               type !== 'link'\r
+                               && type !== 'audio'\r
+                               && type !== 'photo'\r
+                               && type !== 'video')\r
+                       {\r
+                               return null;\r
+                       }\r
+\r
+                       if (type !== '') {\r
+                               data.type = type;\r
+                       }\r
+\r
+                       var url = '';\r
+\r
+                       matches = attributes.match(/url='(.*?)'/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               url = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       matches = attributes.match(/url="(.*?)"/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               url = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       if(url !== '') {\r
+                               data.url = escapeHTML(url);\r
+                       }\r
+\r
+                       var title = '';\r
+\r
+                       matches = attributes.match(/title='(.*?)'/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               title = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       matches = attributes.match(/title="(.*?)"/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               title = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       if (title !== '') {\r
+                               data.title = escapeHTML(title);\r
+                       }\r
+\r
+                       var image = '';\r
+\r
+                       matches = attributes.match(/image='(.*?)'/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               image = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       matches = attributes.match(/image="(.*?)"/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               image = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       if (image !== '') {\r
+                               data.image = escapeHTML(image);\r
+                       }\r
+\r
+                       var preview = '';\r
+\r
+                       matches = attributes.match(/preview='(.*?)'/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               preview = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       matches = attributes.match(/preview="(.*?)"/ism);\r
+                       if (matches !== null && typeof matches[1] !== 'undefined') {\r
+                               preview = matches[1].toLowerCase();\r
+                       }\r
+\r
+                       if (preview !== '') {\r
+                               data.preview = escapeHTML(preview);\r
+                       }\r
+\r
+                       data.text = trim(match[3]);\r
+                       data.after = trim(match[4]);\r
+\r
+                       return data;\r
+               };\r
+\r
+               /**\r
+                * Process txt content and if it contains attachment bbcode\r
+                * add it to the attachment preview .\r
+                * \r
+                * @param {string} content\r
+                * @returns {void}\r
+                */\r
+               var addBBCodeToPreview =function(content) {\r
+                       var attachmentData = getAttachmentData(content);\r
+                       if (attachmentData) {\r
+                               reAddAttachment(attachmentData);\r
+                               // Remove the attachment bbcode from the textarea.\r
+                               var content = content.replace(/\[attachment.*\[\/attachment]/ism, '');\r
+                               $('#' + selector).val(content);\r
+                               $('#' + selector).focus();\r
+                       }\r
+               };\r
+\r
+               /**\r
+                * Add an Attachment with data from an old bbcode\r
+                * generated attachment.\r
+                * \r
+                * @param {object} json The attachment data.\r
+                * @returns {void}\r
+                */\r
+               var reAddAttachment = function(json) {\r
+                       if (isActive) {\r
+                               $('#profile-rotator').hide();\r
+                               return;\r
+                       }\r
+\r
+                       if (json.type !== 'link' && json.type !== 'video' && json.type !== 'photo' || json.url === json.title) {\r
+                               $('#profile-rotator').hide();\r
+                               return;\r
+                       }\r
+\r
+                       var obj = {data: json};\r
+                       obj = sanitizeInputData(obj);\r
+\r
+                       var data = obj.data;\r
+\r
+                       resetPreview();\r
+\r
+                       processAttachmentTpl(data);\r
+                       addTitleDescription(data);\r
+                       addHostToAttachment(data.url);\r
+\r
+                       // Since we don't have an array of image data,\r
+                       // we need to add the preview images in a different way\r
+                       // than in function addImagesToAttachment().\r
+                       var imageClass = 'attachment-preview';\r
+                       var image = '';\r
+\r
+                       if (data.image !== '') {\r
+                               imageClass = 'attachment-image';\r
+                               image = data.image;\r
+                       } else {\r
+                               image = data.preview;\r
+                       }\r
+\r
+                       if (image !== '') {\r
+                               var appendImage = "<img id='imagePreview_" + selector + "' src='" + image + "' class='" + imageClass + "' ></img>"\r
+                               $('#previewImage_' + selector).html(appendImage);\r
+                               $('#attachmentImageSrc_' + selector).val(bin2hex(image));\r
+\r
+                               // We need to add the image widht and height when it is \r
+                               // loaded.\r
+                               $('<img/>' ,{\r
+                                       load : function(){\r
+                                               $('#attachmentImageWidth_' + selector).val(this.width);\r
+                                               $('#attachmentImageHeight_' + selector).val(this.height);\r
+                                       },\r
+                                       src  : image\r
+                               });\r
+                       }\r
+\r
+                       processEventListener();\r
+                       $('#profile-rotator').hide();\r
+               };\r
+\r
+               /**\r
+                * Add missing default properties to the input data object.\r
+                * \r
+                * @param {object} obj Input data.\r
+                * @returns {object}\r
+                */\r
+               var sanitizeInputData = function(obj) {\r
+                       if (typeof obj.contentType === 'undefined'\r
+                               || obj.contentType === null)\r
+                       {\r
+                               obj.contentType = "";\r
+                       }\r
+                       if (typeof obj.data.url === 'undefined'\r
+                               || obj.data.url === null)\r
+                       {\r
+                               obj.data.url = "";\r
+                       }\r
+                       if (typeof obj.data.title === 'undefined'\r
+                               || obj.data.title === null\r
+                               || obj.data.title === "")\r
+                       {\r
+                               obj.data.title = defaultTitle;\r
+                       }\r
+                       if (typeof obj.data.text === 'undefined'\r
+                               || obj.data.text === null\r
+                               || obj.data.text === "")\r
+                       {\r
+                               obj.data.text = "";\r
+                       }\r
+                       if (typeof obj.data.images === 'undefined'\r
+                               || obj.data.images === null)\r
+                       {\r
+                               obj.data.images = "";\r
+                       }\r
+\r
+                       if (typeof obj.data.image === 'undefined'\r
+                               || obj.data.image === null)\r
+                       {\r
+                               obj.data.image = "";\r
+                       }\r
+\r
+                       if (typeof obj.data.preview === 'undefined'\r
+                               || obj.data.preview === null)\r
+                       {\r
+                               obj.data.preview = "";\r
+                       }\r
+\r
+                       return obj;\r
+               };\r
+\r
+               /**\r
+                * Destroy the plugin.\r
+                * \r
+                * @returns {void}\r
+                */\r
                var destroy = function() {\r
                        $('#' + selector).unbind();\r
                        $('#preview_' + selector).remove();\r
                                .replace(/\[/g, '&#91;')\r
                                .replace(/\]/g, '&#93;')\r
                                .replace(/\'/g, '&#39;'); // '&apos;' is not valid HTML 4\r
-               }\r
+               };\r
 \r
                // Initialize LinkPreview \r
                init();\r
                        crawlText: function(text) {\r
                                crawlText(text);\r
                        },\r
+                       addBBCodeToPreview: function(content) {\r
+                               addBBCodeToPreview(content);\r
+                       },\r
                        destroy: function() {\r
                                destroy();\r
                        }\r