API Unified json responses via new HTTPBulkToolsResponse

All bulk handlers and the bulk uploader now use a common HTTPBulkToolsResponse to return a common json format and handle errors. The front end uses this json to update the drifield accordingling.
This commit is contained in:
Thierry François 2018-03-14 22:21:54 +02:00
parent a1dcbc00e6
commit bc2b317a35
18 changed files with 714 additions and 98 deletions

View File

@ -1 +1 @@
!function(n){function t(i){if(e[i])return e[i].exports;var o=e[i]={i:i,l:!1,exports:{}};return n[i].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var e={};t.m=n,t.c=e,t.d=function(n,e,i){t.o(n,e)||Object.defineProperty(n,e,{configurable:!1,enumerable:!0,get:i})},t.n=function(n){var e=n&&n.__esModule?function(){return n.default}:function(){return n};return t.d(e,"a",e),e},t.o=function(n,t){return Object.prototype.hasOwnProperty.call(n,t)},t.p="",t(t.s=0)}({"./client/src/js/manager.js":function(n,t,e){(function(n){!function(n){n.entwine("ss",function(n){n.entwine("colymba",function(n){n(".bulkManagerOptions").entwine({onmatch:function(){var t=this.parents("thead"),e=t.find("tr"),i=[".filter-header",".sortable-header"],o=t.find(i.join(",")),a=e.index(this),c=e.length-1;o.each(function(n,t){var i=e.index(t);i<c&&(c=i)}),a>c&&e.eq(c).insertAfter(n(this))},onunmatch:function(){}}),n("td.col-bulkSelect").entwine({onmatch:function(){},onunmatch:function(){},onmouseover:function(){n(this).parents(".ss-gridfield-item").find(".edit-link").removeClass("edit-link").addClass("tempDisabledEditLink")},onmouseout:function(){n(this).parents(".ss-gridfield-item").find(".tempDisabledEditLink").addClass("edit-link").removeClass("tempDisabledEditLink")},onclick:function(t){var e=n(t.target).find("input");n(e).prop("checked")?n(e).prop("checked",!1):n(e).prop("checked",!0)}}),n("td.col-bulkSelect input").entwine({onmatch:function(){},onunmatch:function(){},onclick:function(t){n(this).parents(".grid-field__table").find("input.bulkSelectAll").prop("checked","")}}),n("input.bulkSelectAll").entwine({onmatch:function(){},onunmatch:function(){},onclick:function(){var t=n(this).prop("checked");n(this).parents(".grid-field__table").find("td.col-bulkSelect input").prop("checked",t).trigger("change")},getSelectRecordsID:function(){return n(this).parents(".grid-field__table").find("td.col-bulkSelect input:checked").map(function(){return parseInt(n(this).data("record"))}).get()}}),n("select.bulkActionName").entwine({onmatch:function(){},onunmatch:function(){},onchange:function(t){var e=n(this).val(),i=n(this).parents(".bulkManagerOptions"),o=i.find(".doBulkActionButton"),a=o.data("config");if(n.each(a,function(n,t){n!=e&&o.removeClass(t.buttonClasses)}),!e)return void o.addClass("disabled");if(o.removeClass("disabled"),o.addClass(a[e].buttonClasses).addClass("btn-outline-secondary"),a[e].icon){var c=o.find("img");c.length?c.attr("src",a[e].icon):o.prepend('<img src="'+a[e].icon+'" alt="" />')}else o.find("img").remove();a[e].destructive?o.addClass("btn-outline-danger"):o.removeClass("btn-outline-danger")}}),n(".doBulkActionButton").entwine({onmatch:function(){},onunmatch:function(){},getActionURL:function(n,t){var e=(new Date).getTime();return t=t.split("?"),n=n?"/"+n:"",t=t[1]?t[0]+n+"?"+t[1]+"&cacheBuster="+e:t[0]+n+"?cacheBuster="+e},onclick:function(t){var e=n(this).parents(".bulkManagerOptions"),i=e.find("select.bulkActionName").val(),o=n(this).parents(".bulkManagerOptions").find("input.bulkSelectAll:first").getSelectRecordsID();this.doBulkAction(i,o)},doBulkAction:function(t,e,i,o){var a=n(this).parents(".bulkManagerOptions"),c=a.find("a.doBulkActionButton"),s=c.data("config"),r=this.getActionURL(t,n(this).data("url")),l={records:e};return e.length<=0?void alert(ss.i18n._t("GRIDFIELD_BULK_MANAGER.BULKACTION_EMPTY_SELECT")):s[t].destructive&&!confirm(ss.i18n._t("GRIDFIELD_BULK_MANAGER.CONFIRM_DESTRUCTIVE_ACTION"))?(i&&o&&i.call(o,!1),!1):(c.addClass("loading"),void(s[t].xhr?n.ajax({url:r,data:l,type:"POST",context:n(this)}).done(function(t,e,a){c.removeClass("loading"),i&&o?i.call(o,t):n(this).parents(".ss-gridfield").entwine(".").entwine("ss").reload()}):(r=r+"&records[]="+e.join("&records[]="),window.location.href=r)))}})})})}(n)}).call(t,e("jquery"))},"./client/src/js/managerBulkEditingForm.js":function(n,t,e){(function(n){!function(n){n.entwine("colymba",function(n){n("#bulkEditToggle").entwine({onmatch:function(){},onunmatch:function(){},onclick:function(t){var e=this.parents("form").find(".ss-toggle .ui-accordion-header"),i=this.data("state");i=i&&"close"!==i?"close":"open",e.each(function(){var t=n(this);"open"!==i||t.hasClass("ui-state-active")||t.click(),"close"===i&&t.hasClass("ui-state-active")&&t.click()}),this.data("state",i)}}),n(".bulkEditingFieldHolder").entwine({onmatch:function(){},onunmatch:function(){},onchange:function(){this.removeClass("updated"),this.hasClass("hasUpdate")||this.addClass("hasUpdate")}})})}(n)}).call(t,e("jquery"))},"./client/src/js/uploader.js":function(n,t,e){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(n){var t=e("lib/Injector"),i=function(t){var e=n("#"+t.fieldId).data("schema");n.ajax(e.data.attachFileEndpoint.url,{method:e.data.attachFileEndpoint.method,data:{fileID:t.file.id}}).done(function(n,t,e){})},o=function(n){return function(t){return function(t,e){var o=e.type,a=e.payload;switch(o){case"UPLOADFIELD_ADD_FILE":return-1!==a.fieldId.indexOf("_BU")&&a.file.id&&i(a),n(t,{type:o,payload:a});default:return n(t,{type:o,payload:a})}}}};e.n(t).a.transform("bulkUploaderCustom",function(n){n.reducer("assetAdmin",o)})}.call(t,e("jquery"))},0:function(n,t,e){e("./client/src/js/manager.js"),e("./client/src/js/managerBulkEditingForm.js"),n.exports=e("./client/src/js/uploader.js")},jquery:function(n,t){n.exports=jQuery},"lib/Injector":function(n,t){n.exports=Injector}}); !function(e){function t(i){if(n[i])return n[i].exports;var s=n[i]={i:i,l:!1,exports:{}};return e[i].call(s.exports,s,s.exports,t),s.l=!0,s.exports}var n={};t.m=e,t.c=n,t.d=function(e,n,i){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:i})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=0)}({"./client/src/js/bulkTools.js":function(e,t,n){(function(e){window.bulkTools={gridfieldRefresh:function(e,t){t.isError||(t.isDestructive?this.removeGridFieldRows(e,t.records.success):this.updateGridFieldRows(e,t.records.success),this.failedGridFieldRows(e,t.records.failed))},getGridFieldRow:function(e,t){return e.find('.ss-gridfield-item[data-id="'+t.id+'"][data-class="'+t.class+'"]')},cleanGridFieldRow:function(e){return e.removeClass("bt-deleted bt-failed bt-updated").removeAttr("bt-error")},removeGridFieldRows:function(e,t){t.forEach(function(t){this.getGridFieldRow(e,t).addClass("bt-deleted").fadeOut(2e3)},this),e.entwine(".").entwine("ss").delay(2e3).reload()},failedGridFieldRows:function(e,t){t.forEach(function(t){this.getGridFieldRow(e,t).addClass("bt-failed").attr("bt-error",t.message)},this)},updateGridFieldRows:function(t,n){t.find(".ss-gridfield-item.ss-gridfield-no-items").remove(),n.forEach(function(n){var i=this.getGridFieldRow(t,n),s=e(n.row).addClass("bt-updated");1===i.length?i.replaceWith(s):t.find(".ss-gridfield-items").prepend(s)},this)}}}).call(t,n("jquery"))},"./client/src/js/manager.js":function(e,t,n){(function(e){!function(e){e.entwine("ss",function(e){e.entwine("colymba",function(e){e(".bulkManagerOptions").entwine({onmatch:function(){var t=this.parents("thead"),n=t.find("tr"),i=[".filter-header",".sortable-header"],s=t.find(i.join(",")),o=n.index(this),a=n.length-1;s.each(function(e,t){var i=n.index(t);i<a&&(a=i)}),o>a&&n.eq(a).insertAfter(e(this))},onunmatch:function(){}}),e("td.col-bulkSelect").entwine({onmatch:function(){},onunmatch:function(){},onmouseover:function(){e(this).parents(".ss-gridfield-item").find(".edit-link").removeClass("edit-link").addClass("tempDisabledEditLink")},onmouseout:function(){e(this).parents(".ss-gridfield-item").find(".tempDisabledEditLink").addClass("edit-link").removeClass("tempDisabledEditLink")},onclick:function(t){var n=e(t.target).find("input");e(n).prop("checked")?e(n).prop("checked",!1):e(n).prop("checked",!0)}}),e("td.col-bulkSelect input").entwine({onmatch:function(){},onunmatch:function(){},onclick:function(t){e(this).parents(".grid-field__table").find("input.bulkSelectAll").prop("checked","")}}),e("input.bulkSelectAll").entwine({onmatch:function(){},onunmatch:function(){},onclick:function(){var t=e(this).prop("checked");e(this).parents(".grid-field__table").find("td.col-bulkSelect input").prop("checked",t).trigger("change")},getSelectRecordsID:function(){return e(this).parents(".grid-field__table").find("td.col-bulkSelect input:checked").map(function(){return parseInt(e(this).data("record"))}).get()}}),e("select.bulkActionName").entwine({onmatch:function(){},onunmatch:function(){},onchange:function(t){var n=e(this).val(),i=e(this).parents(".bulkManagerOptions"),s=i.find(".doBulkActionButton"),o=s.data("config");if(e.each(o,function(e,t){e!=n&&s.removeClass(t.buttonClasses)}),!n)return void s.addClass("disabled");if(s.removeClass("disabled"),s.addClass(o[n].buttonClasses).addClass("btn-outline-secondary"),o[n].icon){var a=s.find("img");a.length?a.attr("src",o[n].icon):s.prepend('<img src="'+o[n].icon+'" alt="" />')}else s.find("img").remove();o[n].destructive?s.addClass("btn-outline-danger"):s.removeClass("btn-outline-danger")}}),e(".doBulkActionButton").entwine({onmatch:function(){},onunmatch:function(){},getActionURL:function(e,t){var n=(new Date).getTime();return t=t.split("?"),e=e?"/"+e:"",t=t[1]?t[0]+e+"?"+t[1]+"&cacheBuster="+n:t[0]+e+"?cacheBuster="+n},onclick:function(t){var n=e(this).parents(".bulkManagerOptions"),i=n.find("select.bulkActionName").val(),s=e(this).parents(".bulkManagerOptions").find("input.bulkSelectAll:first").getSelectRecordsID();this.doBulkAction(i,s)},doBulkAction:function(t,n){var i=e(this).parents(".bulkManagerOptions"),s=i.find("a.doBulkActionButton"),o=i.find(".message"),a=s.data("config"),r=this.getActionURL(t,e(this).data("url")),d={records:n};return n.length<=0?void alert(ss.i18n._t("GRIDFIELD_BULK_MANAGER.BULKACTION_EMPTY_SELECT")):!(a[t].destructive&&!confirm(ss.i18n._t("GRIDFIELD_BULK_MANAGER.CONFIRM_DESTRUCTIVE_ACTION")))&&(s.addClass("loading"),o.removeClass("static show error warning"),a[t].xhr?e.ajax({url:r,data:d,type:"POST",context:e(this)}).always(function(t,n,i){s.removeClass("loading"),t.responseText&&(t=JSON.parse(t.responseText)),o.html(t.message),t.isError?o.addClass("static error"):t.isWarning?o.addClass("show warning"):o.addClass("show"),bulkTools.gridfieldRefresh(e(this).parents(".ss-gridfield"),t)}):(r=r+"&records[]="+n.join("&records[]="),window.location.href=r),void 0)}})})})}(e)}).call(t,n("jquery"))},"./client/src/js/managerBulkEditingForm.js":function(e,t,n){(function(e){!function(e){e.entwine("colymba",function(e){e("#bulkEditToggle").entwine({onmatch:function(){},onunmatch:function(){},onclick:function(t){var n=this.parents("form").find(".ss-toggle .ui-accordion-header"),i=this.data("state");i=i&&"close"!==i?"close":"open",n.each(function(){var t=e(this);"open"!==i||t.hasClass("ui-state-active")||t.click(),"close"===i&&t.hasClass("ui-state-active")&&t.click()}),this.data("state",i)}}),e(".bulkEditingFieldHolder").entwine({onmatch:function(){},onunmatch:function(){},onchange:function(){this.removeClass("updated"),this.hasClass("hasUpdate")||this.addClass("hasUpdate")}})})}(e)}).call(t,n("jquery"))},"./client/src/js/uploader.js":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),function(e){var t=n("lib/Injector"),i=function(t){var n=e("#"+t.fieldId),i=n.parents(".ss-gridfield"),s=n.data("schema");e.ajax(s.data.attachFileEndpoint.url,{method:s.data.attachFileEndpoint.method,data:{fileID:t.file.id}}).done(function(e,t,n){bulkTools.gridfieldRefresh(i,e)})},s=function(t){var n=e("#"+t.fieldId).parents(".ss-gridfield");bulkTools.gridfieldRefresh(n,t.json.bulkTools)},o=function(e){return function(t){return function(t,n){var o=n.type,a=n.payload;switch(o){case"UPLOADFIELD_ADD_FILE":return-1!==a.fieldId.indexOf("_BU")&&a.file.id&&i(a),e(t,{type:o,payload:a});case"UPLOADFIELD_UPLOAD_SUCCESS":return-1!==a.fieldId.indexOf("_BU")&&s(a),e(t,{type:o,payload:a});default:return e(t,{type:o,payload:a})}}}};n.n(t).a.transform("bulkUploaderTransformation",function(e){e.reducer("assetAdmin",o)})}.call(t,n("jquery"))},0:function(e,t,n){n("./client/src/js/bulkTools.js"),n("./client/src/js/manager.js"),n("./client/src/js/managerBulkEditingForm.js"),e.exports=n("./client/src/js/uploader.js")},jquery:function(e,t){e.exports=jQuery},"lib/Injector":function(e,t){e.exports=Injector}});

1
client/dist/js/main.js.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["webpack:///webpack/bootstrap 7b8a3a564178b2753754","webpack:///./client/src/js/bulkTools.js","webpack:///./client/src/js/manager.js","webpack:///./client/src/js/managerBulkEditingForm.js","webpack:///./client/src/js/uploader.js","webpack:///external \"jQuery\"","webpack:///external \"Injector\""],"names":["window","bulkTools","gridfieldRefresh","$gridfield","data","isError","isDestructive","removeGridFieldRows","records","success","updateGridFieldRows","failedGridFieldRows","failed","getGridFieldRow","record","find","id","class","cleanGridFieldRow","$row","removeClass","removeAttr","forEach","addClass","fadeOut","entwine","delay","reload","attr","message","remove","$newRow","$","row","length","replaceWith","prepend","onmatch","$parent","parents","$tr","targets","$target","join","index","newIndex","each","Element","idx","eq","insertAfter","onunmatch","onmouseover","onmouseout","onclick","e","cb","target","prop","state","trigger","getSelectRecordsID","map","parseInt","get","onchange","value","val","$btn","config","configKey","configData","$img","getActionURL","action","url","cacheBuster","Date","getTime","split","ids","doBulkAction","$msg","alert","ss","i18n","_t","confirm","ajax","type","context","always","textStatus","jqXHR","responseText","JSON","parse","html","isWarning","location","href","jQuery","toggleFields","$this","hasClass","click","bulkUploadFieldAttach","payload","$uploadField","fieldId","schema","attachFileEndpoint","method","fileID","file","done","bulkUploadFieldUpload","json","bulkUploadFieldReducer","originalReducer","globalState","indexOf","Injector","transform","updater","reducer"],"mappings":"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","file":"js/main.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 7b8a3a564178b2753754","/**\n * Handles Gridfield updates after a bulk action/upload\n */\nwindow.bulkTools = {\n \n gridfieldRefresh: function ($gridfield, data) {\n if (!data.isError) {\n if (data.isDestructive) {\n this.removeGridFieldRows($gridfield, data.records.success);\n } else {\n this.updateGridFieldRows($gridfield, data.records.success);\n }\n //failed rows\n this.failedGridFieldRows($gridfield, data.records.failed);\n }\n },\n\n // return the gridfield row node for a specific record\n getGridFieldRow: function ($gridfield, record) {\n return $gridfield.find('.ss-gridfield-item[data-id=\"'+record.id+'\"][data-class=\"'+record.class+'\"]');\n },\n\n // remove all bulk tools class and attributes from the row\n cleanGridFieldRow: function ($row) {\n return $row.removeClass('bt-deleted bt-failed bt-updated').removeAttr('bt-error');\n },\n\n // mark all affected gridfield rows as deleted\n removeGridFieldRows: function ($gridfield, records) {\n records.forEach(function(record){\n var $row = this.getGridFieldRow($gridfield, record);\n $row.addClass('bt-deleted').fadeOut(2000);\n }, this);\n $gridfield.entwine('.').entwine('ss').delay(2000).reload();\n },\n\n // mark all affected gridfield rows as failed\n failedGridFieldRows: function ($gridfield, records) {\n records.forEach(function(record){\n var $row = this.getGridFieldRow($gridfield, record);\n $row.addClass('bt-failed').attr('bt-error', record.message);\n //pseudo element absolute pos don't work in TR, so we'll have to find some JS way to show the bt-error content..\n }, this);\n },\n\n // update rows with new content\n updateGridFieldRows: function ($gridfield, records) {\n $gridfield.find('.ss-gridfield-item.ss-gridfield-no-items').remove();\n records.forEach(function(record){\n var $row = this.getGridFieldRow($gridfield, record);\n var $newRow = $(record.row).addClass('bt-updated');\n //replace existing or add new?\n if ($row.length === 1) {\n $row.replaceWith($newRow);\n } else {\n $gridfield.find('.ss-gridfield-items').prepend($newRow);\n } \n }, this);\n },\n\n //removes an item from the upload item\n //this is bad! can't dispatch within Reducer\n //so it's commentted until actions are written\n /*\n removeUploadItem: function ($gridfield, queueIndex, fileID)\n {\n //we use queueIndex for uploads since the input value will not have been changed yet and we can't watch for change event on hidden input\n if (fileID) {\n $gridfield.find('.uploadfield-item').find('input[value=\"'+fileID+'\"]').siblings('button.uploadfield-item__remove-btn').trigger('click');\n } else if (queueIndex) {\n $gridfield.find('.uploadfield-item').eq(queueIndex-1).find('button.uploadfield-item__remove-btn').trigger('click');\n }\n }*/\n}\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/js/bulkTools.js","(function($) {\n\t$.entwine('ss', function($) {\n\n\t\t$.entwine('colymba', function($) {\n\n\t\t\t/**\n * Makes sure the component is above the headers\n */\n $('.bulkManagerOptions').entwine({\n onmatch: function(){\n var $parent = this.parents('thead'),\n \t\t$tr = $parent.find('tr'),\n\n \t\ttargets = ['.filter-header', '.sortable-header'],\n \t\t$target = $parent.find(targets.join(',')),\n\n index = $tr.index(this),\n newIndex = $tr.length - 1\n ;\n\n $target.each(function(index, Element){\n \tvar idx = $tr.index(Element);\n \tif ( idx < newIndex )\n \t{\n \t\tnewIndex = idx;\n \t}\n });\n\n if ( index > newIndex )\n {\n $tr.eq(newIndex).insertAfter($(this));\n }\n },\n onunmatch: function(){}\n });\n\n\n\t\t /**\n\t\t * Bulkselect table cell behaviours\n\t\t */\n\t\t\t$('td.col-bulkSelect').entwine({\n\t\t\t\tonmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t\t\t\tonmouseover: function(){\n\t\t\t\t\t//disable default row click behaviour -> avoid navigation to edit form when clicking the checkbox\n\t $(this).parents('.ss-gridfield-item').find('.edit-link').removeClass('edit-link').addClass('tempDisabledEditLink');\n\t\t\t\t},\n\t\t\t\tonmouseout: function(){\n\t\t\t\t\t//re-enable default row click behaviour\n\t\t\t\t\t$(this).parents('.ss-gridfield-item').find('.tempDisabledEditLink').addClass('edit-link').removeClass('tempDisabledEditLink');\n\t\t\t\t},\n\t\t\t\tonclick: function(e) {\n\t\t\t\t\t//check/uncheck checkbox when clicking cell\n\t\t\t\t\tvar cb = $(e.target).find('input');\n\t\t\t\t\tif ( !$(cb).prop('checked') ) $(cb).prop('checked', true);\n\t\t\t\t\telse $(cb).prop('checked', false);\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t\t/**\n\t\t\t * Individual select checkbox behaviour\n\t\t\t */\n\t\t\t$('td.col-bulkSelect input').entwine({\n\t\t\t\tonmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t\t\t\tonclick: function(e) {\n\t\t\t\t\t$(this).parents('.grid-field__table').find('input.bulkSelectAll').prop('checked', '');\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t\t/**\n\t\t\t * Bulkselect checkbox behaviours\n\t\t\t */\n\t $('input.bulkSelectAll').entwine({\n\t onmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t onclick: function()\n\t {\n\t var state = $(this).prop('checked');\n\t $(this).parents('.grid-field__table')\n\t \t\t\t .find('td.col-bulkSelect input')\n\t \t\t\t .prop('checked', state)\n\t \t\t\t .trigger('change');\n\t },\n\t getSelectRecordsID: function()\n\t {\n\t \treturn $(this).parents('.grid-field__table')\n\t\t\t\t\t \t\t\t\t.find('td.col-bulkSelect input:checked')\n\t\t\t\t\t \t\t\t\t.map(function() {\n\t\t\t\t\t \t\t\t\t\treturn parseInt( $(this).data('record') )\n\t\t\t\t\t \t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\t .get();\n\t }\n\t });\n\n\n\t /**\n\t * Bulk action dropdown behaviours\n\t */\n\t\t\t$('select.bulkActionName').entwine({\n\t\t\t\tonmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t\t\t\tonchange: function(e)\n\t\t\t\t{\n\t\t\t\t\tvar value = $(this).val(),\n\t\t\t\t\t\t$parent = $(this).parents('.bulkManagerOptions'),\n\t\t\t\t\t\t$btn = $parent.find('.doBulkActionButton'),\n\t\t\t\t\t\tconfig = $btn.data('config');\n\n\t\t\t\t\t$.each( config, function( configKey, configData )\n\t\t\t\t\t{\n\t\t\t\t\t\tif ( configKey != value )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$btn.removeClass(configData['buttonClasses']);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\t\tif(!value)\n\t\t\t\t\t{\n\t\t\t\t\t\t$btn.addClass('disabled');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t$btn.removeClass('disabled');\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t$btn.addClass(config[value]['buttonClasses']).addClass('btn-outline-secondary');\n\n\n\t\t\t\t\tif ( config[value]['icon'] )\n\t\t\t\t\t{\n\t\t\t\t\t\tvar $img = $btn.find('img');\n\n\t\t\t\t\t\tif ($img.length)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\t$img.attr('src', config[value]['icon']);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse{\n\t\t\t\t\t\t\t$btn.prepend('<img src=\"'+config[value]['icon']+'\" alt=\"\" />');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\t$btn.find('img').remove();\n\t\t\t\t\t}\n\n\n\t\t\t\t\tif ( config[value]['destructive'] )\n\t\t\t\t\t{\n\t\t\t\t\t\t$btn.addClass('btn-outline-danger');\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\t$btn.removeClass('btn-outline-danger');\n\t\t\t\t\t}\n\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t\t/**\n\t\t\t * bulk action button behaviours\n\t\t\t */\n\t\t\t$('.doBulkActionButton').entwine({\n\t\t\t\tonmatch: function(){\n\t\t\t\t},\n\t\t\t\tonunmatch: function(){\n\t\t\t\t},\n\t\t\t\tgetActionURL: function(action, url)\n\t\t\t\t{\n\t\t\t\t\tvar cacheBuster = new Date().getTime();\n\t\t\t\t\turl = url.split('?');\n\n\t\t\t\t\tif ( action )\n\t\t\t\t\t{\n\t\t\t\t\t\taction = '/' + action;\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\taction = '';\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( url[1] )\n\t\t\t\t\t{\n\t\t\t\t\t\turl = url[0] + action + '?' + url[1] + '&' + 'cacheBuster=' + cacheBuster;\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\turl = url[0] + action + '?' + 'cacheBuster=' + cacheBuster;\n\t\t\t\t\t}\n\t\t\t\t\treturn url;\n\t\t\t\t},\n\t\t\t\tonclick: function(e)\n\t\t\t\t{\n var $parent = $(this).parents('.bulkManagerOptions'),\n action = $parent.find('select.bulkActionName').val(),\n ids = $(this).parents('.bulkManagerOptions').find('input.bulkSelectAll:first').getSelectRecordsID()\n\t\t\t\t\t\t\t;\n\n\t\t\t\t\tthis.doBulkAction(action, ids);\n\t\t\t\t},\n\n\t\t\t\tdoBulkAction: function(action, ids)\n\t\t\t\t{\n var $parent = $(this).parents('.bulkManagerOptions'),\n $btn = $parent.find('a.doBulkActionButton'),\n $msg = $parent.find('.message'),\n\n config = $btn.data('config'),\n url = this.getActionURL(action, $(this).data('url')),\n data = { records: ids }\n\t\t\t\t\t\t\t;\n\n\t\t\t\t\tif ( ids.length <= 0 )\n\t\t\t\t\t{\n\t\t\t\t\t\talert( ss.i18n._t('GRIDFIELD_BULK_MANAGER.BULKACTION_EMPTY_SELECT') );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t//if ( $btn.hasClass('ss-ui-action-destructive') )\n\t\t\t\t\tif ( config[action]['destructive'] )\n\t\t\t\t\t{\n\t\t\t\t\t\tif( !confirm(ss.i18n._t('GRIDFIELD_BULK_MANAGER.CONFIRM_DESTRUCTIVE_ACTION')) )\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t$btn.addClass('loading');\n\t\t\t\t\t$msg.removeClass('static show error warning');\n\n\t\t\t\t\tif ( config[action]['xhr'] )\n\t\t\t\t\t{\n\t\t\t\t\t\t$.ajax({\n\t\t\t\t\t\t\turl: url,\n\t\t\t\t\t\t\tdata: data,\n\t\t\t\t\t\t\ttype: \"POST\",\n\t\t\t\t\t\t\tcontext: $(this)\n\t\t\t\t\t\t}).always(function(data, textStatus, jqXHR) {\n\t\t\t\t\t\t\t$btn.removeClass('loading');\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t//if request fail, return a +4xx status code, extract json response\n\t\t\t\t\t\t\tif (data.responseText) {\n\t\t\t\t\t\t\t\tdata = JSON.parse(data.responseText);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t$msg.html(data.message);\n\n\t\t\t\t\t\t\tif(data.isError) {\n\t\t\t\t\t\t\t\t$msg.addClass('static error');\n\t\t\t\t\t\t\t} else if (data.isWarning) {\n\t\t\t\t\t\t\t\t$msg.addClass('show warning');\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t$msg.addClass('show');\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tbulkTools.gridfieldRefresh($(this).parents('.ss-gridfield'), data);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\telse{\n\t\t\t\t\t\tvar records = 'records[]='+ids.join('&records[]=');\n\t\t\t\t\t\turl = url + '&' + records;\n\n\t\t\t\t\t\twindow.location.href = url;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\n\n\t\t});\n\t});\n}(jQuery));\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/js/manager.js","(function($) {\n $.entwine('colymba', function($) {\n\n /**\n * Toggle all accordion forms\n * open or closed\n */\n $('#bulkEditToggle') .entwine({\n onmatch: function(){},\n onunmatch: function(){},\n onclick: function(e)\n {\n var toggleFields = this.parents('form').find('.ss-toggle .ui-accordion-header'),\n state = this.data('state')\n ;\n\n if ( !state || state === 'close' )\n {\n state = 'open';\n }\n else {\n state = 'close';\n }\n\n toggleFields.each(function()\n {\n var $this = $(this);\n \n if ( state === 'open' && !$this.hasClass('ui-state-active') )\n {\n $this.click();\n }\n\n if ( state === 'close' && $this.hasClass('ui-state-active') )\n {\n $this.click();\n } \n });\n\n this.data('state', state);\n }\n });\n \n \n /**\n * Contains each rocrds editing fields,\n * tracks changes and updates...\n */\n $('.bulkEditingFieldHolder').entwine({\n onmatch: function(){},\n onunmatch: function(){},\n onchange: function(){\n this.removeClass('updated');\n if ( !this.hasClass('hasUpdate') )\n {\n this.addClass('hasUpdate');\n }\n }\n });\n \n });\n}(jQuery));\n\n\n// WEBPACK FOOTER //\n// ./client/src/js/managerBulkEditingForm.js","/**\n * A quick hack to catch the uploadfield add file event\n * and send the file ID to the bulkUploader component\n */\nimport Injector from 'lib/Injector';\n\n\nconst bulkUploadFieldAttach = (payload) => {\n const $uploadField = jQuery('#'+payload.fieldId);\n\tconst $gridfield = $uploadField.parents('.ss-gridfield');\n const schema = $uploadField.data('schema');\n\tjQuery.ajax(schema.data.attachFileEndpoint.url, {\n\t method: schema.data.attachFileEndpoint.method, //doesn't seem to change anything\n\t data: {\n\t \tfileID: payload.file.id\n\t }\n\t}).done(function( data, textStatus, jqXHR ) {\n\t bulkTools.gridfieldRefresh($gridfield, data);\n //bulkTools.removeUploadItem($gridfield, null, payload.file.id);//bad! can't dispath in Reducer\n\t});\n}\n\nconst bulkUploadFieldUpload = (payload) => {\n const $gridfield = jQuery('#'+payload.fieldId).parents('.ss-gridfield');\n bulkTools.gridfieldRefresh($gridfield, payload.json.bulkTools);\n //bulkTools.removeUploadItem($gridfield, payload.queuedId, null);//bad! can't dispath in Reducer\n}\n\nconst bulkUploadFieldReducer = (originalReducer) => (globalState) => (state, { type, payload }) => {\n switch (type) {\n case 'UPLOADFIELD_ADD_FILE': {\n // Needs to be a bulk upload field and have a file ID (no file ID = normal)\n if (payload.fieldId.indexOf('_BU') !== -1 && payload.file.id)\n {\n \tbulkUploadFieldAttach(payload);\n }\n return originalReducer(state, { type, payload });\n }\n\n case 'UPLOADFIELD_UPLOAD_SUCCESS': {\n //check if this is a bulk upload\n if (payload.fieldId.indexOf('_BU') !== -1)\n {\n bulkUploadFieldUpload(payload);\n }\n return originalReducer(state, { type, payload });\n }\n\n default: {\n return originalReducer(state, { type, payload });\n }\n }\n}\n\nInjector.transform('bulkUploaderTransformation', (updater) => {\n updater.reducer('assetAdmin', bulkUploadFieldReducer);\n});\n\n\n// WEBPACK FOOTER //\n// ./client/src/js/uploader.js","module.exports = jQuery;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"jQuery\"\n// module id = jquery\n// module chunks = 0","module.exports = Injector;\n\n\n//////////////////\n// WEBPACK FOOTER\n// external \"Injector\"\n// module id = lib/Injector\n// module chunks = 0"],"sourceRoot":""}

View File

@ -1 +1 @@
.cms table.grid-field__table tr.bulkManagerOptions th{text-transform:none}.cms table.grid-field__table tr.bulkManagerOptions th .bulkActionName{float:left}.cms table.grid-field__table tr.bulkManagerOptions th .bulkActionName .form__field-holder{min-width:200px;margin-left:0}.cms table.grid-field__table tr.bulkManagerOptions th .bulkActionName .chosen-container{min-width:120px}.cms table.grid-field__table tr.bulkManagerOptions th .bulkActionName .chosen-container-single .chosen-single{border-top-right-radius:0;border-bottom-right-radius:0}.cms table.grid-field__table tr.bulkManagerOptions th .doBulkActionButton{border-top-left-radius:0;border-bottom-left-radius:0;height:36px;line-height:26px;margin-left:-1px}.cms table.grid-field__table tr.bulkManagerOptions th .doBulkActionButton img{height:20px}.cms table.grid-field__table tbody .col-bulkSelect{width:25px;text-align:center}#bulkEditHeader{float:left;width:70%;margin:40px 0 20px;font-size:30px;font-weight:700}#bulkEditToggle{float:right;clear:right;width:25%;margin:40px 0 20px;text-decoration:underline;text-align:right;cursor:pointer}.bulkEditingFieldHolder{position:relative;float:left;width:100%}.bulkEditingFieldHolder.hasUpdate .ui-accordion-header{background-color:#f2ba11;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0,#f2ba11),color-stop(100%,#df6e00));background-image:-webkit-linear-gradient(top,#f2ba11,#df6e00);background-image:-o-linear-gradient(top,#f2ba11 0,#df6e00 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2ba11),to(#df6e00));background-image:linear-gradient(top,#f2ba11,#df6e00)}.bulkEditingFieldHolder.hasUpdate .ui-accordion-header a{color:#fff;text-shadow:none}.bulkEditingFieldHolder.updated .ui-accordion-header{background-color:#a4ca3a;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0,#a4ca3a),color-stop(100%,#59781d));background-image:-webkit-linear-gradient(top,#a4ca3a,#59781d);background-image:-o-linear-gradient(top,#a4ca3a 0,#59781d 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(top),color-stop(0,#a4ca3a),to(#59781d));background-image:linear-gradient(top,#a4ca3a,#59781d)}.bulkEditingFieldHolder.updated .ui-accordion-header a{color:#fff;text-shadow:none}.bulkUploader .uploadfield__droptext:before{text-transform:none;content:"b"} @-webkit-keyframes bt_fade_out{0%{opacity:1}to{opacity:0}}@-o-keyframes bt_fade_out{0%{opacity:1}to{opacity:0}}@keyframes bt_fade_out{0%{opacity:1}to{opacity:0}}@-webkit-keyframes bt_loading{0%{opacity:1}to{opacity:.25}}@-o-keyframes bt_loading{0%{opacity:1}to{opacity:.25}}@keyframes bt_loading{0%{opacity:1}to{opacity:.25}}@-webkit-keyframes bt_fade_border{0%{border-left-width:6px}to{border-left-width:0}}@-o-keyframes bt_fade_border{0%{border-left-width:6px}to{border-left-width:0}}@keyframes bt_fade_border{0%{border-left-width:6px}to{border-left-width:0}}.cms table.grid-field__table tr.bulkManagerOptions th{text-transform:none}.cms table.grid-field__table tr.bulkManagerOptions th .bulkActionName{float:left}.cms table.grid-field__table tr.bulkManagerOptions th .bulkActionName .form__field-holder{min-width:200px;margin-left:0}.cms table.grid-field__table tr.bulkManagerOptions th .bulkActionName .chosen-container{min-width:120px}.cms table.grid-field__table tr.bulkManagerOptions th .bulkActionName .chosen-container-single .chosen-single{border-top-right-radius:0;border-bottom-right-radius:0}.cms table.grid-field__table tr.bulkManagerOptions th .doBulkActionButton{float:left;border-top-left-radius:0;border-bottom-left-radius:0;height:36px;line-height:26px;margin-left:-1px;margin-right:20px}.cms table.grid-field__table tr.bulkManagerOptions th .doBulkActionButton img{height:20px}.cms table.grid-field__table tr.bulkManagerOptions th .doBulkActionButton.loading{-webkit-animation:.5s bt_loading infinite alternate;-o-animation:.5s bt_loading infinite alternate;animation:.5s bt_loading infinite alternate;cursor:wait;pointer-events:none}.cms table.grid-field__table tr.bulkManagerOptions th .message{float:left;clear:none;max-width:100%;margin:0;padding:0 1.25rem;height:36px;line-height:34px;opacity:0;overflow:auto}.cms table.grid-field__table tr.bulkManagerOptions th .message.show{-webkit-animation:10s bt_fade_out;-o-animation:10s bt_fade_out;animation:10s bt_fade_out}.cms table.grid-field__table tr.bulkManagerOptions th .message.static{opacity:1}.cms table.grid-field__table tbody .col-bulkSelect{width:25px;text-align:center}.cms table.grid-field__table tbody .ss-gridfield-item.bt-deleted{opacity:.5}.cms table.grid-field__table tbody .ss-gridfield-item.bt-failed{border-left:0 solid #e68288;-webkit-animation:10s bt_fade_border;-o-animation:10s bt_fade_border;animation:10s bt_fade_border}.cms table.grid-field__table tbody .ss-gridfield-item.bt-updated{border-left:0 solid #56bd59;-webkit-animation:10s bt_fade_border;-o-animation:10s bt_fade_border;animation:10s bt_fade_border}#bulkEditHeader{float:left;width:70%;margin:40px 0 20px;font-size:30px;font-weight:700}#bulkEditToggle{float:right;clear:right;width:25%;margin:40px 0 20px;text-decoration:underline;text-align:right;cursor:pointer}.bulkEditingFieldHolder{position:relative;float:left;width:100%}.bulkEditingFieldHolder.hasUpdate .ui-accordion-header{background-color:#f2ba11;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0,#f2ba11),color-stop(100%,#df6e00));background-image:-webkit-linear-gradient(top,#f2ba11,#df6e00);background-image:-o-linear-gradient(top,#f2ba11 0,#df6e00 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2ba11),to(#df6e00));background-image:linear-gradient(top,#f2ba11,#df6e00)}.bulkEditingFieldHolder.hasUpdate .ui-accordion-header a{color:#fff;text-shadow:none}.bulkEditingFieldHolder.updated .ui-accordion-header{background-color:#a4ca3a;background-image:-webkit-gradient(linear,50% 0,50% 100%,color-stop(0,#a4ca3a),color-stop(100%,#59781d));background-image:-webkit-linear-gradient(top,#a4ca3a,#59781d);background-image:-o-linear-gradient(top,#a4ca3a 0,#59781d 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(top),color-stop(0,#a4ca3a),to(#59781d));background-image:linear-gradient(top,#a4ca3a,#59781d)}.bulkEditingFieldHolder.updated .ui-accordion-header a{color:#fff;text-shadow:none}.bulkUploader .uploadfield__droptext:before{text-transform:none;content:"b"}

1
client/dist/styles/main.css.map vendored Normal file
View File

@ -0,0 +1 @@
{"version":3,"sources":["webpack:///./client/src/styles/manager.scss","webpack:///./client/src/styles/managerBulkEditingForm.scss","webpack:///./client/src/styles/uploader.scss"],"names":[],"mappings":"AAAA,+BACE,GACE,UAGF,GACE,UACD,CACF,0BAPC,GACE,UAGF,GACE,UACD,CACF,uBAPC,GACE,UAGF,GACE,UACD,CAGH,8BACE,GACE,UAGF,GACE,YACD,CACF,yBAPC,GACE,UAGF,GACE,YACD,CACF,sBAPC,GACE,UAGF,GACE,YACD,CAGH,kCACE,GACE,sBAGF,GACE,oBACD,CACF,6BAPC,GACE,sBAGF,GACE,oBACD,CACF,0BAPC,GACE,sBAGF,GACE,oBACD,CAGH,sDAMM,oBAJL,sEAQO,WAJP,0FAQS,gBACA,cAJT,wFASS,gBALT,8GAUS,0BACA,6BANT,0EAYO,WACA,yBACA,4BAEA,YACA,iBACA,iBACA,kBATP,8EAaS,YATT,kFAcS,+IACA,YACA,oBAIJ,+DAEE,WACA,WACA,eAEA,SACA,kBAEA,YACA,iBAEA,UACA,cAfP,oEAmBS,yFAfT,sEAoBS,UAhBT,mDA8BK,WACA,kBAGF,iEAII,WA7BP,gEAkCO,4BACA,kGAVJ,iEAcI,4BACA,kGC1IR,gBAEC,WACA,UAEA,mBAEA,eACA,gBAGD,gBAEC,YACA,YACA,UAEA,mBAEA,0BACA,iBACA,eAGD,wBAEC,kBACA,WACA,WAJD,uDAQE,yBAEA,wGACA,8DAEA,gEAEA,+IAEA,yDAEC,WACA,iBARF,qDAcC,yBAEA,wGACA,8DAEA,gEAEA,iKAEA,uDAEC,WACA,iBC7DF,4CAIE,oBACA","file":"styles/main.css","sourcesContent":["@keyframes bt_fade_out {\n from {\n opacity: 1; \n }\n\n to {\n opacity: 0;\n }\n}\n\n@keyframes bt_loading {\n from {\n opacity: 1; \n }\n\n to {\n opacity: .25;\n }\n}\n\n@keyframes bt_fade_border {\n from {\n border-left-width: 6px; \n }\n\n to {\n border-left-width: 0;\n }\n}\n\n.cms table.grid-field__table\n{\n tr.bulkManagerOptions\n {\n th\n {\n text-transform: none;\n\n .bulkActionName\n {\n float: left;\n\n .form__field-holder\n {\n min-width: 200px;\n margin-left: 0;\n }\n\n .chosen-container\n {\n min-width: 120px;\n }\n\n .chosen-container-single .chosen-single\n {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n }\n }\n\n .doBulkActionButton\n {\n float: left;\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n\n height: 36px;\n line-height: 26px;\n margin-left: -1px;\n margin-right: 20px;\n\n img\n {\n height: 20px;\n }\n\n &.loading\n {\n animation: .5s bt_loading infinite alternate;\n cursor: wait;\n pointer-events: none;\n }\n }\n\n .message\n {\n float: left;\n clear: none;\n max-width: 100%;\n\n margin: 0;\n padding: 0 1.25rem;\n\n height: 36px;\n line-height: 34px;\n\n opacity: 0;\n overflow: auto;\n\n &.show\n {\n animation: 10s bt_fade_out;\n }\n\n &.static\n {\n opacity: 1;\n }\n }\n\n .bulkSelectAll\n {\n }\n }\n }// .bulkManagerOptions\n\n tbody\n {\n .col-bulkSelect\n {\n width: 25px;\n text-align: center;\n }\n\n .ss-gridfield-item\n {\n &.bt-deleted\n {\n opacity: .5;\n }\n\n &.bt-failed\n {\n border-left: 0 solid #e68288;\n animation: 10s bt_fade_border;\n }\n &.bt-updated\n {\n border-left: 0 solid #56bd59;\n animation: 10s bt_fade_border;\n }\n }\n }\n}\n\n\n\n// WEBPACK FOOTER //\n// ./client/src/styles/manager.scss","\n#bulkEditHeader\n{\n\tfloat: left;\n\twidth: 70%;\n\n\tmargin: 40px 0 20px 0;\n\n\tfont-size: 30px;\n\tfont-weight: bold;\n}\n\n#bulkEditToggle\n{\n\tfloat: right;\n\tclear: right;\n\twidth: 25%;\n\n\tmargin: 40px 0 20px 0;\n\n\ttext-decoration: underline;\n\ttext-align: right;\n\tcursor: pointer;\n}\n\n.bulkEditingFieldHolder\n{\n\tposition: relative;\n\tfloat: left;\n\twidth: 100%;\n\n\t&.hasUpdate .ui-accordion-header\n\t{\n\t\tbackground-color: #f2ba11;\n\t\t\n\t\tbackground-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #f2ba11), color-stop(100%, #df6e00));\n\t\tbackground-image: -webkit-linear-gradient(top, #f2ba11 0%, #df6e00 100%);\n\t\tbackground-image: -moz-linear-gradient(top, #f2ba11 0%, #df6e00 100%);\n\t\tbackground-image: -o-linear-gradient(top, #f2ba11 0%, #df6e00 100%);\n\t\tbackground-image: -ms-linear-gradient(top, #f2ba11 0%, #df6e00 100%);\n\t\tbackground-image: linear-gradient(top, #f2ba11 0%, #df6e00 100%);\n\n\t\ta\n\t\t{\n\t\t\tcolor: #fff;\n\t\t\ttext-shadow: none;\n\t\t}\n\t}\n\n\t&.updated .ui-accordion-header\n\t{\n\t\tbackground-color: #a4ca3a;\n\t\t\n\t\tbackground-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #a4ca3a), color-stop(100%, #59781D));\n\t\tbackground-image: -webkit-linear-gradient(top, #a4ca3a 0%, #59781D 100%);\n\t\tbackground-image: -moz-linear-gradient(top, #a4ca3a 0%, #59781D 100%);\n\t\tbackground-image: -o-linear-gradient(top, #a4ca3a 0%, #59781D 100%);\n\t\tbackground-image: -ms-linear-gradient(top, #a4ca3a 0%, #59781D 100%);\n\t\tbackground-image: linear-gradient(top, #a4ca3a 0%, #59781D 100%);\n\n\t\ta\n\t\t{\n\t\t\tcolor: #fff;\n\t\t\ttext-shadow: none;\n\t\t}\n\t}\n}\n\n\n// WEBPACK FOOTER //\n// ./client/src/styles/managerBulkEditingForm.scss",".bulkUploader\n{\n\t.uploadfield__droptext\n\t{\n\t\t&::before\n\t\t{\n\t\t\ttext-transform: none;\n\t\t\tcontent: \"b\";\n\t\t}\n\t}\n}\n\n\n// WEBPACK FOOTER //\n// ./client/src/styles/uploader.scss"],"sourceRoot":""}

View File

@ -0,0 +1,74 @@
/**
* Handles Gridfield updates after a bulk action/upload
*/
window.bulkTools = {
gridfieldRefresh: function ($gridfield, data) {
if (!data.isError) {
if (data.isDestructive) {
this.removeGridFieldRows($gridfield, data.records.success);
} else {
this.updateGridFieldRows($gridfield, data.records.success);
}
//failed rows
this.failedGridFieldRows($gridfield, data.records.failed);
}
},
// return the gridfield row node for a specific record
getGridFieldRow: function ($gridfield, record) {
return $gridfield.find('.ss-gridfield-item[data-id="'+record.id+'"][data-class="'+record.class+'"]');
},
// remove all bulk tools class and attributes from the row
cleanGridFieldRow: function ($row) {
return $row.removeClass('bt-deleted bt-failed bt-updated').removeAttr('bt-error');
},
// mark all affected gridfield rows as deleted
removeGridFieldRows: function ($gridfield, records) {
records.forEach(function(record){
var $row = this.getGridFieldRow($gridfield, record);
$row.addClass('bt-deleted').fadeOut(2000);
}, this);
$gridfield.entwine('.').entwine('ss').delay(2000).reload();
},
// mark all affected gridfield rows as failed
failedGridFieldRows: function ($gridfield, records) {
records.forEach(function(record){
var $row = this.getGridFieldRow($gridfield, record);
$row.addClass('bt-failed').attr('bt-error', record.message);
//pseudo element absolute pos don't work in TR, so we'll have to find some JS way to show the bt-error content..
}, this);
},
// update rows with new content
updateGridFieldRows: function ($gridfield, records) {
$gridfield.find('.ss-gridfield-item.ss-gridfield-no-items').remove();
records.forEach(function(record){
var $row = this.getGridFieldRow($gridfield, record);
var $newRow = $(record.row).addClass('bt-updated');
//replace existing or add new?
if ($row.length === 1) {
$row.replaceWith($newRow);
} else {
$gridfield.find('.ss-gridfield-items').prepend($newRow);
}
}, this);
},
//removes an item from the upload item
//this is bad! can't dispatch within Reducer
//so it's commentted until actions are written
/*
removeUploadItem: function ($gridfield, queueIndex, fileID)
{
//we use queueIndex for uploads since the input value will not have been changed yet and we can't watch for change event on hidden input
if (fileID) {
$gridfield.find('.uploadfield-item').find('input[value="'+fileID+'"]').siblings('button.uploadfield-item__remove-btn').trigger('click');
} else if (queueIndex) {
$gridfield.find('.uploadfield-item').eq(queueIndex-1).find('button.uploadfield-item__remove-btn').trigger('click');
}
}*/
}

View File

@ -206,10 +206,11 @@
this.doBulkAction(action, ids); this.doBulkAction(action, ids);
}, },
doBulkAction: function(action, ids, callbackFunction, callbackContext) doBulkAction: function(action, ids)
{ {
var $parent = $(this).parents('.bulkManagerOptions'), var $parent = $(this).parents('.bulkManagerOptions'),
$btn = $parent.find('a.doBulkActionButton'), $btn = $parent.find('a.doBulkActionButton'),
$msg = $parent.find('.message'),
config = $btn.data('config'), config = $btn.data('config'),
url = this.getActionURL(action, $(this).data('url')), url = this.getActionURL(action, $(this).data('url')),
@ -227,15 +228,12 @@
{ {
if( !confirm(ss.i18n._t('GRIDFIELD_BULK_MANAGER.CONFIRM_DESTRUCTIVE_ACTION')) ) if( !confirm(ss.i18n._t('GRIDFIELD_BULK_MANAGER.CONFIRM_DESTRUCTIVE_ACTION')) )
{ {
if ( callbackFunction && callbackContext )
{
callbackFunction.call(callbackContext, false);
}
return false; return false;
} }
} }
$btn.addClass('loading'); $btn.addClass('loading');
$msg.removeClass('static show error warning');
if ( config[action]['xhr'] ) if ( config[action]['xhr'] )
{ {
@ -244,15 +242,25 @@
data: data, data: data,
type: "POST", type: "POST",
context: $(this) context: $(this)
}).done(function(data, textStatus, jqXHR) { }).always(function(data, textStatus, jqXHR) {
$btn.removeClass('loading'); $btn.removeClass('loading');
if ( callbackFunction && callbackContext )
{ //if request fail, return a +4xx status code, extract json response
callbackFunction.call(callbackContext, data); if (data.responseText) {
data = JSON.parse(data.responseText);
} }
else{
$(this).parents('.ss-gridfield').entwine('.').entwine('ss').reload(); $msg.html(data.message);
if(data.isError) {
$msg.addClass('static error');
} else if (data.isWarning) {
$msg.addClass('show warning');
} else {
$msg.addClass('show');
} }
bulkTools.gridfieldRefresh($(this).parents('.ss-gridfield'), data);
}); });
} }
else{ else{

View File

@ -1,22 +1,32 @@
/** /**
* A quick hack to catch the uploadfield add file event * A quick hack to catch the uploadfield add file event
* and send the file ID to the bulkUploader component * and send the file ID to the bulkUploader component
* @todo write actions
*/ */
import Injector from 'lib/Injector'; import Injector from 'lib/Injector';
const bulkUploadFieldAttach = (payload) => { const bulkUploadFieldAttach = (payload) => {
const schema = jQuery('#'+payload.fieldId).data('schema'); const $uploadField = jQuery('#'+payload.fieldId);
const $gridfield = $uploadField.parents('.ss-gridfield');
const schema = $uploadField.data('schema');
jQuery.ajax(schema.data.attachFileEndpoint.url, { jQuery.ajax(schema.data.attachFileEndpoint.url, {
method: schema.data.attachFileEndpoint.method, //doesn't seem to change anything method: schema.data.attachFileEndpoint.method, //doesn't seem to change anything
data: { data: {
fileID: payload.file.id fileID: payload.file.id
} }
}).done(function( data, textStatus, jqXHR ) { }).done(function( data, textStatus, jqXHR ) {
//do something? bulkTools.gridfieldRefresh($gridfield, data);
//bulkTools.removeUploadItem($gridfield, null, payload.file.id);//bad! can't dispath in Reducer
}); });
} }
const bulkUploadFieldUpload = (payload) => {
const $gridfield = jQuery('#'+payload.fieldId).parents('.ss-gridfield');
bulkTools.gridfieldRefresh($gridfield, payload.json.bulkTools);
//bulkTools.removeUploadItem($gridfield, payload.queuedId, null);//bad! can't dispath in Reducer
}
const bulkUploadFieldReducer = (originalReducer) => (globalState) => (state, { type, payload }) => { const bulkUploadFieldReducer = (originalReducer) => (globalState) => (state, { type, payload }) => {
switch (type) { switch (type) {
case 'UPLOADFIELD_ADD_FILE': { case 'UPLOADFIELD_ADD_FILE': {
@ -28,12 +38,21 @@ const bulkUploadFieldReducer = (originalReducer) => (globalState) => (state, { t
return originalReducer(state, { type, payload }); return originalReducer(state, { type, payload });
} }
case 'UPLOADFIELD_UPLOAD_SUCCESS': {
//check if this is a bulk upload
if (payload.fieldId.indexOf('_BU') !== -1)
{
bulkUploadFieldUpload(payload);
}
return originalReducer(state, { type, payload });
}
default: { default: {
return originalReducer(state, { type, payload }); return originalReducer(state, { type, payload });
} }
} }
} }
Injector.transform('bulkUploaderCustom', (updater) => { Injector.transform('bulkUploaderTransformation', (updater) => {
updater.reducer('assetAdmin', bulkUploadFieldReducer); updater.reducer('assetAdmin', bulkUploadFieldReducer);
}); });

View File

@ -1,3 +1,33 @@
@keyframes bt_fade_out {
from {
opacity: 1;
}
to {
opacity: 0;
}
}
@keyframes bt_loading {
from {
opacity: 1;
}
to {
opacity: .25;
}
}
@keyframes bt_fade_border {
from {
border-left-width: 6px;
}
to {
border-left-width: 0;
}
}
.cms table.grid-field__table .cms table.grid-field__table
{ {
tr.bulkManagerOptions tr.bulkManagerOptions
@ -30,17 +60,52 @@
.doBulkActionButton .doBulkActionButton
{ {
float: left;
border-top-left-radius: 0; border-top-left-radius: 0;
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
height: 36px; height: 36px;
line-height: 26px; line-height: 26px;
margin-left: -1px; margin-left: -1px;
margin-right: 20px;
img img
{ {
height: 20px; height: 20px;
} }
&.loading
{
animation: .5s bt_loading infinite alternate;
cursor: wait;
pointer-events: none;
}
}
.message
{
float: left;
clear: none;
max-width: 100%;
margin: 0;
padding: 0 1.25rem;
height: 36px;
line-height: 34px;
opacity: 0;
overflow: auto;
&.show
{
animation: 10s bt_fade_out;
}
&.static
{
opacity: 1;
}
} }
.bulkSelectAll .bulkSelectAll
@ -56,5 +121,24 @@
width: 25px; width: 25px;
text-align: center; text-align: center;
} }
.ss-gridfield-item
{
&.bt-deleted
{
opacity: .5;
}
&.bt-failed
{
border-left: 0 solid #e68288;
animation: 10s bt_fade_border;
}
&.bt-updated
{
border-left: 0 solid #56bd59;
animation: 10s bt_fade_border;
}
}
} }
} }

View File

@ -16,8 +16,8 @@
} }
], ],
"require": { "require": {
"silverstripe/framework": "^4.0", "silverstripe/framework": "~4",
"silverstripe/asset-admin": "^1.0" "silverstripe/asset-admin": "~1"
}, },
"extra": { "extra": {
"branch-alias": { "branch-alias": {
@ -30,6 +30,7 @@
}, },
"autoload": { "autoload": {
"psr-4": { "psr-4": {
"Colymba\\BulkTools\\": "src/BulkTools/",
"Colymba\\BulkManager\\": "src/BulkManager/", "Colymba\\BulkManager\\": "src/BulkManager/",
"Colymba\\BulkUpload\\": "src/BulkUploader/" "Colymba\\BulkUpload\\": "src/BulkUploader/"
} }

View File

@ -3,9 +3,11 @@
namespace Colymba\BulkManager\BulkAction; namespace Colymba\BulkManager\BulkAction;
use Colymba\BulkManager\BulkAction\Handler; use Colymba\BulkManager\BulkAction\Handler;
use Colymba\BulkTools\HTTPBulkToolsResponse;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use Exception;
/** /**
* Bulk action handler for recursive archiving records. * Bulk action handler for recursive archiving records.
@ -90,31 +92,37 @@ class ArchiveHandler extends Handler
* *
* @param HTTPRequest $request * @param HTTPRequest $request
* *
* @return HTTPResponse List of affected records ID * @return HTTPBulkToolsResponse
*/ */
public function archive(HTTPRequest $request) public function archive(HTTPRequest $request)
{ {
$records = $this->getRecords(); $records = $this->getRecords();
$response = new HTTPBulkToolsResponse(true, $this->gridField);
$successes = array(); try {
$errors = array();
foreach ($records as $record) foreach ($records as $record)
{ {
$done = $record->doArchive(); $done = $record->doArchive();
if ($done) if ($done)
{ {
array_push($successes, $record->ID); $response->addSuccessRecord($record);
}else{ }else{
array_push($errors, array('id' => $record->ID, 'message' => $done)); $response->addFailedRecord($record, $done);
} }
} }
$response = new HTTPResponse(Convert::raw2json(array( $doneCount = count($response->getSuccessRecords());
'done' => $successes, $failCount = count($response->getFailedRecords());
'errors' => $errors, $message = sprintf(
))); 'Archived %1$d of %2$d records.',
$response->addHeader('Content-Type', 'text/json'); $doneCount,
$doneCount + $failCount
);
$response->setMessage($message);
} catch (Exception $ex) {
$response->setStatusCode(500);
$response->setMessage($ex->getMessage());
}
return $response; return $response;
} }

View File

@ -3,9 +3,11 @@
namespace Colymba\BulkManager\BulkAction; namespace Colymba\BulkManager\BulkAction;
use Colymba\BulkManager\BulkAction\Handler; use Colymba\BulkManager\BulkAction\Handler;
use Colymba\BulkTools\HTTPBulkToolsResponse;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use Exception;
/** /**
* Bulk action handler for deleting records. * Bulk action handler for deleting records.
@ -90,22 +92,28 @@ class DeleteHandler extends Handler
* *
* @param HTTPRequest $request * @param HTTPRequest $request
* *
* @return HTTPResponse List of deleted records ID * @return HTTPBulkToolsResponse
*/ */
public function delete(HTTPRequest $request) public function delete(HTTPRequest $request)
{ {
$ids = array(); $response = new HTTPBulkToolsResponse(true, $this->gridField);
try {
foreach ($this->getRecords() as $record) { foreach ($this->getRecords() as $record) {
array_push($ids, $record->ID); $response->addSuccessRecord($record);
$record->delete(); $record->delete();
} }
$response = new HTTPResponse(Convert::raw2json(array( $doneCount = count($response->getSuccessRecords());
'done' => true, $message = sprintf(
'records' => $ids, 'Deleted %1$d records.',
))); $doneCount
$response->addHeader('Content-Type', 'text/json'); );
$response->setMessage($message);
} catch (Exception $ex) {
$response->setStatusCode(500);
$response->setMessage($ex->getMessage());
}
return $response; return $response;
} }

View File

@ -3,9 +3,11 @@
namespace Colymba\BulkManager\BulkAction; namespace Colymba\BulkManager\BulkAction;
use Colymba\BulkManager\BulkAction\Handler; use Colymba\BulkManager\BulkAction\Handler;
use Colymba\BulkTools\HTTPBulkToolsResponse;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use Exception;
/** /**
* Bulk action handler for recursive publishing records. * Bulk action handler for recursive publishing records.
@ -90,31 +92,37 @@ class PublishHandler extends Handler
* *
* @param HTTPRequest $request * @param HTTPRequest $request
* *
* @return HTTPResponse List of affected records ID * @return HTTPBulkToolsResponse
*/ */
public function publish(HTTPRequest $request) public function publish(HTTPRequest $request)
{ {
$records = $this->getRecords(); $records = $this->getRecords();
$response = new HTTPBulkToolsResponse(false, $this->gridField);
$successes = array(); try {
$errors = array();
foreach ($records as $record) foreach ($records as $record)
{ {
$done = $record->publishRecursive(); $done = $record->publishRecursive();
if ($done) if ($done)
{ {
array_push($successes, $record->ID); $response->addSuccessRecord($record);
}else{ }else{
array_push($errors, array('id' => $record->ID, 'message' => $done)); $response->addFailedRecord($record, $done);
} }
} }
$response = new HTTPResponse(Convert::raw2json(array( $doneCount = count($response->getSuccessRecords());
'done' => $successes, $failCount = count($response->getFailedRecords());
'errors' => $errors, $message = sprintf(
))); 'Published %1$d of %2$d records.',
$response->addHeader('Content-Type', 'text/json'); $doneCount,
$doneCount + $failCount
);
$response->setMessage($message);
} catch (Exception $ex) {
$response->setStatusCode(500);
$response->setMessage($ex->getMessage());
}
return $response; return $response;
} }

View File

@ -3,9 +3,11 @@
namespace Colymba\BulkManager\BulkAction; namespace Colymba\BulkManager\BulkAction;
use Colymba\BulkManager\BulkAction\Handler; use Colymba\BulkManager\BulkAction\Handler;
use Colymba\BulkTools\HTTPBulkToolsResponse;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use Exception;
/** /**
* Bulk action handler for recursive unpublishing records. * Bulk action handler for recursive unpublishing records.
@ -90,31 +92,37 @@ class UnPublishHandler extends Handler
* *
* @param HTTPRequest $request * @param HTTPRequest $request
* *
* @return HTTPResponse List of affected records ID * @return HTTPBulkToolsResponse
*/ */
public function unPublish(HTTPRequest $request) public function unPublish(HTTPRequest $request)
{ {
$records = $this->getRecords(); $records = $this->getRecords();
$response = new HTTPBulkToolsResponse(false, $this->gridField);
$successes = array(); try {
$errors = array();
foreach ($records as $record) foreach ($records as $record)
{ {
$done = $record->doUnpublish(); $done = $record->doUnpublish();
if ($done) if ($done)
{ {
array_push($successes, $record->ID); $response->addSuccessRecord($record);
}else{ }else{
array_push($errors, array('id' => $record->ID, 'message' => $done)); $response->addFailedRecord($record, $done);
} }
} }
$response = new HTTPResponse(Convert::raw2json(array( $doneCount = count($response->getSuccessRecords());
'done' => $successes, $failCount = count($response->getFailedRecords());
'errors' => $errors, $message = sprintf(
))); 'UnPublished %1$d of %2$d records.',
$response->addHeader('Content-Type', 'text/json'); $doneCount,
$doneCount + $failCount
);
$response->setMessage($message);
} catch (Exception $ex) {
$response->setStatusCode(500);
$response->setMessage($ex->getMessage());
}
return $response; return $response;
} }

View File

@ -3,9 +3,11 @@
namespace Colymba\BulkManager\BulkAction; namespace Colymba\BulkManager\BulkAction;
use Colymba\BulkManager\BulkAction\Handler; use Colymba\BulkManager\BulkAction\Handler;
use Colymba\BulkTools\HTTPBulkToolsResponse;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use Exception;
/** /**
* Bulk action handler for unlinking records. * Bulk action handler for unlinking records.
@ -90,18 +92,22 @@ class UnlinkHandler extends Handler
* *
* @param HTTPRequest $request * @param HTTPRequest $request
* *
* @return HTTPResponse List of affected records ID * @return HTTPBulkToolsResponse
*/ */
public function unLink(HTTPRequest $request) public function unLink(HTTPRequest $request)
{ {
$ids = $this->getRecordIDList(); $ids = $this->getRecordIDList();
$this->gridField->list->removeMany($ids); $response = new HTTPBulkToolsResponse(true, $this->gridField);
$response = new HTTPResponse(Convert::raw2json(array( try {
'done' => true, //@todo fix this. seems no ids are returned!
'records' => $ids, $response->addSuccessRecords($this->getRecords());
))); $this->gridField->list->removeMany($ids);
$response->addHeader('Content-Type', 'text/json'); $response->setMessage('UnLinked records.');
} catch (Exception $ex) {
$response->setStatusCode(500);
$response->setMessage($ex->getMessage());
}
return $response; return $response;
} }

View File

@ -0,0 +1,377 @@
<?php
namespace Colymba\BulkTools;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Core\Convert;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\SS_List;
use SilverStripe\View\HTML;
/**
* Custom HTTPResponse for all bulk tools to use
* for a unified response format and facilitate forn-end handling
*
* Add custom methods and tool to create a common json output format:
* {
* isDestructive: false,
* isError: false,
* isWarning: false,
* message: "General response error or not message for the cms user",
* successClasses: ['list', 'of-new', 'classes', 'to-add', 'bt-done'],
* failedClasses: ['list', 'of-new', 'classes', 'to-add', 'bt-done']
* records: {
* success: [{
* id: 1,
* class: 'ObjectClass',
* row: 'tr .ss-gridfield-item html markup for this record'
* }],
* failed: [{
* id: 2,
* class: 'AnotherClass',
* message: 'Erro message for that object.'
* }]
* }
* }
*
* @author colymba
*/
class HTTPBulkToolsResponse extends HTTPResponse
{
/**
* We always return JSON
* @var array
*/
protected $headers = array(
"content-type" => "application/json; charset=utf-8",
);
/**
* Does the bulk action removes rows?
*
* @var boolean
*/
protected $removesRows;
/**
* Bulk action result message
*
* @var string
*/
protected $message = '';
/**
* Gridfield instance.
*
* @var GridField
*/
protected $gridField;
/**
* List of DataObject that has been modified successfully by the bulk action
*
* @var array
*/
protected $successRecords = [];
/**
* List of css classes to add to gridfield row modified successfully
*
* @var array
*/
protected $successClasses = [];
/**
* List of DataObject IDs that failed to be modified by the bulk action
*
* @var array
*/
protected $failedRecords = [];
/**
* List of css classes to add to gridfield row with errors
*
* @var array
*/
protected $failedClasses = [];
/**
* Create a new bulk tools HTTP response
*
* @param boolean $removesRows Does the action removes rows?
* @param gridfield $gridfield gridfield instance that holds the records list
* @param int $statusCode The numeric status code - 200, 404, etc
* @param string $statusDescription The text to be given alongside the status code.
* See {@link setStatusCode()} for more information.
*/
public function __construct($removesRows, $gridfield, $statusCode = null)
{
$this->removesRows = $removesRows;
$this->gridfield = $gridfield;
register_shutdown_function(array($this, 'shutdown'));
parent::__construct(null, $statusCode, $message);
}
/**
* Overriden here so content-type cannot be changed
* Add a HTTP header to the response, replacing any header of the same name.
*
* @param string $header Example: "content-type"
* @param string $value Example: "text/xml"
* @return $this
*/
public function addHeader($header, $value)
{
if($header === "content-type") {
return $this;
}
return parent::addHeader($header, $value);
}
/**
* Overriden here so content-type cannot be changed
* Remove an existing HTTP header by its name,
* e.g. "Content-Type".
*
* @param string $header
* @return $this
*/
public function removeHeader($header)
{
if($header === "content-type") {
return $this;
}
return parent::removeHeader($header);
}
/**
* Overriden here so the response body cannot be set manually
*
* @return $this
*/
public function setBody($body)
{
return $this;
}
/**
* Makes sure body is created before being returned
* @return string
*/
public function getBody()
{
$this->createBody();
return $this->body;
}
/**
* Set the general response message
*
* @return $this
*/
public function setMessage($message)
{
$this->message = $message;
return $this;
}
/**
* Add a record to the successfully modified list
* @param DataObject $record the newly modified dataObject
* @return $this
*/
public function addSuccessRecord($record)
{
$this->successRecords[] = $record;
return $this;
}
/**
* Add a list of records to the successfully modified list
* @param SS_List $records newly modified dataObjects list
* @return $this
*/
public function addSuccessRecords(SS_List $records)
{
array_push($this->successRecords, $records->toArray());
return $this;
}
/**
* Add an ID to the successfully modified list
* @param interger $id the newly modified ID
* @param string $className object class name (default to gridfield getModelClass())
* @return $this
*/
/*public function addSuccessID($id, $className = null)
{
if (!$className) {
$className = $this->gridfield->getModelClass();
}
//we use all caps ID since DO have their ID ion all caps, so createBody finds it...
$this->successRecords[] = (object) ['ID' => (int) $id, 'ClassName' => $className];
return $this;
}*/
/**
* Add an array of ID to the successfully modified list
* @param array $ids of the newly modified objects
* @return $this
*/
/*public function addSuccessIDs($ids, $className = null)
{
//we use all caps ID since DO have their ID ion all caps, so createBody finds it...
foreach ($ids as $id) {
$this->successRecords[] = (object) ['ID' => (int) $id];
}
return $this;
}*/
/**
* Return the list of succesful records
* @return array
*/
public function getSuccessRecords()
{
return $this->successRecords;
}
/**
* Add a record to the failed to modified list with its error message
* @param DataObject $record the failed dataObject
* @param string $message error message
* @return $this
*/
public function addFailedRecord($record, $message)
{
$this->failedRecords[] = array('id' => $record->ID, 'class' => $record->ClassName, 'message' => $message);
return $this;
}
/**
* Add a list of records to the failed to modified list with a common error message
* @param SS_List $records the failed dataObject list
* @param string $message error message
* @return $this
*/
public function addFailedRecords(SS_List $records, $message)
{
foreach ($records as $record) {
$this->failedRecords[] = array('id' => $record->ID, 'class' => $record->ClassName, 'message' => $message);
}
return $this;
}
/**
* Return the list of failed records
* @return array
*/
public function getFailedRecords()
{
return $this->failedRecords;
}
/**
* Creates a gridfield table row for a given record
* @param DataObject $record the record to create the row for
* @return string the html TR tag
*/
protected function getRecordGridfieldRow($record)
{
$total = count($this->gridfield->getList()) + count($this->successRecords);
$index = 0;
$this->gridfield->setList(new ArrayList(array($record)));
$rowContent = '';
foreach ($this->gridfield->getColumns() as $column) {
$colContent = $this->gridfield->getColumnContent($record, $column);
// Null means this columns should be skipped altogether.
if ($colContent === null) {
continue;
}
$colAttributes = $this->gridfield->getColumnAttributes($record, $column);
$rowContent .= HTML::createTag(
'td',
$colAttributes,
$colContent
);
}
$rowAttributes = array(
'class' => 'ss-gridfield-item ' . implode(' ', $this->successClasses),
'data-id' => $record->ID,
'data-class' => $record->ClassName,
);
$row = HTML::createTag(
'tr',
$rowAttributes,
$rowContent
);
return $row;
}
/**
* Creates the response JSON body
*/
public function createBody()
{
$body = array(
'isDestructive' => $this->removesRows,
'isError' => $this->isError(),
'isWarning' => false,
'message' => $this->message,
'successClasses' => $this->successClasses,
'failedClasses' => $this->failedClasses
);
if (!$this->isError()) {
$body['records'] = array(
'success' => array(),
'failed' => array()
);
foreach ($this->successRecords as $record) {
$data = array('id' => $record->ID, 'class' => $record->ClassName);
if (!$this->removesRows) {
$data['row'] = $this->getRecordGridfieldRow($record);
}
$body['records']['success'][] = $data;
}
$body['records']['failed'] = $this->failedRecords;
}
if (count($body['records']['success']) === 0) {
$body['isWarning'] = true;
}
$this->body = Convert::raw2json($body);
}
/**
* Make sure the body has been created before output
* Output body of this response to the browser
*/
protected function outputBody()
{
$this->createBody();
parent::outputBody();
}
/**
* Catches fatal PHP eror and output something useful for the front end
*/
public function shutdown()
{
$error = error_get_last();
if ($error !== null ) {
$this->setMessage($error['message']);
$this->setStatusCode(500, $error['message']);
$this->outputBody();
exit();
}
}
}

View File

@ -2,6 +2,7 @@
namespace Colymba\BulkUpload; namespace Colymba\BulkUpload;
use Colymba\BulkTools\HTTPBulkToolsResponse;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;
use SilverStripe\Control\RequestHandler; use SilverStripe\Control\RequestHandler;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
@ -114,34 +115,43 @@ class BulkUploadHandler extends RequestHandler
{ {
$responseData = Convert::json2array($uploadResponse->getBody()); $responseData = Convert::json2array($uploadResponse->getBody());
$responseData = array_shift($responseData); $responseData = array_shift($responseData);
}
$this->createDataObject($responseData['id']); $record = $this->createDataObject($responseData['id']);
$bulkToolsResponse = new HTTPBulkToolsResponse(false, $this->gridField);
$bulkToolsResponse->addSuccessRecord($record);
$responseData['bulkTools'] = json_decode($bulkToolsResponse->getBody());
$uploadResponse->setBody(json_encode(array($responseData)));
}
return $uploadResponse; return $uploadResponse;
} }
/** /**
* Retrieve File to be attached * Retrieve File to be attached
* and generated DataObjects for each one. * and generated DataObject.
* *
* @param HTTPRequest $request * @param HTTPRequest $request
* *
* @return HTTPResponse * @return HTTPBulkToolsResponse
*/ */
public function attach(HTTPRequest $request) public function attach(HTTPRequest $request)
{ {
$fileID = $request->requestVar('fileID'); //why is this not POST? $fileID = $request->requestVar('fileID'); //why is this not POST?
$dataObject = $this->createDataObject($fileID); $dataObject = $this->createDataObject($fileID);
$response = new HTTPResponse(Convert::raw2json(array( $response = new HTTPBulkToolsResponse(false, $this->gridField);
'done' => $dataObject->ID $response->addSuccessRecord($dataObject);
)));
$response->addHeader('Content-Type', 'text/json');
return $response; return $response;
} }
public function getRecordRow(HTTPRequest $request)
{
$recordID = $request->requestVar('recordID');
print_r($recordID);
}
/** /**
* @param string $action * @param string $action
* *

View File

@ -10,6 +10,8 @@
$Button.Label $Button.Label
</a> </a>
<div class="message notice"></div>
</th> </th>
<th> <th>
<label class="form-check-label"> <label class="form-check-label">

View File

@ -30,6 +30,7 @@ const config = [
{ {
name: 'js', name: 'js',
entry: [ entry: [
`${PATHS.SRC}/js/bulkTools.js`,
`${PATHS.SRC}/js/manager.js`, `${PATHS.SRC}/js/manager.js`,
`${PATHS.SRC}/js/managerBulkEditingForm.js`, `${PATHS.SRC}/js/managerBulkEditingForm.js`,
`${PATHS.SRC}/js/uploader.js` `${PATHS.SRC}/js/uploader.js`