diff --git a/client/dist/js/main.js b/client/dist/js/main.js index fb34ea0..a104dc9 100644 --- a/client/dist/js/main.js +++ b/client/dist/js/main.js @@ -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);ic&&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('')}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}}); \ No newline at end of file +!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);ia&&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('')}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}}); \ No newline at end of file diff --git a/client/dist/js/main.js.map b/client/dist/js/main.js.map new file mode 100644 index 0000000..96a314a --- /dev/null +++ b/client/dist/js/main.js.map @@ -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('\"\"');\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":""} \ No newline at end of file diff --git a/client/dist/styles/main.css b/client/dist/styles/main.css index c4db74f..38cd1cc 100644 --- a/client/dist/styles/main.css +++ b/client/dist/styles/main.css @@ -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"} \ No newline at end of file +@-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"} \ No newline at end of file diff --git a/client/dist/styles/main.css.map b/client/dist/styles/main.css.map new file mode 100644 index 0000000..8f6d2c7 --- /dev/null +++ b/client/dist/styles/main.css.map @@ -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":""} \ No newline at end of file diff --git a/client/src/js/bulkTools.js b/client/src/js/bulkTools.js new file mode 100644 index 0000000..0180fba --- /dev/null +++ b/client/src/js/bulkTools.js @@ -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'); + } + }*/ +} diff --git a/client/src/js/manager.js b/client/src/js/manager.js index 4de13c3..33a54ed 100644 --- a/client/src/js/manager.js +++ b/client/src/js/manager.js @@ -206,10 +206,11 @@ this.doBulkAction(action, ids); }, - doBulkAction: function(action, ids, callbackFunction, callbackContext) + doBulkAction: function(action, ids) { var $parent = $(this).parents('.bulkManagerOptions'), $btn = $parent.find('a.doBulkActionButton'), + $msg = $parent.find('.message'), config = $btn.data('config'), url = this.getActionURL(action, $(this).data('url')), @@ -227,15 +228,12 @@ { if( !confirm(ss.i18n._t('GRIDFIELD_BULK_MANAGER.CONFIRM_DESTRUCTIVE_ACTION')) ) { - if ( callbackFunction && callbackContext ) - { - callbackFunction.call(callbackContext, false); - } return false; } } $btn.addClass('loading'); + $msg.removeClass('static show error warning'); if ( config[action]['xhr'] ) { @@ -244,15 +242,25 @@ data: data, type: "POST", context: $(this) - }).done(function(data, textStatus, jqXHR) { - $btn.removeClass('loading'); - if ( callbackFunction && callbackContext ) - { - callbackFunction.call(callbackContext, data); + }).always(function(data, textStatus, jqXHR) { + $btn.removeClass('loading'); + + //if request fail, return a +4xx status code, extract json response + 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{ diff --git a/client/src/js/uploader.js b/client/src/js/uploader.js index 63d1409..53a3d9a 100644 --- a/client/src/js/uploader.js +++ b/client/src/js/uploader.js @@ -1,22 +1,32 @@ /** * A quick hack to catch the uploadfield add file event * and send the file ID to the bulkUploader component + * @todo write actions */ import Injector from 'lib/Injector'; 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, { method: schema.data.attachFileEndpoint.method, //doesn't seem to change anything data: { fileID: payload.file.id } }).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 }) => { switch (type) { case 'UPLOADFIELD_ADD_FILE': { @@ -28,12 +38,21 @@ const bulkUploadFieldReducer = (originalReducer) => (globalState) => (state, { t 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: { return originalReducer(state, { type, payload }); } } } -Injector.transform('bulkUploaderCustom', (updater) => { +Injector.transform('bulkUploaderTransformation', (updater) => { updater.reducer('assetAdmin', bulkUploadFieldReducer); }); \ No newline at end of file diff --git a/client/src/styles/manager.scss b/client/src/styles/manager.scss index fab9746..ae98b65 100644 --- a/client/src/styles/manager.scss +++ b/client/src/styles/manager.scss @@ -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 { tr.bulkManagerOptions @@ -30,17 +60,52 @@ .doBulkActionButton { + float: left; border-top-left-radius: 0; border-bottom-left-radius: 0; height: 36px; line-height: 26px; margin-left: -1px; + margin-right: 20px; img { 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 @@ -56,5 +121,24 @@ width: 25px; 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; + } + } } } diff --git a/composer.json b/composer.json index d5ce94e..619f738 100644 --- a/composer.json +++ b/composer.json @@ -16,8 +16,8 @@ } ], "require": { - "silverstripe/framework": "^4.0", - "silverstripe/asset-admin": "^1.0" + "silverstripe/framework": "~4", + "silverstripe/asset-admin": "~1" }, "extra": { "branch-alias": { @@ -30,6 +30,7 @@ }, "autoload": { "psr-4": { + "Colymba\\BulkTools\\": "src/BulkTools/", "Colymba\\BulkManager\\": "src/BulkManager/", "Colymba\\BulkUpload\\": "src/BulkUploader/" } diff --git a/src/BulkManager/BulkAction/ArchiveHandler.php b/src/BulkManager/BulkAction/ArchiveHandler.php index 6797138..70ebaa8 100644 --- a/src/BulkManager/BulkAction/ArchiveHandler.php +++ b/src/BulkManager/BulkAction/ArchiveHandler.php @@ -3,9 +3,11 @@ namespace Colymba\BulkManager\BulkAction; use Colymba\BulkManager\BulkAction\Handler; +use Colymba\BulkTools\HTTPBulkToolsResponse; use SilverStripe\Core\Convert; use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPResponse; +use Exception; /** * Bulk action handler for recursive archiving records. @@ -90,31 +92,37 @@ class ArchiveHandler extends Handler * * @param HTTPRequest $request * - * @return HTTPResponse List of affected records ID + * @return HTTPBulkToolsResponse */ public function archive(HTTPRequest $request) { $records = $this->getRecords(); - - $successes = array(); - $errors = array(); + $response = new HTTPBulkToolsResponse(true, $this->gridField); - foreach ($records as $record) - { - $done = $record->doArchive(); - if ($done) + try { + foreach ($records as $record) { - array_push($successes, $record->ID); - }else{ - array_push($errors, array('id' => $record->ID, 'message' => $done)); + $done = $record->doArchive(); + if ($done) + { + $response->addSuccessRecord($record); + }else{ + $response->addFailedRecord($record, $done); + } } - } - $response = new HTTPResponse(Convert::raw2json(array( - 'done' => $successes, - 'errors' => $errors, - ))); - $response->addHeader('Content-Type', 'text/json'); + $doneCount = count($response->getSuccessRecords()); + $failCount = count($response->getFailedRecords()); + $message = sprintf( + 'Archived %1$d of %2$d records.', + $doneCount, + $doneCount + $failCount + ); + $response->setMessage($message); + } catch (Exception $ex) { + $response->setStatusCode(500); + $response->setMessage($ex->getMessage()); + } return $response; } diff --git a/src/BulkManager/BulkAction/DeleteHandler.php b/src/BulkManager/BulkAction/DeleteHandler.php index f08eddc..fca61ea 100644 --- a/src/BulkManager/BulkAction/DeleteHandler.php +++ b/src/BulkManager/BulkAction/DeleteHandler.php @@ -3,9 +3,11 @@ namespace Colymba\BulkManager\BulkAction; use Colymba\BulkManager\BulkAction\Handler; +use Colymba\BulkTools\HTTPBulkToolsResponse; use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPResponse; use SilverStripe\Core\Convert; +use Exception; /** * Bulk action handler for deleting records. @@ -90,23 +92,29 @@ class DeleteHandler extends Handler * * @param HTTPRequest $request * - * @return HTTPResponse List of deleted records ID + * @return HTTPBulkToolsResponse */ public function delete(HTTPRequest $request) { - $ids = array(); + $response = new HTTPBulkToolsResponse(true, $this->gridField); - foreach ($this->getRecords() as $record) { - array_push($ids, $record->ID); - $record->delete(); + try { + foreach ($this->getRecords() as $record) { + $response->addSuccessRecord($record); + $record->delete(); + } + + $doneCount = count($response->getSuccessRecords()); + $message = sprintf( + 'Deleted %1$d records.', + $doneCount + ); + $response->setMessage($message); + } catch (Exception $ex) { + $response->setStatusCode(500); + $response->setMessage($ex->getMessage()); } - $response = new HTTPResponse(Convert::raw2json(array( - 'done' => true, - 'records' => $ids, - ))); - $response->addHeader('Content-Type', 'text/json'); - return $response; } } diff --git a/src/BulkManager/BulkAction/PublishHandler.php b/src/BulkManager/BulkAction/PublishHandler.php index 92c043f..00e08e0 100644 --- a/src/BulkManager/BulkAction/PublishHandler.php +++ b/src/BulkManager/BulkAction/PublishHandler.php @@ -3,9 +3,11 @@ namespace Colymba\BulkManager\BulkAction; use Colymba\BulkManager\BulkAction\Handler; +use Colymba\BulkTools\HTTPBulkToolsResponse; use SilverStripe\Core\Convert; use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPResponse; +use Exception; /** * Bulk action handler for recursive publishing records. @@ -90,32 +92,38 @@ class PublishHandler extends Handler * * @param HTTPRequest $request * - * @return HTTPResponse List of affected records ID + * @return HTTPBulkToolsResponse */ public function publish(HTTPRequest $request) { $records = $this->getRecords(); - - $successes = array(); - $errors = array(); + $response = new HTTPBulkToolsResponse(false, $this->gridField); - foreach ($records as $record) - { - $done = $record->publishRecursive(); - if ($done) + try { + foreach ($records as $record) { - array_push($successes, $record->ID); - }else{ - array_push($errors, array('id' => $record->ID, 'message' => $done)); + $done = $record->publishRecursive(); + if ($done) + { + $response->addSuccessRecord($record); + }else{ + $response->addFailedRecord($record, $done); + } } + + $doneCount = count($response->getSuccessRecords()); + $failCount = count($response->getFailedRecords()); + $message = sprintf( + 'Published %1$d of %2$d records.', + $doneCount, + $doneCount + $failCount + ); + $response->setMessage($message); + } catch (Exception $ex) { + $response->setStatusCode(500); + $response->setMessage($ex->getMessage()); } - - $response = new HTTPResponse(Convert::raw2json(array( - 'done' => $successes, - 'errors' => $errors, - ))); - $response->addHeader('Content-Type', 'text/json'); - + return $response; } } diff --git a/src/BulkManager/BulkAction/UnPublishHandler.php b/src/BulkManager/BulkAction/UnPublishHandler.php index 7047a47..cfc8917 100644 --- a/src/BulkManager/BulkAction/UnPublishHandler.php +++ b/src/BulkManager/BulkAction/UnPublishHandler.php @@ -3,9 +3,11 @@ namespace Colymba\BulkManager\BulkAction; use Colymba\BulkManager\BulkAction\Handler; +use Colymba\BulkTools\HTTPBulkToolsResponse; use SilverStripe\Core\Convert; use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPResponse; +use Exception; /** * Bulk action handler for recursive unpublishing records. @@ -90,31 +92,37 @@ class UnPublishHandler extends Handler * * @param HTTPRequest $request * - * @return HTTPResponse List of affected records ID + * @return HTTPBulkToolsResponse */ public function unPublish(HTTPRequest $request) { $records = $this->getRecords(); + $response = new HTTPBulkToolsResponse(false, $this->gridField); - $successes = array(); - $errors = array(); - - foreach ($records as $record) - { - $done = $record->doUnpublish(); - if ($done) + try { + foreach ($records as $record) { - array_push($successes, $record->ID); - }else{ - array_push($errors, array('id' => $record->ID, 'message' => $done)); + $done = $record->doUnpublish(); + if ($done) + { + $response->addSuccessRecord($record); + }else{ + $response->addFailedRecord($record, $done); + } } - } - $response = new HTTPResponse(Convert::raw2json(array( - 'done' => $successes, - 'errors' => $errors, - ))); - $response->addHeader('Content-Type', 'text/json'); + $doneCount = count($response->getSuccessRecords()); + $failCount = count($response->getFailedRecords()); + $message = sprintf( + 'UnPublished %1$d of %2$d records.', + $doneCount, + $doneCount + $failCount + ); + $response->setMessage($message); + } catch (Exception $ex) { + $response->setStatusCode(500); + $response->setMessage($ex->getMessage()); + } return $response; } diff --git a/src/BulkManager/BulkAction/UnlinkHandler.php b/src/BulkManager/BulkAction/UnlinkHandler.php index 2a2c8e5..0dc8f45 100644 --- a/src/BulkManager/BulkAction/UnlinkHandler.php +++ b/src/BulkManager/BulkAction/UnlinkHandler.php @@ -3,9 +3,11 @@ namespace Colymba\BulkManager\BulkAction; use Colymba\BulkManager\BulkAction\Handler; +use Colymba\BulkTools\HTTPBulkToolsResponse; use SilverStripe\Core\Convert; use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPResponse; +use Exception; /** * Bulk action handler for unlinking records. @@ -90,18 +92,22 @@ class UnlinkHandler extends Handler * * @param HTTPRequest $request * - * @return HTTPResponse List of affected records ID + * @return HTTPBulkToolsResponse */ public function unLink(HTTPRequest $request) { $ids = $this->getRecordIDList(); - $this->gridField->list->removeMany($ids); + $response = new HTTPBulkToolsResponse(true, $this->gridField); - $response = new HTTPResponse(Convert::raw2json(array( - 'done' => true, - 'records' => $ids, - ))); - $response->addHeader('Content-Type', 'text/json'); + try { + //@todo fix this. seems no ids are returned! + $response->addSuccessRecords($this->getRecords()); + $this->gridField->list->removeMany($ids); + $response->setMessage('UnLinked records.'); + } catch (Exception $ex) { + $response->setStatusCode(500); + $response->setMessage($ex->getMessage()); + } return $response; } diff --git a/src/BulkTools/HTTPBulkToolsResponse.php b/src/BulkTools/HTTPBulkToolsResponse.php new file mode 100644 index 0000000..ceb0083 --- /dev/null +++ b/src/BulkTools/HTTPBulkToolsResponse.php @@ -0,0 +1,377 @@ + "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(); + } + } +} diff --git a/src/BulkUploader/BulkUploadHandler.php b/src/BulkUploader/BulkUploadHandler.php index a6c088b..c7b1d92 100644 --- a/src/BulkUploader/BulkUploadHandler.php +++ b/src/BulkUploader/BulkUploadHandler.php @@ -2,6 +2,7 @@ namespace Colymba\BulkUpload; +use Colymba\BulkTools\HTTPBulkToolsResponse; use SilverStripe\Control\Controller; use SilverStripe\Control\RequestHandler; use SilverStripe\Control\HTTPRequest; @@ -114,34 +115,43 @@ class BulkUploadHandler extends RequestHandler { $responseData = Convert::json2array($uploadResponse->getBody()); $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; } /** * Retrieve File to be attached - * and generated DataObjects for each one. + * and generated DataObject. * * @param HTTPRequest $request * - * @return HTTPResponse + * @return HTTPBulkToolsResponse */ public function attach(HTTPRequest $request) { $fileID = $request->requestVar('fileID'); //why is this not POST? $dataObject = $this->createDataObject($fileID); - $response = new HTTPResponse(Convert::raw2json(array( - 'done' => $dataObject->ID - ))); - $response->addHeader('Content-Type', 'text/json'); - + $response = new HTTPBulkToolsResponse(false, $this->gridField); + $response->addSuccessRecord($dataObject); return $response; } + public function getRecordRow(HTTPRequest $request) + { + $recordID = $request->requestVar('recordID'); + print_r($recordID); + } + /** * @param string $action * diff --git a/templates/Colymba/BulkManager/BulkManagerButtons.ss b/templates/Colymba/BulkManager/BulkManagerButtons.ss index 01f6a35..aac277c 100644 --- a/templates/Colymba/BulkManager/BulkManagerButtons.ss +++ b/templates/Colymba/BulkManager/BulkManagerButtons.ss @@ -9,6 +9,8 @@ class="doBulkActionButton disabled btn btn-outline-secondary"> $Button.Label + +
diff --git a/webpack.config.js b/webpack.config.js index 51a6597..81661f7 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -30,6 +30,7 @@ const config = [ { name: 'js', entry: [ + `${PATHS.SRC}/js/bulkTools.js`, `${PATHS.SRC}/js/manager.js`, `${PATHS.SRC}/js/managerBulkEditingForm.js`, `${PATHS.SRC}/js/uploader.js`