2

我在文章表单中使用 tinymce (4.0.6)。我已经更新了图像插件以支持 img 上的“title”属性,并且我想支持自定义数据属性“data-caption”,因为我将使用它来将标题文本放在文章中的图像下。

这是我更新的图像 plugin.min.js:

tinymce.PluginManager.add("image",function(t){function e(t,e){function n(t,n){i.parentNode.removeChild(i),e({width:t,height:n})}var i=document.createElement("img");i.onload=function(){n(i.clientWidth,i.clientHeight)},i.onerror=function(){n()},i.src=t;var a=i.style;a.visibility="hidden",a.position="fixed",a.bottom=a.left=0,a.width=a.height="auto",document.body.appendChild(i)}function n(e){return function(){var n=t.settings.image_list;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(t){e(tinymce.util.JSON.parse(t))}}):e(n)}}function i(n){function i(){var t=[{text:"None",value:""}];return tinymce.each(n,function(e){t.push({text:e.text||e.title,value:e.value||e.url,menu:e.menu})}),t}function a(t){var e,n,i,a;e=s.find("#width")[0],n=s.find("#height")[0],i=e.value(),a=n.value(),s.find("#constrain")[0].checked()&&h&&u&&i&&a&&(t.control==e?(a=Math.round(i/h*a),n.value(a)):(i=Math.round(a/u*i),e.value(i))),h=i,u=a}function o(){function e(e){function i(){e.onload=e.onerror=null,t.selection.select(e),t.nodeChanged()}e.onload=function(){n.width||n.height||m.setAttribs(e,{width:e.clientWidth,height:e.clientHeight}),i()},e.onerror=i}var n=s.toJSON();""===n.width&&(n.width=null),""===n.height&&(n.height=null),""===n.style&&(n.style=null),n={src:n.src,alt:n.alt,caption:n.caption,title:n.title,width:n.width,height:n.height,style:n.style},t.undoManager.transact(function(){return n.src?(p?m.setAttribs(p,n):(n.id="__mcenew",t.selection.setContent(m.createHTML("img",n)),p=m.get("__mcenew"),m.setAttrib(p,"id",null)),e(p),void 0):(p&&(m.remove(p),t.nodeChanged()),void 0)})}function l(t){return t&&(t=t.replace(/px$/,"")),t}function r(){e(this.value(),function(t){t.width&&t.height&&(h=t.width,u=t.height,s.find("#width").value(h),s.find("#height").value(u))})}function c(){function t(t){return t.length>0&&/^[0-9]+$/.test(t)&&(t+="px"),t}var e=s.toJSON(),n=m.parseStyle(e.style);m.setAttrib(p,"style",""),delete n.margin,n["margin-top"]=n["margin-bottom"]=t(e.vspace),n["margin-left"]=n["margin-right"]=t(e.hspace),n["border-width"]=t(e.border),s.find("#style").value(m.serializeStyle(m.parseStyle(m.serializeStyle(n))))}var s,d,h,u,g,m=t.dom,p=t.selection.getNode();h=m.getAttrib(p,"width"),u=m.getAttrib(p,"height"),"IMG"!=p.nodeName||p.getAttribute("data-mce-object")?p=null:d={src:m.getAttrib(p,"src"),alt:m.getAttrib(p,"alt"),caption:m.getAttrib(p,"data-caption"),title:m.getAttrib(p,"title"),width:h,height:u},n&&(g={name:"target",type:"listbox",label:"Image list",values:i(),onselect:function(t){var e=s.find("#alt");(!e.value()||t.lastControl&&e.value()==t.lastControl.text())&&e.value(t.control.text()),s.find("#src").value(t.control.value())}});var y=[{name:"src",type:"filepicker",filetype:"image",label:"Source",autofocus:!0,onchange:r},g,{name:"alt",type:"textbox",label:"Image description"},{name:"data-caption",type:"textbox",label:"Caption"},{name:"title",type:"textbox",label:"Title"},{type:"container",label:"Dimensions",layout:"flex",direction:"row",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:3,size:3,onchange:a},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:3,size:3,onchange:a},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}];t.settings.image_advtab?(p&&(d.hspace=l(p.style.marginLeft||p.style.marginRight),d.vspace=l(p.style.marginTop||p.style.marginBottom),d.border=l(p.style.borderWidth),d.style=t.dom.serializeStyle(t.dom.parseStyle(t.dom.getAttrib(p,"style")))),s=t.windowManager.open({title:"Insert/edit image",data:d,bodyType:"tabpanel",body:[{title:"General",type:"form",items:y},{title:"Advanced",type:"form",pack:"start",items:[{label:"Style",name:"style",type:"textbox"},{type:"form",layout:"grid",packV:"start",columns:2,padding:0,alignH:["left","right"],defaults:{type:"textbox",maxWidth:50,onchange:c},items:[{label:"Vertical space",name:"vspace"},{label:"Horizontal space",name:"hspace"},{label:"Border",name:"border"}]}]}],onSubmit:o})):s=t.windowManager.open({title:"Insert/edit image",data:d,body:y,onSubmit:o})}t.addButton("image",{icon:"image",tooltip:"Insert/edit image",onclick:n(i),stateSelector:"img:not([data-mce-object])"}),t.addMenuItem("image",{icon:"image",text:"Insert image",onclick:n(i),context:"insert",prependToContext:!0})});

当我通过 JS Beautifier 运行它时,它看起来像这样:

tinymce.PluginManager.add("image", function (t) {
function e(t, e) {
    function n(t, n) {
        i.parentNode.removeChild(i), e({
            width: t,
            height: n
        })
    }
    var i = document.createElement("img");
    i.onload = function () {
        n(i.clientWidth, i.clientHeight)
    }, i.onerror = function () {
        n()
    }, i.src = t;
    var a = i.style;
    a.visibility = "hidden", a.position = "fixed", a.bottom = a.left = 0, a.width = a.height = "auto", document.body.appendChild(i)
}

function n(e) {
    return function () {
        var n = t.settings.image_list;
        "string" == typeof n ? tinymce.util.XHR.send({
            url: n,
            success: function (t) {
                e(tinymce.util.JSON.parse(t))
            }
        }) : e(n)
    }
}

function i(n) {
    function i() {
        var t = [{
            text: "None",
            value: ""
        }];
        return tinymce.each(n, function (e) {
            t.push({
                text: e.text || e.title,
                value: e.value || e.url,
                menu: e.menu
            })
        }), t
    }

    function a(t) {
        var e, n, i, a;
        e = s.find("#width")[0], n = s.find("#height")[0], i = e.value(), a = n.value(), s.find("#constrain")[0].checked() && h && u && i && a && (t.control == e ? (a = Math.round(i / h * a), n.value(a)) : (i = Math.round(a / u * i), e.value(i))), h = i, u = a
    }

    function o() {
        function e(e) {
            function i() {
                e.onload = e.onerror = null, t.selection.select(e), t.nodeChanged()
            }
            e.onload = function () {
                n.width || n.height || m.setAttribs(e, {
                    width: e.clientWidth,
                    height: e.clientHeight
                }), i()
            }, e.onerror = i
        }
        var n = s.toJSON();
        "" === n.width && (n.width = null), "" === n.height && (n.height = null), "" === n.style && (n.style = null), n = {
            src: n.src,
            alt: n.alt,
            caption: n.caption,
            title: n.title,
            width: n.width,
            height: n.height,
            style: n.style
        }, t.undoManager.transact(function () {
            return n.src ? (p ? m.setAttribs(p, n) : (n.id = "__mcenew", t.selection.setContent(m.createHTML("img", n)), p = m.get("__mcenew"), m.setAttrib(p, "id", null)), e(p), void 0) : (p && (m.remove(p), t.nodeChanged()), void 0)
        })
    }

    function l(t) {
        return t && (t = t.replace(/px$/, "")), t
    }

    function r() {
        e(this.value(), function (t) {
            t.width && t.height && (h = t.width, u = t.height, s.find("#width").value(h), s.find("#height").value(u))
        })
    }

    function c() {
        function t(t) {
            return t.length > 0 && /^[0-9]+$/.test(t) && (t += "px"), t
        }
        var e = s.toJSON(),
            n = m.parseStyle(e.style);
        m.setAttrib(p, "style", ""), delete n.margin, n["margin-top"] = n["margin-bottom"] = t(e.vspace), n["margin-left"] = n["margin-right"] = t(e.hspace), n["border-width"] = t(e.border), s.find("#style").value(m.serializeStyle(m.parseStyle(m.serializeStyle(n))))
    }
    var s, d, h, u, g, m = t.dom,
        p = t.selection.getNode();
    h = m.getAttrib(p, "width"), u = m.getAttrib(p, "height"), "IMG" != p.nodeName || p.getAttribute("data-mce-object") ? p = null : d = {
        src: m.getAttrib(p, "src"),
        alt: m.getAttrib(p, "alt"),
        caption: m.getAttrib(p, "data-caption"),
        title: m.getAttrib(p, "title"),
        width: h,
        height: u
    }, n && (g = {
        name: "target",
        type: "listbox",
        label: "Image list",
        values: i(),
        onselect: function (t) {
            var e = s.find("#alt");
            (!e.value() || t.lastControl && e.value() == t.lastControl.text()) && e.value(t.control.text()), s.find("#src").value(t.control.value())
        }
    });
    var y = [{
            name: "src",
            type: "filepicker",
            filetype: "image",
            label: "Source",
            autofocus: !0,
            onchange: r
        },
        g, {
            name: "alt",
            type: "textbox",
            label: "Image description"
        }, {
            name: "data-caption",
            type: "textbox",
            label: "Caption"
        }, {
            name: "title",
            type: "textbox",
            label: "Title"
        }, {
            type: "container",
            label: "Dimensions",
            layout: "flex",
            direction: "row",
            align: "center",
            spacing: 5,
            items: [{
                name: "width",
                type: "textbox",
                maxLength: 3,
                size: 3,
                onchange: a
            }, {
                type: "label",
                text: "x"
            }, {
                name: "height",
                type: "textbox",
                maxLength: 3,
                size: 3,
                onchange: a
            }, {
                name: "constrain",
                type: "checkbox",
                checked: !0,
                text: "Constrain proportions"
            }]
        }
    ];
    t.settings.image_advtab ? (p && (d.hspace = l(p.style.marginLeft || p.style.marginRight), d.vspace = l(p.style.marginTop || p.style.marginBottom), d.border = l(p.style.borderWidth), d.style = t.dom.serializeStyle(t.dom.parseStyle(t.dom.getAttrib(p, "style")))), s = t.windowManager.open({
        title: "Insert/edit image",
        data: d,
        bodyType: "tabpanel",
        body: [{
            title: "General",
            type: "form",
            items: y
        }, {
            title: "Advanced",
            type: "form",
            pack: "start",
            items: [{
                label: "Style",
                name: "style",
                type: "textbox"
            }, {
                type: "form",
                layout: "grid",
                packV: "start",
                columns: 2,
                padding: 0,
                alignH: ["left", "right"],
                defaults: {
                    type: "textbox",
                    maxWidth: 50,
                    onchange: c
                },
                items: [{
                    label: "Vertical space",
                    name: "vspace"
                }, {
                    label: "Horizontal space",
                    name: "hspace"
                }, {
                    label: "Border",
                    name: "border"
                }]
            }]
        }],
        onSubmit: o
    })) : s = t.windowManager.open({
        title: "Insert/edit image",
        data: d,
        body: y,
        onSubmit: o
    })
}
t.addButton("image", {
    icon: "image",
    tooltip: "Insert/edit image",
    onclick: n(i),
    stateSelector: "img:not([data-mce-object])"
}), t.addMenuItem("image", {
    icon: "image",
    text: "Insert image",
    onclick: n(i),
    context: "insert",
    prependToContext: !0
})
});

我的tinymce初始化中有这个:

extended_valid_elements : "img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name|data-caption]"

title 属性按预期工作,但在提交图像对话框时删除了 data-caption 属性。如果我检查工具 - > 源代码框,标题属性存在于生成的 img 标记上,但数据标题不存在。

我认为这可能与传递属性值的函数的某些部分有关,例如行标题:n.caption,。我这样做了,因为我认为 data-caption 不会在此处正确评估为变量名。

有没有人尝试通过tinymce 4中的图像插件在图像上放置数据属性?还是有另一种方法可以将 data-caption 属性添加到 img 标记上(无需在源代码窗口中进行编辑)?我希望这对内容作者来说很容易使用(使用 tinymce 的全部意义),并且我在编写其他自定义函数方面取得了一些巨大的成功,但是这个挂断让我很难过。

提前谢谢!

4

0 回答 0