mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #6636 from open-sausages/pulls/4.0/filehandlefield-class
Change to use injector for file upload fields in framework
This commit is contained in:
commit
eda4aae923
@ -66,3 +66,9 @@ SilverStripe\Core\Injector\Injector:
|
||||
SilverStripe\Assets\Image_Backend:
|
||||
class: SilverStripe\Assets\GDBackend
|
||||
Image_Backend: '%$SilverStripe\Assets\Image_Backend'
|
||||
---
|
||||
Name: coreassetfield
|
||||
---
|
||||
SilverStripe\Core\Injector\Injector:
|
||||
SilverStripe\Forms\FileHandleField:
|
||||
class: SilverStripe\Forms\FileField
|
||||
|
@ -3,40 +3,39 @@
|
||||
use SilverStripe\Admin\CMSMenu;
|
||||
use SilverStripe\Forms\HTMLEditor\TinyMCEConfig;
|
||||
|
||||
|
||||
// Default CMS HTMLEditorConfig
|
||||
TinyMCEConfig::get('cms')->setOptions(array(
|
||||
'friendly_name' => 'Default CMS',
|
||||
'priority' => '50',
|
||||
'friendly_name' => 'Default CMS',
|
||||
'priority' => '50',
|
||||
|
||||
'body_class' => 'typography',
|
||||
'body_class' => 'typography',
|
||||
|
||||
'contextmenu' => "sslink ssmedia inserttable | cell row column deletetable",
|
||||
'contextmenu' => "sslink ssmedia inserttable | cell row column deletetable",
|
||||
|
||||
'use_native_selects' => false,
|
||||
'valid_elements' => "@[id|class|style|title],a[id|rel|rev|dir|tabindex|accesskey|type|name|href|target|title"
|
||||
. "|class],-strong/-b[class],-em/-i[class],-strike[class],-u[class],#p[id|dir|class|align|style],-ol[class],"
|
||||
. "-ul[class],-li[class],br,img[id|dir|longdesc|usemap|class|src|border|alt=|title|width|height|align|data*],"
|
||||
. "-sub[class],-sup[class],-blockquote[dir|class],-cite[dir|class|id|title],"
|
||||
. "-table[cellspacing|cellpadding|width|height|class|align|summary|dir|id|style],"
|
||||
. "-tr[id|dir|class|rowspan|width|height|align|valign|bgcolor|background|bordercolor|style],"
|
||||
. "tbody[id|class|style],thead[id|class|style],tfoot[id|class|style],"
|
||||
. "#td[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style],"
|
||||
. "-th[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style],caption[id|dir|class],"
|
||||
. "-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align],address[class|align],"
|
||||
. "-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],"
|
||||
. "-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|dir|class|align|style],hr[class],"
|
||||
. "dd[id|class|title|dir],dl[id|class|title|dir],dt[id|class|title|dir]",
|
||||
'extended_valid_elements' => "img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name"
|
||||
. "|usemap|data*],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling],"
|
||||
. "object[width|height|data|type],param[name|value],map[class|name|id],area[shape|coords|href|target|alt]"
|
||||
'use_native_selects' => false,
|
||||
'valid_elements' => "@[id|class|style|title],a[id|rel|rev|dir|tabindex|accesskey|type|name|href|target|title"
|
||||
. "|class],-strong/-b[class],-em/-i[class],-strike[class],-u[class],#p[id|dir|class|align|style],-ol[class],"
|
||||
. "-ul[class],-li[class],br,img[id|dir|longdesc|usemap|class|src|border|alt=|title|width|height|align|data*],"
|
||||
. "-sub[class],-sup[class],-blockquote[dir|class],-cite[dir|class|id|title],"
|
||||
. "-table[cellspacing|cellpadding|width|height|class|align|summary|dir|id|style],"
|
||||
. "-tr[id|dir|class|rowspan|width|height|align|valign|bgcolor|background|bordercolor|style],"
|
||||
. "tbody[id|class|style],thead[id|class|style],tfoot[id|class|style],"
|
||||
. "#td[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style],"
|
||||
. "-th[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style],caption[id|dir|class],"
|
||||
. "-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align],address[class|align],"
|
||||
. "-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],"
|
||||
. "-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|dir|class|align|style],hr[class],"
|
||||
. "dd[id|class|title|dir],dl[id|class|title|dir],dt[id|class|title|dir]",
|
||||
'extended_valid_elements' => "img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name"
|
||||
. "|usemap|data*],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling],"
|
||||
. "object[width|height|data|type],param[name|value],map[class|name|id],area[shape|coords|href|target|alt]"
|
||||
));
|
||||
|
||||
TinyMCEConfig::get('cms')
|
||||
->enablePlugins(array(
|
||||
'contextmenu' => null,
|
||||
'image' => null,
|
||||
'ssbuttons' => FRAMEWORK_ADMIN_DIR . '/client/dist/js/TinyMCE_SSPlugin.js'
|
||||
));
|
||||
->enablePlugins(array(
|
||||
'contextmenu' => null,
|
||||
'image' => null,
|
||||
'sslink' => FRAMEWORK_ADMIN_DIR . '/client/dist/js/TinyMCE_sslink.js'
|
||||
));
|
||||
|
||||
CMSMenu::remove_menu_class('SilverStripe\\Admin\\CMSProfileController');
|
||||
|
18
admin/client/dist/js/TinyMCE_SSPlugin.js
vendored
18
admin/client/dist/js/TinyMCE_SSPlugin.js
vendored
@ -1,18 +0,0 @@
|
||||
webpackJsonp([2],[function(t,e,n){(function(t){"use strict"
|
||||
!function(){var e={getInfo:function n(){return{longname:"Special buttons for SilverStripe CMS",author:"Sam Minnée",authorurl:"http://www.siverstripe.com/",infourl:"http://www.silverstripe.com/",version:"1.0"
|
||||
}},init:function i(e){e.addButton("sslink",{icon:"link",title:"Insert Link",cmd:"sslink"}),e.addMenuItem("sslink",{icon:"link",text:"Insert Link",cmd:"sslink"}),e.addButton("ssmedia",{icon:"image",title:"Insert Media",
|
||||
cmd:"ssmedia"}),e.addMenuItem("ssmedia",{icon:"image",text:"Insert Media",cmd:"ssmedia"}),e.addCommand("sslink",function(e){t("#"+this.id).entwine("ss").openLinkDialog()}),e.addCommand("ssmedia",function(e){
|
||||
t("#"+this.id).entwine("ss").openMediaDialog()}),e.on("BeforeExecCommand",function(t){var n=t.command,i=t.ui,a=t.value
|
||||
"mceAdvLink"==n||"mceLink"==n?(t.preventDefault(),e.execCommand("sslink",i,a)):"mceAdvImage"!=n&&"mceImage"!=n||(t.preventDefault(),e.execCommand("ssmedia",i,a))}),e.on("SaveContent",function(e){var n=t(e.content),i=function a(t){
|
||||
return Object.keys(t).map(function(e){return t[e]?e+'="'+t[e]+'"':null}).filter(function(t){return null!==t}).join(" ")}
|
||||
n.find(".ss-htmleditorfield-file.embed").each(function(){var e=t(this),n={width:e.attr("width"),"class":e.attr("cssclass"),thumbnail:e.data("thumbnail")},a="[embed "+i(n)+"]"+e.data("url")+"[/embed]"
|
||||
e.replaceWith(a)}),n.find("img").each(function(){var e=t(this),n={src:e.attr("src"),id:e.data("id"),width:e.attr("width"),height:e.attr("height"),"class":e.attr("class"),title:e.attr("title"),alt:e.attr("alt")
|
||||
},a="[image "+i(n)+"]"
|
||||
e.replaceWith(a)}),e.content="",n.each(function(){void 0!==this.outerHTML&&(e.content+=this.outerHTML)})}),e.on("BeforeSetContent",function(e){for(var n,i=e.content,a=function d(t){return t.match(/([^\s\/'"=,]+)\s*=\s*(('([^']+)')|("([^"]+)")|([^\s,\]]+))/g).reduce(function(t,e){
|
||||
var n=e.match(/^([^\s\/'"=,]+)\s*=\s*(?:(?:'([^']+)')|(?:"([^"]+)")|(?:[^\s,\]]+))$/),i=n[1],a=n[2]||n[3]||n[4]
|
||||
return t[i]=a,t},{})},s=/\[embed(.*?)\](.+?)\[\/\s*embed\s*\]/gi;n=s.exec(i);){var c=a(n[1]),r
|
||||
r=t("<img/>").attr({src:c.thumbnail,width:c.width,height:c.height,"class":c["class"],"data-url":n[2]}).addClass("ss-htmleditorfield-file embed"),c.cssclass=c["class"],Object.keys(c).forEach(function(t){
|
||||
return r.attr("data-"+t,c[t])}),i=i.replace(n[0],t("<div/>").append(r).html())}for(var s=/\[image(.*?)\]/gi;n=s.exec(i);){var c=a(n[1]),r=t("<img/>").attr({src:c.src,width:c.width,height:c.height,"class":c["class"],
|
||||
alt:c.alt,title:c.title,"data-id":c.id})
|
||||
i=i.replace(n[0],t("<div/>").append(r).html())}e.content=i})}}
|
||||
tinymce.PluginManager.add("ssbuttons",function(t){e.init(t)})}()}).call(e,n(1))}])
|
5
admin/client/dist/js/TinyMCE_sslink.js
vendored
Normal file
5
admin/client/dist/js/TinyMCE_sslink.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
webpackJsonp([2],[function(n,i){"use strict"
|
||||
!function(){var n={init:function i(n){n.addButton("sslink",{icon:"link",title:"Insert Link",cmd:"sslink"}),n.addMenuItem("sslink",{icon:"link",text:"Insert Link",cmd:"sslink"}),n.addCommand("sslink",function(){
|
||||
window.jQuery("#"+n.id).entwine("ss").openLinkDialog()}),n.on("BeforeExecCommand",function(i){var e=i.command,t=i.ui,s=i.value
|
||||
"mceAdvLink"!==e&&"mceLink"!==e||(i.preventDefault(),n.execCommand("sslink",t,s))})}}
|
||||
tinymce.PluginManager.add("sslink",function(i){return n.init(i)})}()}])
|
23
admin/client/dist/js/TinyMCE_ssmedia.js
vendored
Normal file
23
admin/client/dist/js/TinyMCE_ssmedia.js
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
webpackJsonp([3],[function(t,e){"use strict"
|
||||
function i(t,e,i){return e in t?Object.defineProperty(t,e,{value:i,enumerable:!0,configurable:!0,writable:!0}):t[e]=i,t}var n=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var i=arguments[e]
|
||||
|
||||
|
||||
for(var n in i)Object.prototype.hasOwnProperty.call(i,n)&&(t[n]=i[n])}return t}
|
||||
!function(){var t={getInfo:function e(){return{longname:"Media Dialog for SilverStripe CMS",author:"Sam Minnée",authorurl:"http://www.siverstripe.com/",infourl:"http://www.silverstripe.com/",version:"1.1"
|
||||
}},init:function a(t){t.addButton("ssmedia",{icon:"image",title:"Insert Media",cmd:"ssmedia"}),t.addMenuItem("ssmedia",{icon:"image",text:"Insert Media",cmd:"ssmedia"}),t.addCommand("ssmedia",function(){
|
||||
window.jQuery("#"+t.id).entwine("ss").openMediaDialog()}),t.on("BeforeExecCommand",function(e){var i=e.command,n=e.ui,a=e.value
|
||||
"mceAdvImage"!==i&&"mceImage"!==i||(e.preventDefault(),t.execCommand("ssmedia",n,a))}),t.on("SaveContent",function(t){var e=window.jQuery(t.content),i=function n(t){return Object.keys(t).map(function(e){
|
||||
return t[e]?e+'="'+t[e]+'"':null}).filter(function(t){return null!==t}).join(" ")}
|
||||
e.find(".ss-htmleditorfield-file.embed").each(function(){var t=window.jQuery(this),e={width:t.attr("width"),"class":t.attr("cssclass"),thumbnail:t.data("thumbnail")},n="[embed "+i(e)+"]"+t.data("url")+"[/embed]"
|
||||
|
||||
|
||||
t.replaceWith(n)}),e.find("img").each(function(){var t=window.jQuery(this),e={src:t.attr("src"),id:t.data("id"),width:t.attr("width"),height:t.attr("height"),"class":t.attr("class"),title:t.attr("title"),
|
||||
alt:t.attr("alt")},n="[image "+i(e)+"]"
|
||||
t.replaceWith(n)}),t.content="",e.each(function(){void 0!==this.outerHTML&&(t.content+=this.outerHTML)})}),t.on("BeforeSetContent",function(t){for(var e=null,a=t.content,r=function l(t){return t.match(/([^\s\/'"=,]+)\s*=\s*(('([^']+)')|("([^"]+)")|([^\s,\]]+))/g).reduce(function(t,e){
|
||||
var a=e.match(/^([^\s\/'"=,]+)\s*=\s*(?:(?:'([^']+)')|(?:"([^"]+)")|(?:[^\s,\]]+))$/),r=a[1],s=a[2]||a[3]||a[4]
|
||||
return n({},t,i({},r,s))},{})},s=/\[embed(.*?)](.+?)\[\/\s*embed\s*]/gi,c=function m(){var t=r(e[1]),i=window.jQuery("<img/>").attr({src:t.thumbnail,width:t.width,height:t.height,"class":t["class"],"data-url":e[2]
|
||||
}).addClass("ss-htmleditorfield-file embed")
|
||||
t.cssclass=t["class"],Object.keys(t).forEach(function(e){return i.attr("data-"+e,t[e])}),a=a.replace(e[0],window.jQuery("<div/>").append(i).html())};e=s.exec(a);)c()
|
||||
for(var o=/\[image(.*?)]/gi;e=o.exec(a);){var d=r(e[1]),u=window.jQuery("<img/>").attr({src:d.src,width:d.width,height:d.height,"class":d["class"],alt:d.alt,title:d.title,"data-id":d.id})
|
||||
a=a.replace(e[0],window.jQuery("<div/>").append(u).html())}t.content=a})}}
|
||||
tinymce.PluginManager.add("ssmedia",function(e){return t.init(e)})}()}])
|
22
admin/client/dist/js/bundle.js
vendored
22
admin/client/dist/js/bundle.js
vendored
@ -1,7 +1,7 @@
|
||||
webpackJsonp([4],[function(e,t,n){"use strict"
|
||||
n(2),n(3),n(6),n(16),n(18),n(24),n(26),n(28),n(29),n(31),n(34),n(104),n(112),n(116),n(126),n(127),n(128),n(129),n(130),n(131),n(133),n(136),n(138),n(140),n(143),n(146),n(148),n(150),n(152),n(154),n(156),
|
||||
n(157),n(166),n(167),n(169),n(170),n(171),n(172),n(173),n(174),n(175),n(176),n(177),n(178),n(179),n(180),n(181),n(184),n(186),n(187),n(188),n(189),n(193),n(194),n(195),n(196),n(197),n(194),n(189),n(200),
|
||||
n(202),n(204),n(205)},,function(e,t){"use strict"
|
||||
n(157),n(166),n(167),n(169),n(170),n(171),n(172),n(173),n(174),n(175),n(176),n(177),n(178),n(179),n(180),n(181),n(184),n(186),n(187),n(188),n(189),n(193),n(194),n(195),n(196),n(197),n(194),n(200),n(202),
|
||||
n(204),n(205)},,function(e,t){"use strict"
|
||||
function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0})
|
||||
var i=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n]
|
||||
i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}(),r=function(){function e(){
|
||||
@ -1811,15 +1811,13 @@ this.setEditor(t),t.init(this.attr("id")),this._super()},onremove:function n(){t
|
||||
return n.length||(n=e('<div id="insert-media-react__dialog-wrapper" />'),e("body").append(n)),n.setElement(this),void n.open()}var i=function s(e){return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()
|
||||
|
||||
},r=this,a=e("#cms-editor-dialogs").data("url"+i(t)+"form"),o=e(".htmleditorfield-"+t+"dialog")
|
||||
o.length?(o.getForm().setElement(this),o.html(""),o.addClass("loading"),o.open()):(o=e('<div class="htmleditorfield-dialog htmleditorfield-'+t+'dialog loading">'),e("body").append(o)),e.ajax({url:a,complete:function l(){
|
||||
o.removeClass("loading")},success:function u(e){o.html(e),o.getForm().setElement(r),o.trigger("ssdialogopen")}})}}),e(".htmleditorfield-dialog").entwine({onadd:function s(){this.is(".ui-dialog-content")||this.ssdialog({
|
||||
autoOpen:!0,buttons:{insert:{text:_i18n2["default"]._t("HtmlEditorField.INSERT","Insert"),"data-icon":"accept","class":"btn action btn-primary media-insert",click:function t(){e(this).find("form").submit()
|
||||
|
||||
}}}}),this._super()},getForm:function l(){return this.find("form")},open:function u(){this.ssdialog("open")},close:function c(){this.ssdialog("close")},toggle:function d(e){this.is(":visible")?this.close():this.open()
|
||||
|
||||
},onscroll:function f(){this.animate({scrollTop:this.find("form").height()},500)}}),e("form.htmleditorfield-form").entwine({Selection:null,Bookmark:null,Element:null,setSelection:function p(t){return this._super(e(t))
|
||||
|
||||
},onadd:function h(){var e=this.find(":header:first")
|
||||
if(!a){if("media"===t)throw new Error("Install silverstripe/asset-admin to use media dialog")
|
||||
throw new Error("Dialog named "+t+" is not available.")}o.length?(o.getForm().setElement(this),o.html(""),o.addClass("loading"),o.open()):(o=e('<div class="htmleditorfield-dialog htmleditorfield-'+t+'dialog loading">'),
|
||||
e("body").append(o)),e.ajax({url:a,complete:function l(){o.removeClass("loading")},success:function u(e){o.html(e),o.getForm().setElement(r),o.trigger("ssdialogopen")}})}}),e(".htmleditorfield-dialog").entwine({
|
||||
onadd:function s(){this.is(".ui-dialog-content")||this.ssdialog({autoOpen:!0,buttons:{insert:{text:_i18n2["default"]._t("HtmlEditorField.INSERT","Insert"),"data-icon":"accept","class":"btn action btn-primary media-insert",
|
||||
click:function t(){e(this).find("form").submit()}}}}),this._super()},getForm:function l(){return this.find("form")},open:function u(){this.ssdialog("open")},close:function c(){this.ssdialog("close")},toggle:function d(e){
|
||||
this.is(":visible")?this.close():this.open()},onscroll:function f(){this.animate({scrollTop:this.find("form").height()},500)}}),e("form.htmleditorfield-form").entwine({Selection:null,Bookmark:null,Element:null,
|
||||
setSelection:function p(t){return this._super(e(t))},onadd:function h(){var e=this.find(":header:first")
|
||||
this.getDialog().attr("title",e.text()),this._super()},onremove:function m(){this.setSelection(null),this.setBookmark(null),this.setElement(null),this._super()},getDialog:function g(){return this.closest(".htmleditorfield-dialog")
|
||||
|
||||
},fromDialog:{onssdialogopen:function v(){var e=this.getEditor()
|
||||
@ -1844,7 +1842,7 @@ i&&(e+="#"+i)
|
||||
break
|
||||
case"anchor":e="#"+i
|
||||
break
|
||||
case"file":var r=this.find(".ss-uploadfield .ss-uploadfield-item").attr("data-fileid")
|
||||
case"file":var r=this.find(":input[name=file]").val()
|
||||
e=r?"[file_link,id="+r+"]":""
|
||||
break
|
||||
case"email":e="mailto:"+this.find(":input[name=email]").val(),n&&(e+="?subject="+encodeURIComponent(n)),t=null
|
||||
|
2
admin/client/dist/js/vendor.js
vendored
2
admin/client/dist/js/vendor.js
vendored
@ -10,7 +10,7 @@ return e.e=function a(t,n){if(0===i[t])return n.call(null,e)
|
||||
if(void 0!==i[t])i[t].push(n)
|
||||
else{i[t]=[n]
|
||||
var r=document.getElementsByTagName("head")[0],o=document.createElement("script")
|
||||
o.type="text/javascript",o.charset="utf-8",o.async=!0,o.src=e.p+""+t+".js/"+({0:"LeftAndMain.Ping",1:"MemberImportForm",2:"TinyMCE_SSPlugin",3:"UploadField_select",4:"bundle",5:"leaktools"}[t]||t)+".js",
|
||||
o.type="text/javascript",o.charset="utf-8",o.async=!0,o.src=e.p+""+t+".js/"+({0:"LeftAndMain.Ping",1:"MemberImportForm",2:"TinyMCE_sslink",3:"UploadField_select",4:"bundle",5:"leaktools"}[t]||t)+".js",
|
||||
r.appendChild(o)}},e.m=t,e.c=r,e.p="",e(0)}([function(t,e,n){"use strict"
|
||||
n(398),n(694),n(695),n(698),n(700),n(702),n(732),n(870),n(979),n(981),n(1114),n(1124),n(1139),n(1314),n(1316),n(1364),n(1370),n(1623),n(1631),n(1634),n(1635),n(1638),n(1641),n(1642),n(1744),n(1755),n(1758),
|
||||
n(1772),n(1777),n(168),n(198),n(203),n(1778),n(1779),n(1780),n(1781),n(199),n(1782),n(1783),n(1784),n(1785),n(1786),n(1787),n(1788),n(1789)},function(t,e){t.exports=jQuery},,,,function(t,e){t.exports=React
|
||||
|
@ -65,7 +65,6 @@ require('../legacy/ToggleCompositeField.js');
|
||||
require('../legacy/MemberDatetimeOptionsetField.js');
|
||||
require('../legacy/TreeDropdownField.js');
|
||||
require('../legacy/DateField.js');
|
||||
require('../legacy/UploadField.js');
|
||||
require('../legacy/HtmlEditorField.js');
|
||||
require('../legacy/TabSet.js');
|
||||
require('../legacy/GridField.js');
|
||||
|
@ -327,6 +327,7 @@ $.entwine('ss', function($) {
|
||||
},
|
||||
|
||||
openDialog: function(type) {
|
||||
// Note: This requires asset-admin module
|
||||
if (type === 'media' && window.InsertMediaModal) {
|
||||
let dialog = $('#insert-media-react__dialog-wrapper');
|
||||
|
||||
@ -348,6 +349,13 @@ $.entwine('ss', function($) {
|
||||
url = $('#cms-editor-dialogs').data('url' + capitalize(type) + 'form'),
|
||||
dialog = $('.htmleditorfield-' + type + 'dialog');
|
||||
|
||||
if (!url) {
|
||||
if (type === 'media') {
|
||||
throw new Error("Install silverstripe/asset-admin to use media dialog")
|
||||
}
|
||||
throw new Error(`Dialog named ${type} is not available.`);
|
||||
}
|
||||
|
||||
if(dialog.length) {
|
||||
// Clean existing dialog for reload
|
||||
dialog.getForm().setElement(this);
|
||||
@ -598,7 +606,7 @@ $.entwine('ss', function($) {
|
||||
break;
|
||||
|
||||
case 'file':
|
||||
var fileid = this.find('.ss-uploadfield .ss-uploadfield-item').attr('data-fileid');
|
||||
var fileid = this.find(':input[name=file]').val();
|
||||
href = fileid ? '[file_link,id=' + fileid + ']' : '';
|
||||
break;
|
||||
|
||||
|
@ -1,178 +0,0 @@
|
||||
(function() {
|
||||
|
||||
var ssbuttons = {
|
||||
/**
|
||||
* Returns information about the plugin as a name/value array.
|
||||
* The current keys are longname, author, authorurl, infourl and version.
|
||||
*
|
||||
* @returns Name/value array containing information about the plugin.
|
||||
* @type Array
|
||||
*/
|
||||
getInfo : function() {
|
||||
return {
|
||||
longname : 'Special buttons for SilverStripe CMS',
|
||||
author : 'Sam Minnée',
|
||||
authorurl : 'http://www.siverstripe.com/',
|
||||
infourl : 'http://www.silverstripe.com/',
|
||||
version : "1.0"
|
||||
};
|
||||
},
|
||||
|
||||
init : function(ed) {
|
||||
ed.addButton('sslink', {
|
||||
icon : 'link',
|
||||
title : 'Insert Link',
|
||||
cmd : 'sslink'
|
||||
});
|
||||
ed.addMenuItem('sslink', {
|
||||
icon : 'link',
|
||||
text : 'Insert Link',
|
||||
cmd : 'sslink'
|
||||
});
|
||||
ed.addButton('ssmedia', {
|
||||
icon : 'image',
|
||||
title : 'Insert Media',
|
||||
cmd : 'ssmedia'
|
||||
});
|
||||
ed.addMenuItem('ssmedia', {
|
||||
icon : 'image',
|
||||
text : 'Insert Media',
|
||||
cmd : 'ssmedia'
|
||||
});
|
||||
|
||||
|
||||
ed.addCommand('sslink', function(ed) {
|
||||
// See HtmlEditorField.js
|
||||
jQuery('#' + this.id).entwine('ss').openLinkDialog();
|
||||
});
|
||||
|
||||
ed.addCommand('ssmedia', function(ed) {
|
||||
// See HtmlEditorField.js
|
||||
jQuery('#' + this.id).entwine('ss').openMediaDialog();
|
||||
});
|
||||
|
||||
// Replace the mceAdvLink and mceLink commands with the sslink command, and
|
||||
// the mceAdvImage and mceImage commands with the ssmedia command
|
||||
ed.on('BeforeExecCommand', function(e){
|
||||
var cmd = e.command;
|
||||
var ui = e.ui;
|
||||
var val = e.value;
|
||||
if (cmd == 'mceAdvLink' || cmd == 'mceLink'){
|
||||
e.preventDefault();
|
||||
ed.execCommand('sslink', ui, val);
|
||||
} else if (cmd == 'mceAdvImage' || cmd == 'mceImage'){
|
||||
e.preventDefault();
|
||||
ed.execCommand('ssmedia', ui, val);
|
||||
}
|
||||
});
|
||||
|
||||
ed.on('SaveContent', function(o) {
|
||||
var content = jQuery(o.content);
|
||||
var attrsFn = (attrs) => {
|
||||
return Object.keys(attrs)
|
||||
.map((name) => attrs[name] ? name + '="' + attrs[name] + '"' : null)
|
||||
.filter((el) => el !== null)
|
||||
.join(' ')
|
||||
};
|
||||
|
||||
// Transform [embed] shortcodes
|
||||
content.find('.ss-htmleditorfield-file.embed').each(function() {
|
||||
var el = jQuery(this);
|
||||
var attrs = {
|
||||
width: el.attr('width'),
|
||||
class: el.attr('cssclass'),
|
||||
thumbnail: el.data('thumbnail')
|
||||
};
|
||||
var shortCode = '[embed ' + attrsFn(attrs) + ']' + el.data('url') + '[/embed]';
|
||||
el.replaceWith(shortCode);
|
||||
});
|
||||
|
||||
// Transform [image] shortcodes
|
||||
content.find('img').each(function() {
|
||||
var el = jQuery(this);
|
||||
var attrs = {
|
||||
// Requires server-side preprocessing of HTML+shortcodes in HTMLValue
|
||||
src: el.attr('src'),
|
||||
id: el.data('id'),
|
||||
width: el.attr('width'),
|
||||
height: el.attr('height'),
|
||||
class: el.attr('class'),
|
||||
// don't save caption, since that's in the containing element
|
||||
title: el.attr('title'),
|
||||
alt: el.attr('alt')
|
||||
};
|
||||
var shortCode = '[image ' + attrsFn(attrs) + ']';
|
||||
el.replaceWith(shortCode);
|
||||
});
|
||||
|
||||
// Insert outerHTML in order to retain all nodes incl. <script>
|
||||
// tags which would've been filtered out with jQuery.html().
|
||||
// Note that <script> tags might be sanitized separately based on editor config.
|
||||
o.content = '';
|
||||
content.each(function() {
|
||||
if(this.outerHTML !== undefined) {
|
||||
o.content += this.outerHTML;
|
||||
}
|
||||
});
|
||||
});
|
||||
ed.on('BeforeSetContent', function(o) {
|
||||
var matches;
|
||||
var content = o.content;
|
||||
var attrFromStrFn = (str) => {
|
||||
return str
|
||||
// Split on all attributes, quoted or not
|
||||
.match(/([^\s\/'"=,]+)\s*=\s*(('([^']+)')|("([^"]+)")|([^\s,\]]+))/g)
|
||||
.reduce((coll, val) => {
|
||||
var match = val.match(/^([^\s\/'"=,]+)\s*=\s*(?:(?:'([^']+)')|(?:"([^"]+)")|(?:[^\s,\]]+))$/),
|
||||
key = match[1],
|
||||
value = match[2] || match[3] || match[4]; // single, double, or unquoted match
|
||||
coll[key] = value;
|
||||
return coll;
|
||||
}, {});
|
||||
};
|
||||
|
||||
// Transform [embed] tag
|
||||
var shortTagRegex = /\[embed(.*?)\](.+?)\[\/\s*embed\s*\]/gi;
|
||||
while((matches = shortTagRegex.exec(content))) {
|
||||
var attrs = attrFromStrFn(matches[1]);
|
||||
var el;
|
||||
|
||||
el = jQuery('<img/>').attr({
|
||||
'src': attrs['thumbnail'],
|
||||
'width': attrs['width'],
|
||||
'height': attrs['height'],
|
||||
'class': attrs['class'],
|
||||
'data-url': matches[2]
|
||||
}).addClass('ss-htmleditorfield-file embed');
|
||||
attrs['cssclass'] = attrs['class'];
|
||||
|
||||
Object.keys(attrs).forEach((key) => el.attr('data-' + key, attrs[key]));
|
||||
content = content.replace(matches[0], (jQuery('<div/>').append(el).html()));
|
||||
}
|
||||
|
||||
// Transform [image] tag
|
||||
var shortTagRegex = /\[image(.*?)\]/gi;
|
||||
while((matches = shortTagRegex.exec(content))) {
|
||||
var attrs = attrFromStrFn(matches[1]);
|
||||
var el = jQuery('<img/>').attr({
|
||||
'src': attrs['src'],
|
||||
'width': attrs['width'],
|
||||
'height': attrs['height'],
|
||||
'class': attrs['class'],
|
||||
'alt': attrs['alt'],
|
||||
'title': attrs['title'],
|
||||
'data-id': attrs['id']
|
||||
});
|
||||
content = content.replace(matches[0], (jQuery('<div/>').append(el).html()));
|
||||
}
|
||||
|
||||
o.content = content;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Adds the plugin class to the list of available TinyMCE plugins
|
||||
tinymce.PluginManager.add("ssbuttons", function(editor) {
|
||||
ssbuttons.init(editor);
|
||||
});
|
||||
})();
|
44
admin/client/src/legacy/TinyMCE_sslink.js
Normal file
44
admin/client/src/legacy/TinyMCE_sslink.js
Normal file
@ -0,0 +1,44 @@
|
||||
/* global tinymce */
|
||||
|
||||
(() => {
|
||||
const sslink = {
|
||||
|
||||
/**
|
||||
* Initialise this plugin
|
||||
*
|
||||
* @param {Object} ed
|
||||
*/
|
||||
init(ed) {
|
||||
ed.addButton('sslink', {
|
||||
icon: 'link',
|
||||
title: 'Insert Link',
|
||||
cmd: 'sslink',
|
||||
});
|
||||
ed.addMenuItem('sslink', {
|
||||
icon: 'link',
|
||||
text: 'Insert Link',
|
||||
cmd: 'sslink',
|
||||
});
|
||||
|
||||
ed.addCommand('sslink', () => {
|
||||
// See HtmlEditorField.js
|
||||
window.jQuery(`#${ed.id}`).entwine('ss').openLinkDialog();
|
||||
});
|
||||
|
||||
// Replace the mceAdvLink and mceLink commands with the sslink command, and
|
||||
// the mceAdvImage and mceImage commands with the ssmedia command
|
||||
ed.on('BeforeExecCommand', (e) => {
|
||||
const cmd = e.command;
|
||||
const ui = e.ui;
|
||||
const val = e.value;
|
||||
if (cmd === 'mceAdvLink' || cmd === 'mceLink') {
|
||||
e.preventDefault();
|
||||
ed.execCommand('sslink', ui, val);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
// Adds the plugin class to the list of available TinyMCE plugins
|
||||
tinymce.PluginManager.add('sslink', (editor) => sslink.init(editor));
|
||||
})();
|
2
client/dist/styles/debug.css
vendored
2
client/dist/styles/debug.css
vendored
@ -154,4 +154,4 @@ fieldset{
|
||||
background:#ffe9e9;
|
||||
border:1px solid #c80700;
|
||||
border-radius:4px;
|
||||
}
|
||||
}
|
@ -588,4 +588,4 @@ body #Footer p{
|
||||
font-size:18px;
|
||||
padding:0 2px 2px 0;
|
||||
font-weight:700;
|
||||
}
|
||||
}
|
@ -46,7 +46,7 @@ use SilverStripe\Core\Object;
|
||||
* }
|
||||
* </code>
|
||||
*/
|
||||
class FileField extends FormField
|
||||
class FileField extends FormField implements FileHandleField
|
||||
{
|
||||
use UploadReceiver;
|
||||
|
||||
|
18
src/Forms/FileHandleField.php
Normal file
18
src/Forms/FileHandleField.php
Normal file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Forms;
|
||||
|
||||
interface FileHandleField
|
||||
{
|
||||
public function getAttributes();
|
||||
|
||||
public function getFolderName();
|
||||
|
||||
public function setAllowedExtensions($rules);
|
||||
|
||||
public function getAllowedExtensions();
|
||||
|
||||
public function setAllowedFileCategories($category);
|
||||
|
||||
public function setFolderName($folderName);
|
||||
}
|
@ -4,7 +4,6 @@ namespace SilverStripe\Forms\HTMLEditor;
|
||||
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Core\Object;
|
||||
|
||||
/**
|
||||
* A PHP version of TinyMCE's configuration, to allow various parameters to be configured on a site or section basis
|
||||
@ -57,7 +56,7 @@ abstract class HTMLEditorConfig
|
||||
* instance - do not call 'new'
|
||||
*
|
||||
* @param string $identifier The identifier for the config set. If omitted, the active config is returned.
|
||||
* @return HTMLEditorConfig The configuration object.
|
||||
* @return static The configuration object.
|
||||
* This will be created if it does not yet exist for that identifier
|
||||
*/
|
||||
public static function get($identifier = null)
|
||||
|
@ -44,7 +44,6 @@ class HTMLEditorField_Toolbar extends RequestHandler
|
||||
|
||||
private static $allowed_actions = array(
|
||||
'LinkForm',
|
||||
'MediaForm',
|
||||
'viewfile',
|
||||
'getanchors'
|
||||
);
|
||||
@ -78,9 +77,8 @@ class HTMLEditorField_Toolbar extends RequestHandler
|
||||
public function forTemplate()
|
||||
{
|
||||
return sprintf(
|
||||
'<div id="cms-editor-dialogs" data-url-linkform="%s" data-url-mediaform="%s"></div>',
|
||||
Controller::join_links($this->controller->Link(), $this->name, 'LinkForm', 'forTemplate'),
|
||||
Controller::join_links($this->controller->Link(), $this->name, 'MediaForm', 'forTemplate')
|
||||
'<div id="cms-editor-dialogs" data-url-linkform="%s"></div>',
|
||||
Controller::join_links($this->controller->Link(), $this->name, 'LinkForm', 'forTemplate')
|
||||
);
|
||||
}
|
||||
|
||||
@ -122,6 +120,7 @@ class HTMLEditorField_Toolbar extends RequestHandler
|
||||
|
||||
$numericLabelTmpl = '<span class="step-label"><span class="flyout">Step %d.</span>'
|
||||
. '<span class="title">%s</span></span>';
|
||||
|
||||
$form = new Form(
|
||||
$this->controller,
|
||||
"{$this->name}/LinkForm",
|
||||
@ -159,7 +158,13 @@ class HTMLEditorField_Toolbar extends RequestHandler
|
||||
$siteTree,
|
||||
TextField::create('external', _t('HTMLEditorField.URL', 'URL'), 'http://'),
|
||||
EmailField::create('email', _t('HTMLEditorField.EMAIL', 'Email address')),
|
||||
$fileField = UploadField::create('file', _t('HTMLEditorField.FILE', 'File')),
|
||||
$fileField = TreeDropdownField::create(
|
||||
'file',
|
||||
_t('HTMLEditorField.FILE', 'File'),
|
||||
File::class,
|
||||
'ID',
|
||||
'Name'
|
||||
),
|
||||
TextField::create('Anchor', _t('HTMLEditorField.ANCHORVALUE', 'Anchor')),
|
||||
TextField::create('Subject', _t('HTMLEditorField.SUBJECT', 'Email subject')),
|
||||
TextField::create('Description', _t('HTMLEditorField.LINKDESCR', 'Link description')),
|
||||
@ -177,7 +182,6 @@ class HTMLEditorField_Toolbar extends RequestHandler
|
||||
$headerWrap->addExtraClass('CompositeField composite cms-content-header form-group--no-label ');
|
||||
$contentComposite->setName('ContentBody');
|
||||
$contentComposite->addExtraClass('ss-insert-link content');
|
||||
$fileField->setAllowedMaxFileNumber(1);
|
||||
|
||||
$form->unsetValidator();
|
||||
$form->loadDataFrom($this);
|
||||
@ -200,146 +204,6 @@ class HTMLEditorField_Toolbar extends RequestHandler
|
||||
return $parentID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link Form} instance allowing a user to
|
||||
* add images and flash objects to the TinyMCE content editor.
|
||||
*
|
||||
* @return Form
|
||||
*/
|
||||
public function MediaForm()
|
||||
{
|
||||
// TODO Handle through GridState within field - currently this state set too late to be useful here (during
|
||||
// request handling)
|
||||
$parentID = $this->getAttachParentID();
|
||||
|
||||
$fileFieldConfig = GridFieldConfig::create()->addComponents(
|
||||
new GridFieldSortableHeader(),
|
||||
new GridFieldFilterHeader(),
|
||||
new GridFieldDataColumns(),
|
||||
new GridFieldPaginator(7),
|
||||
// TODO Shouldn't allow delete here, its too confusing with a "remove from editor view" action.
|
||||
// Remove once we can fit the search button in the last actual title column
|
||||
new GridFieldDeleteAction(),
|
||||
new GridFieldDetailForm()
|
||||
);
|
||||
$fileField = GridField::create('Files', false, null, $fileFieldConfig);
|
||||
$fileField->setList($this->getFiles($parentID));
|
||||
$fileField->setAttribute('data-selectable', true);
|
||||
$fileField->setAttribute('data-multiselect', true);
|
||||
/** @var GridFieldDataColumns $columns */
|
||||
$columns = $fileField->getConfig()->getComponentByType('SilverStripe\\Forms\\GridField\\GridFieldDataColumns');
|
||||
$columns->setDisplayFields(array(
|
||||
'StripThumbnail' => false,
|
||||
'Title' => _t('File.Title', 'Title'),
|
||||
'Created' => File::singleton()->fieldLabel('Created'),
|
||||
));
|
||||
$columns->setFieldCasting(array(
|
||||
'Created' => 'DBDatetime->Nice'
|
||||
));
|
||||
|
||||
$fromCMS = new CompositeField(
|
||||
$select = TreeDropdownField::create('ParentID', "", 'SilverStripe\\Assets\\Folder')
|
||||
->addExtraClass('noborder')
|
||||
->setValue($parentID),
|
||||
$fileField
|
||||
);
|
||||
|
||||
$fromCMS->addExtraClass('content ss-uploadfield htmleditorfield-from-cms');
|
||||
$select->addExtraClass('content-select');
|
||||
|
||||
|
||||
$URLDescription = _t(
|
||||
'HTMLEditorField.URLDESCRIPTION',
|
||||
'Insert videos and images from the web into your page simply by entering the URL of the file. Make sure you have the rights or permissions before sharing media directly from the web.<br /><br />Please note that files are not added to the file store of the CMS but embeds the file from its original location, if for some reason the file is no longer available in its original location it will no longer be viewable on this page.'
|
||||
);
|
||||
$fromWeb = new CompositeField(
|
||||
$description = new LiteralField(
|
||||
'URLDescription',
|
||||
'<div class="url-description">' . $URLDescription . '</div>'
|
||||
),
|
||||
$remoteURL = new TextField('RemoteURL', 'http://'),
|
||||
new LiteralField(
|
||||
'addURLImage',
|
||||
'<button type="button" class="btn action btn-primary field font-icon-plus add-url">' .
|
||||
_t('HTMLEditorField.BUTTONADDURL', 'Add url') . '</button>'
|
||||
)
|
||||
);
|
||||
|
||||
$remoteURL->addExtraClass('remoteurl');
|
||||
$fromWeb->addExtraClass('content ss-uploadfield htmleditorfield-from-web');
|
||||
|
||||
Requirements::css(ltrim(FRAMEWORK_ADMIN_DIR . '/client/dist/styles/AssetUploadField.css', '/'));
|
||||
$computerUploadField = UploadField::create('AssetUploadField', '');
|
||||
$computerUploadField->setConfig('previewMaxWidth', 40);
|
||||
$computerUploadField->setConfig('previewMaxHeight', 30);
|
||||
$computerUploadField->addExtraClass('toolbar toolbar--content ss-assetuploadfield htmleditorfield-from-computer');
|
||||
$computerUploadField->removeExtraClass('ss-uploadfield');
|
||||
$computerUploadField->setTemplate('SilverStripe\\Forms\\HTMLEditorField_UploadField');
|
||||
$computerUploadField->setFolderName(Upload::config()->get('uploads_folder'));
|
||||
|
||||
$defaultPanel = new CompositeField(
|
||||
$computerUploadField,
|
||||
$fromCMS
|
||||
);
|
||||
|
||||
$fromWebPanel = new CompositeField(
|
||||
$fromWeb
|
||||
);
|
||||
|
||||
$defaultPanel->addExtraClass('htmleditorfield-default-panel');
|
||||
$fromWebPanel->addExtraClass('htmleditorfield-web-panel');
|
||||
|
||||
$allFields = new CompositeField(
|
||||
$defaultPanel,
|
||||
$fromWebPanel,
|
||||
$editComposite = new CompositeField(
|
||||
new LiteralField('contentEdit', '<div class="content-edit ss-uploadfield-files files"></div>')
|
||||
)
|
||||
);
|
||||
|
||||
$allFields->addExtraClass('ss-insert-media');
|
||||
|
||||
$headings = new CompositeField(
|
||||
new LiteralField(
|
||||
'Heading',
|
||||
sprintf(
|
||||
'<h3 class="htmleditorfield-mediaform-heading insert">%s</h3>',
|
||||
_t('HTMLEditorField.INSERTMEDIA', 'Insert media from')
|
||||
) .
|
||||
sprintf(
|
||||
'<h3 class="htmleditorfield-mediaform-heading update">%s</h3>',
|
||||
_t('HTMLEditorField.UpdateMEDIA', 'Update media')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$headings->addExtraClass('cms-content-header');
|
||||
$editComposite->addExtraClass('ss-assetuploadfield');
|
||||
|
||||
$fields = new FieldList(
|
||||
$headings,
|
||||
$allFields
|
||||
);
|
||||
|
||||
$form = new Form(
|
||||
$this->controller,
|
||||
"{$this->name}/MediaForm",
|
||||
$fields,
|
||||
new FieldList()
|
||||
);
|
||||
|
||||
|
||||
$form->unsetValidator();
|
||||
$form->disableSecurityToken();
|
||||
$form->loadDataFrom($this);
|
||||
$form->addExtraClass('htmleditorfield-form htmleditorfield-mediaform cms-dialog-content');
|
||||
|
||||
// Allow other people to extend the fields being added to the imageform
|
||||
$this->extend('updateMediaForm', $form);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of allowed schemes (no wildcard, all lower case) or empty to allow all schemes
|
||||
*
|
||||
|
@ -276,7 +276,7 @@ class TinyMCEConfig extends HTMLEditorConfig
|
||||
2 => array(
|
||||
'formatselect', '|',
|
||||
'paste', 'pastetext', '|',
|
||||
'table', 'ssmedia', 'sslink', 'unlink', '|',
|
||||
'table', 'sslink', 'unlink', '|',
|
||||
'code'
|
||||
),
|
||||
3 => array()
|
||||
@ -339,7 +339,7 @@ class TinyMCEConfig extends HTMLEditorConfig
|
||||
* - relative path - Will be treated as a relative url
|
||||
* - absolute url - Some url to an external plugin
|
||||
*
|
||||
* @param string $plugin,... a string, or several strings, or a single array of strings - The plugins to enable
|
||||
* @param string|array $plugin,... a string, or several strings, or a single array of strings - The plugins to enable
|
||||
* @return $this
|
||||
*/
|
||||
public function enablePlugins($plugin)
|
||||
|
@ -4,8 +4,9 @@ namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Assets\File;
|
||||
use SilverStripe\Assets\Image;
|
||||
use SilverStripe\Forms\UploadField;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\FileHandleField;
|
||||
use SilverStripe\Forms\NumericField;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
@ -48,7 +49,7 @@ class DBForeignKey extends DBInt
|
||||
}
|
||||
$hasOneSingleton = singleton($hasOneClass);
|
||||
if ($hasOneSingleton instanceof File) {
|
||||
$field = new UploadField($relationName, $title);
|
||||
$field = Injector::inst()->create(FileHandleField::class, $relationName, $title);
|
||||
if ($hasOneSingleton instanceof Image) {
|
||||
$field->setAllowedFileCategories('image/supported');
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ const config = [
|
||||
leaktools: `${PATHS.ADMIN_JS_SRC}/legacy/leaktools.js`,
|
||||
MemberImportForm: `${PATHS.ADMIN_JS_SRC}/legacy/MemberImportForm.js`,
|
||||
UploadField_select: `${PATHS.ADMIN_JS_SRC}/legacy/UploadField_select.js`,
|
||||
TinyMCE_SSPlugin: `${PATHS.ADMIN_JS_SRC}/legacy/TinyMCE_SSPlugin.js`,
|
||||
TinyMCE_sslink: `${PATHS.ADMIN_JS_SRC}/legacy/TinyMCE_sslink.js`,
|
||||
},
|
||||
resolve: {
|
||||
root: [__dirname, path.resolve(__dirname, PATHS.ADMIN_JS_SRC)],
|
||||
|
Loading…
Reference in New Issue
Block a user