65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 ASP.NET WebApi2 的 TinyMCE 图片插入插件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.90/5 (7投票s)

2015年3月25日

CPOL

1分钟阅读

viewsIcon

34127

downloadIcon

1146

如何在 ASP.NET 中在 TinyMCE 中添加图片?本文档展示了插件与 .NET WebApi2 通信以插入图片。

引言

在使用 TinyMCE 所见即所得编辑器时,您可能希望在编辑器中添加图片。但要实现此目的,您需要购买文件管理模块,或者自行开发插件。

有两种方法可以实现。第一种方法是将图片上传到服务器的特定目录,并在编辑器中创建指向该图片的链接。另一种方法是将图片文件转换为 Base64 编码字符串。大多数现代浏览器都支持第二种方法,因此我将向您展示如何使用 .NET WebApi 将图片文件转换为 base64 编码字符串。

支持的浏览器

  • IE 9 或更高版本
  • 几乎所有 Chrome 版本
  • 几乎所有 Firefox 版本
  • Opera:未测试。

使用代码

为了将图片二进制数据转换为 base64 编码字符串,我将使用 JQuery AJAX 和 .NET WebApi2。

因此,此项目需要 MVC5。

让我们从 WebApi 控制器开始。其中有一个名为 ConvertImageToBase64 的方法。此方法将图片二进制数据转换为 JQuery AJAX 请求的 base64 编码字符串。转换完成后,该字符串将返回到浏览器。

//
// EditController.cs in Project/Controllers
//

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Http;

namespace TinyMCE.Controllers
{
    public class EditorController : ApiController
    {
        [Route("api/image/convert-base64")]
        [HttpPost]
        public HttpResponseMessage ConvertImageToBase64()
        {
            string base64String = "";
            HttpResponseMessage response = new HttpResponseMessage();

            if (HttpContext.Current.Request.Files.AllKeys.Any())
            {
                // Get the uploaded image from the Files collection
                var httpPostedFile = HttpContext.Current.Request.Files["file"];

                if (httpPostedFile != null)
                {
                    // Validate the uploaded image(optional)

                    byte[] fileData = null;
                    using (var binaryReader = new BinaryReader(httpPostedFile.InputStream))
                    {
                        fileData = binaryReader.ReadBytes(httpPostedFile.ContentLength);
                        base64String = System.Convert.ToBase64String(fileData, 0, fileData.Length);
                    }
                }
            }

            response.Content = new StringContent(base64String);
            response.Content.Headers.ContentType = new MediaTypeHeaderValue("text/html");

            return response;
        }
    }
}

 

这是 TinyMCE 弹出窗口定义文件。为了支持当前 TinyMCE 版本的相同外观和感觉,我在 Contents/Site.css 中添加了一些样式表并使用了 Bootstrap。

//
// dialog.html in Project/Scripts/tinymce
//

<!DOCTYPE html>
<html>
<head>
    <title>Image insert</title>

    <link href="/Content/bootstrap.css" rel="stylesheet" />
    <link href="/Content/Site.css" rel="stylesheet" />

    <script src="/Scripts/modernizr-2.6.2.js"></script>
    <script src="/Scripts/jquery-1.10.2.js"></script>

    <script src="/Scripts/bootstrap.js"></script>

    <script>
        $(document).on('change', '.btn-file :file', function () {
            var input = $(this),
            numFiles = input.get(0).files ? input.get(0).files.length : 1,
            label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
            input.trigger('fileselect', [numFiles, label]);
        });

        $(document).ready(function () {
            $('.btn-file :file').on('fileselect', function (event, numFiles, label) {

                var input = $(this).parents('.input-group').find(':text'),
                    log = numFiles > 1 ? numFiles + ' files selected' : label;

                if (input.length) {
                    input.val(log);
                } else {
                    if (log) alert(log);
                }

            });
        });
    </script>
</head>
<body>
    <div style="padding:20px;">
        <table style="width: 100%;">
            <tr>
                <td style="width: 141px; vertical-align: middle;"><label style="font-weight: normal;">Source</label></td>
                <td style="vertical-align: middle;">
                    <div class="input-group">
                        <span class="input-group-btn">
                            <span class="btn btn-default btn-file">
                                Browse&hellip; <input type="file" id="content" name="content">
                            </span>
                        </span>
                        <input type="text" class="form-control" readonly>
                    </div>
                </td>
            </tr>
            <tr>
                <td style="width: 141px; vertical-align: middle; padding-top: 20px;"><label style="font-weight: normal;">Image Description</label></td>
                <td style ="vertical-align: middle; padding-top: 20px;">
                    <input id="desc" name="desc" type="text" class="form-control">
                </td>
            </tr>
        </table>
    </div>
</body>
</html>

 

这是一个 JavaScript 插件,用于将图片二进制数据发送到服务器。

引用

如果您更改了此文件中的任何内容,则必须将其缩小到 plugin.min.js 文件。否则,该功能将无法按预期工作,因为 TinyMCE 仅读取缩小后的文件。

//
// plugin.js in Project/Scripts/tinymce
//

tinymce.PluginManager.add("base64_image", function (a, b) {
    a.addButton("base64_image", {
        icon: "image",
        tooltip: "Insert image",
        onclick: function () {
            a.windowManager.open({
                title: "Insert image",
                url: b + "/dialog.html",
                width: 500,
                height: 150,
                buttons: [{
                    text: "Ok",
                    classes: 'widget btn primary first abs-layout-item',
                    onclick: function () {
                        var b = a.windowManager.getWindows()[0];

                        if (b.getContentWindow().document.getElementById('content').value == '') {
                            alert('Please select a file');
                            return false;
                        }

                        if (b.getContentWindow().document.getElementById('content').files[0].size > 1000 * 1024) {
                            alert('Max image file size is 1MB');
                            return false;
                        }

                        if (b.getContentWindow().document.getElementById('content').files[0].type != "image/jpeg" && b.getContentWindow().document.getElementById('content').files[0].type != "image/jpg" &&
                            b.getContentWindow().document.getElementById('content').files[0].type != "image/png" && b.getContentWindow().document.getElementById('content').files[0].type != "image/gif") {
                            alert('Only image file format can be uploaded');
                            return false;
                        }

                        var data;

                        data = new FormData();
                        data.append('file', b.getContentWindow().document.getElementById('content').files[0]);

                        $.ajax({
                            url: '/api/image/convert-base64',
                            data: data,
                            processData: false,
                            contentType: false,
                            async: false,
                            type: 'POST',
                        }).done(function (msg) {
                            var imageAlt = b.getContentWindow().document.getElementById('desc').value;
                            var imageSrc = "data:" + b.getContentWindow().document.getElementById('content').files[0].type + ";base64," + msg;

                            var imageTag = '<img src="' + imageSrc + '" alt="' + imageAlt + '" style="max-width: 100%;" />';

                            a.insertContent(imageTag), b.close()

                        }).fail(function (jqXHR, textStatus) {
                            alert("Request failed: " + jqXH.responseText + " --- " +RtextStatus);
                        });
                    }
                }, {
                    text: "Close",
                    onclick: "close"
                }]
            })
        }
    }),

    a.addMenuItem("base64_image", {
        icon: "image",
        text: "Insert image",
        context: "insert",
        prependToContext: !0,
        onclick: function () {
            a.windowManager.open({
                title: "Insert image",
                url: b + "/api/image/convert-base64",
                width: 500,
                height: 150,
                buttons: [{
                    text: "Ok",
                    classes: 'widget btn primary first abs-layout-item',
                    onclick: function () {
                        var b = a.windowManager.getWindows()[0];

                        if (b.getContentWindow().document.getElementById('content').value == '') {
                            alert('Please select a file');
                            return false;
                        }

                        if (b.getContentWindow().document.getElementById('content').files[0].size > 1000 * 1024) {
                            alert('Max image file size is 1MB');
                            return false;
                        }

                        if (b.getContentWindow().document.getElementById('content').files[0].type != "image/jpeg" && b.getContentWindow().document.getElementById('content').files[0].type != "image/jpg" &&
                            b.getContentWindow().document.getElementById('content').files[0].type != "image/png" && b.getContentWindow().document.getElementById('content').files[0].type != "image/gif") {
                            alert('Only image file format can be uploaded');
                            return false;
                        }

                        var data;

                        data = new FormData();
                        data.append('file', b.getContentWindow().document.getElementById('content').files[0]);

                        $.ajax({
                            url: '/api/image/convert-base64',
                            data: data,
                            processData: false,
                            contentType: false,
                            async: false,
                            type: 'POST',
                        }).done(function (msg) {
                            var imageAlt = b.getContentWindow().document.getElementById('desc').value;
                            var imageSrc = "data:" + b.getContentWindow().document.getElementById('content').files[0].type + ";base64," + msg;

                            var imageTag = '<img src="' + imageSrc + '" alt="' + imageAlt + '" style="max-width: 100%;" />';

                            a.insertContent(imageTag), b.close()

                        }).fail(function (jqXHR, textStatus) {
                            alert("Request failed: " + jqXH.responseText + " --- " + RtextStatus);
                        });
                    }
                }, {
                    text: "Close",
                    onclick: "close"
                }]
            })
        }
    })

});

 

最后,只需更改 Index.cshtml 以包含 TinyMCE 编辑器模块即可。

//
// Index.cshtml in Project/View/Home
//


<div class="form-group" style="padding-top: 80px;">
    @Html.TextArea("Content")
</div>

@section Scripts {
    <script type="text/javascript" src="@Url.Content("~/Scripts/tinymce/tinymce.min.js")"></script>

    <script type="text/javascript">
        tinymce.init({
            selector: "textarea",
            width: '100%',
            height: 600,
            statusbar: false,
            menubar: false,

            setup: function (ed) {
                ed.on('init', function () {
                    this.getDoc().body.style.fontSize = '14px';
                    this.getDoc().body.style.fontFamily = '"Helvetica Neue", Helvetica, Arial, sans-serif';
                });
            },

            paste_data_images: true,

            plugins: [
                "advlist autolink lists link base64_image charmap hr anchor pagebreak",
                "searchreplace wordcount visualblocks visualchars code",
                "insertdatetime media nonbreaking save table contextmenu directionality",
                "emoticons textcolor colorpicker textpattern "
            ],
            toolbar: "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link base64_image media | forecolor backcolor"
        });

        // Prevent bootstrap dialog from blocking focusin
        $(document).on('focusin', function (e) {
            if ($(e.target).closest(".mce-window").length) {
                e.stopImmediatePropagation();
            }
        });
    </script>
}

 

屏幕截图

此屏幕截图只是展示了此插件和 WebApi 模块的工作方式。

历史

2015-03-24:初始文章上传

© . All rights reserved.