From 6e969a47207371e082357288f5f36dcad9d3f0d5 Mon Sep 17 00:00:00 2001 From: Clark Winkelmann Date: Sun, 4 Apr 2021 18:18:56 +0200 Subject: [PATCH] Add option to draw with colors instead of carving --- extend.php | 7 +- js/dist/admin.js | 2 +- js/dist/admin.js.map | 2 +- js/dist/forum.js | 2 +- js/dist/forum.js.map | 2 +- js/src/admin/index.js | 54 ++++++++++++ js/src/forum/components/ContestPage.js | 1 + js/src/forum/components/ParticipateModal.js | 70 +++++++++++++--- js/src/forum/components/PumpkinCanvas.js | 93 ++++++++++++--------- js/src/forum/states/BrushState.js | 5 ++ resources/less/admin.less | 3 + resources/less/forum.less | 23 +++++ resources/locale/en.yml | 7 ++ 13 files changed, 218 insertions(+), 53 deletions(-) create mode 100644 js/src/forum/states/BrushState.js create mode 100644 resources/less/admin.less diff --git a/extend.php b/extend.php index 36038f8..4cd4768 100644 --- a/extend.php +++ b/extend.php @@ -14,7 +14,8 @@ ->css(__DIR__ . '/resources/less/forum.less') ->route('/carving-contest', 'carving-contest', Content\Entries::class), (new Extend\Frontend('admin')) - ->js(__DIR__ . '/js/dist/admin.js'), + ->js(__DIR__ . '/js/dist/admin.js') + ->css(__DIR__ . '/resources/less/admin.less'), new Extend\Locales(__DIR__ . '/resources/locale'), (new Extend\Routes('api')) @@ -63,4 +64,8 @@ (new Extend\Filter(Filters\EntryFilterer::class)) ->addFilter(Filters\NoOpFilter::class), + + (new Extend\Settings()) + ->serializeToForum('carvingContestColorMode', 'carving-contest.colorMode', 'boolval') + ->serializeToForum('carvingContestColors', 'carving-contest.colors'), ]; diff --git a/js/dist/admin.js b/js/dist/admin.js index 60b5996..85ed02b 100644 --- a/js/dist/admin.js +++ b/js/dist/admin.js @@ -1,2 +1,2 @@ -module.exports=function(e){var n={};function r(t){if(n[t])return n[t].exports;var i=n[t]={i:t,l:!1,exports:{}};return e[t].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=e,r.c=n,r.d=function(e,n,t){r.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,n){if(1&n&&(e=r(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(r.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var i in e)r.d(t,i,function(n){return e[n]}.bind(null,i));return t},r.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(n,"a",n),n},r.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},r.p="",r(r.s=18)}({0:function(e,n){e.exports=flarum.core.compat.app},18:function(e,n,r){"use strict";r.r(n);var t=r(0),i=r.n(t);i.a.initializers.add("carving-contest",(function(){i.a.extensionData.for("clarkwinkelmann-carving-contest").registerSetting((function(){return m(".Form-group",[m("label",i.a.translator.trans("clarkwinkelmann-carving-contest.admin.settings.maxEntriesPerUser")),m("input.FormControl",{type:"number",min:0,step:1,bidi:this.setting("carving-contest.maxEntriesPerUser",0)})])})).registerPermission({icon:"fas fa-spider",label:i.a.translator.trans("clarkwinkelmann-carving-contest.admin.permissions.view"),permission:"carving-contest.view",allowGuest:!0},"view").registerPermission({icon:"fas fa-spider",label:i.a.translator.trans("clarkwinkelmann-carving-contest.admin.permissions.like"),permission:"carving-contest.like"},"reply").registerPermission({icon:"fas fa-spider",label:i.a.translator.trans("clarkwinkelmann-carving-contest.admin.permissions.participate"),permission:"carving-contest.participate"},"reply").registerPermission({icon:"fas fa-spider",label:i.a.translator.trans("clarkwinkelmann-carving-contest.admin.permissions.moderate"),permission:"carving-contest.moderate"},"moderate")}))}}); +module.exports=function(n){var e={};function t(r){if(e[r])return e[r].exports;var a=e[r]={i:r,l:!1,exports:{}};return n[r].call(a.exports,a,a.exports,t),a.l=!0,a.exports}return t.m=n,t.c=e,t.d=function(n,e,r){t.o(n,e)||Object.defineProperty(n,e,{enumerable:!0,get:r})},t.r=function(n){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(n,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(n,"__esModule",{value:!0})},t.t=function(n,e){if(1&e&&(n=t(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var r=Object.create(null);if(t.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var a in n)t.d(r,a,function(e){return n[e]}.bind(null,a));return r},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,e){return Object.prototype.hasOwnProperty.call(n,e)},t.p="",t(t.s=18)}({0:function(n,e){n.exports=flarum.core.compat.app},18:function(n,e,t){"use strict";t.r(e);var r=t(0),a=t.n(r);a.a.initializers.add("carving-contest",(function(){a.a.extensionData.for("clarkwinkelmann-carving-contest").registerSetting((function(){return m(".Form-group",[m("label",a.a.translator.trans("clarkwinkelmann-carving-contest.admin.settings.maxEntriesPerUser")),m("input.FormControl",{type:"number",min:0,step:1,bidi:this.setting("carving-contest.maxEntriesPerUser",0)})])})).registerSetting({type:"switch",setting:"carving-contest.colorMode",label:a.a.translator.trans("clarkwinkelmann-carving-contest.admin.settings.colorMode")}).registerSetting((function(){var n=this.setting("carving-contest.colors","simple"),e=!this.setting("carving-contest.colorMode")();return[m(".Form-group.CarvingContest-Subgroup",[m("label",[m("input",{type:"radio",name:"carving-contest-color",checked:"simple"===n(),onchange:function(){return n("simple")},disabled:e})," ",a.a.translator.trans("clarkwinkelmann-carving-contest.admin.colors.simple")]),m("label",[m("input",{type:"radio",name:"carving-contest-color",checked:"all"===n(),onchange:function(){return n("all")},disabled:e})," ",a.a.translator.trans("clarkwinkelmann-carving-contest.admin.colors.all")]),m("label",[m("input",{type:"radio",name:"carving-contest-color",checked:"simple"!==n()&&"all"!==n(),onchange:function(){return n("")},disabled:e})," ",a.a.translator.trans("clarkwinkelmann-carving-contest.admin.colors.custom")]),"simple"!==n()&&"all"!==n()?[m("input.FormControl",{bidi:n,disabled:e}),m(".helpText",a.a.translator.trans("clarkwinkelmann-carving-contest.admin.colors.custom-help"))]:null])]})).registerPermission({icon:"fas fa-spider",label:a.a.translator.trans("clarkwinkelmann-carving-contest.admin.permissions.view"),permission:"carving-contest.view",allowGuest:!0},"view").registerPermission({icon:"fas fa-spider",label:a.a.translator.trans("clarkwinkelmann-carving-contest.admin.permissions.like"),permission:"carving-contest.like"},"reply").registerPermission({icon:"fas fa-spider",label:a.a.translator.trans("clarkwinkelmann-carving-contest.admin.permissions.participate"),permission:"carving-contest.participate"},"reply").registerPermission({icon:"fas fa-spider",label:a.a.translator.trans("clarkwinkelmann-carving-contest.admin.permissions.moderate"),permission:"carving-contest.moderate"},"moderate")}))}}); //# sourceMappingURL=admin.js.map \ No newline at end of file diff --git a/js/dist/admin.js.map b/js/dist/admin.js.map index 107d845..bd90046 100644 --- a/js/dist/admin.js.map +++ b/js/dist/admin.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack://@clarkwinkelmann/carving-contest/webpack/bootstrap","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['app']\"","webpack://@clarkwinkelmann/carving-contest/./src/admin/index.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","flarum","core","compat","app","initializers","add","extensionData","registerSetting","translator","trans","type","min","step","bidi","this","setting","registerPermission","icon","label","permission","allowGuest"],"mappings":"2BACE,IAAIA,EAAmB,GAGvB,SAASC,EAAoBC,GAG5B,GAAGF,EAAiBE,GACnB,OAAOF,EAAiBE,GAAUC,QAGnC,IAAIC,EAASJ,EAAiBE,GAAY,CACzCG,EAAGH,EACHI,GAAG,EACHH,QAAS,IAUV,OANAI,EAAQL,GAAUM,KAAKJ,EAAOD,QAASC,EAAQA,EAAOD,QAASF,GAG/DG,EAAOE,GAAI,EAGJF,EAAOD,QA0Df,OArDAF,EAAoBQ,EAAIF,EAGxBN,EAAoBS,EAAIV,EAGxBC,EAAoBU,EAAI,SAASR,EAASS,EAAMC,GAC3CZ,EAAoBa,EAAEX,EAASS,IAClCG,OAAOC,eAAeb,EAASS,EAAM,CAAEK,YAAY,EAAMC,IAAKL,KAKhEZ,EAAoBkB,EAAI,SAAShB,GACX,oBAAXiB,QAA0BA,OAAOC,aAC1CN,OAAOC,eAAeb,EAASiB,OAAOC,YAAa,CAAEC,MAAO,WAE7DP,OAAOC,eAAeb,EAAS,aAAc,CAAEmB,OAAO,KAQvDrB,EAAoBsB,EAAI,SAASD,EAAOE,GAEvC,GADU,EAAPA,IAAUF,EAAQrB,EAAoBqB,IAC/B,EAAPE,EAAU,OAAOF,EACpB,GAAW,EAAPE,GAA8B,iBAAVF,GAAsBA,GAASA,EAAMG,WAAY,OAAOH,EAChF,IAAII,EAAKX,OAAOY,OAAO,MAGvB,GAFA1B,EAAoBkB,EAAEO,GACtBX,OAAOC,eAAeU,EAAI,UAAW,CAAET,YAAY,EAAMK,MAAOA,IACtD,EAAPE,GAA4B,iBAATF,EAAmB,IAAI,IAAIM,KAAON,EAAOrB,EAAoBU,EAAEe,EAAIE,EAAK,SAASA,GAAO,OAAON,EAAMM,IAAQC,KAAK,KAAMD,IAC9I,OAAOF,GAIRzB,EAAoB6B,EAAI,SAAS1B,GAChC,IAAIS,EAAST,GAAUA,EAAOqB,WAC7B,WAAwB,OAAOrB,EAAgB,SAC/C,WAA8B,OAAOA,GAEtC,OADAH,EAAoBU,EAAEE,EAAQ,IAAKA,GAC5BA,GAIRZ,EAAoBa,EAAI,SAASiB,EAAQC,GAAY,OAAOjB,OAAOkB,UAAUC,eAAe1B,KAAKuB,EAAQC,IAGzG/B,EAAoBkC,EAAI,GAIjBlC,EAAoBA,EAAoBmC,EAAI,I,kBClFrDhC,EAAOD,QAAUkC,OAAOC,KAAKC,OAAY,K,2DCIzCC,IAAIC,aAAaC,IAAI,mBAAmB,WACpCF,IAAIG,cAAJ,IAAsB,mCACjBC,iBAAgB,WACb,OAAOnC,EAAE,cAAe,CACpBA,EAAE,QAAS+B,IAAIK,WAAWC,MAAM,qEAChCrC,EAAE,oBAAqB,CACnBsC,KAAM,SACNC,IAAK,EACLC,KAAM,EACNC,KAAMC,KAAKC,QAAQ,oCAAqC,UAInEC,mBAAmB,CAChBC,KAAM,gBACNC,MAAOf,IAAIK,WAAWC,MAAM,0DAC5BU,WAAY,uBACZC,YAAY,GACb,QACFJ,mBAAmB,CAChBC,KAAM,gBACNC,MAAOf,IAAIK,WAAWC,MAAM,0DAC5BU,WAAY,wBACb,SACFH,mBAAmB,CAChBC,KAAM,gBACNC,MAAOf,IAAIK,WAAWC,MAAM,iEAC5BU,WAAY,+BACb,SACFH,mBAAmB,CAChBC,KAAM,gBACNC,MAAOf,IAAIK,WAAWC,MAAM,8DAC5BU,WAAY,4BACb","file":"admin.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, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\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\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 18);\n","module.exports = flarum.core.compat['app'];","import app from 'flarum/app';\n\n/* global m */\n\napp.initializers.add('carving-contest', () => {\n app.extensionData.for('clarkwinkelmann-carving-contest')\n .registerSetting(function () {\n return m('.Form-group', [\n m('label', app.translator.trans('clarkwinkelmann-carving-contest.admin.settings.maxEntriesPerUser')),\n m('input.FormControl', {\n type: 'number',\n min: 0,\n step: 1,\n bidi: this.setting('carving-contest.maxEntriesPerUser', 0),\n }),\n ]);\n })\n .registerPermission({\n icon: 'fas fa-spider',\n label: app.translator.trans('clarkwinkelmann-carving-contest.admin.permissions.view'),\n permission: 'carving-contest.view',\n allowGuest: true,\n }, 'view')\n .registerPermission({\n icon: 'fas fa-spider',\n label: app.translator.trans('clarkwinkelmann-carving-contest.admin.permissions.like'),\n permission: 'carving-contest.like',\n }, 'reply')\n .registerPermission({\n icon: 'fas fa-spider',\n label: app.translator.trans('clarkwinkelmann-carving-contest.admin.permissions.participate'),\n permission: 'carving-contest.participate',\n }, 'reply')\n .registerPermission({\n icon: 'fas fa-spider',\n label: app.translator.trans('clarkwinkelmann-carving-contest.admin.permissions.moderate'),\n permission: 'carving-contest.moderate',\n }, 'moderate');\n});\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack://@clarkwinkelmann/carving-contest/webpack/bootstrap","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['app']\"","webpack://@clarkwinkelmann/carving-contest/./src/admin/index.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","flarum","core","compat","app","initializers","add","extensionData","registerSetting","translator","trans","type","min","step","bidi","this","setting","label","disabled","checked","onchange","registerPermission","icon","permission","allowGuest"],"mappings":"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","file":"admin.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, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\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\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 18);\n","module.exports = flarum.core.compat['app'];","import app from 'flarum/app';\n\n/* global m */\n\napp.initializers.add('carving-contest', () => {\n app.extensionData.for('clarkwinkelmann-carving-contest')\n .registerSetting(function () {\n return m('.Form-group', [\n m('label', app.translator.trans('clarkwinkelmann-carving-contest.admin.settings.maxEntriesPerUser')),\n m('input.FormControl', {\n type: 'number',\n min: 0,\n step: 1,\n bidi: this.setting('carving-contest.maxEntriesPerUser', 0),\n }),\n ]);\n })\n .registerSetting({\n type: 'switch',\n setting: 'carving-contest.colorMode',\n label: app.translator.trans('clarkwinkelmann-carving-contest.admin.settings.colorMode'),\n })\n .registerSetting(function () {\n const setting = this.setting('carving-contest.colors', 'simple');\n const disabled = !this.setting('carving-contest.colorMode')();\n\n return [\n m('.Form-group.CarvingContest-Subgroup', [\n m('label', [\n m('input', {\n type: 'radio',\n name: 'carving-contest-color',\n checked: setting() === 'simple',\n onchange: () => setting('simple'),\n disabled,\n }),\n ' ',\n app.translator.trans('clarkwinkelmann-carving-contest.admin.colors.simple'),\n ]),\n m('label', [\n m('input', {\n type: 'radio',\n name: 'carving-contest-color',\n checked: setting() === 'all',\n onchange: () => setting('all'),\n disabled,\n }),\n ' ',\n app.translator.trans('clarkwinkelmann-carving-contest.admin.colors.all'),\n ]),\n m('label', [\n m('input', {\n type: 'radio',\n name: 'carving-contest-color',\n checked: setting() !== 'simple' && setting() !== 'all',\n onchange: () => setting(''),\n disabled,\n }),\n ' ',\n app.translator.trans('clarkwinkelmann-carving-contest.admin.colors.custom'),\n ]),\n setting() !== 'simple' && setting() !== 'all' ? [\n m('input.FormControl', {\n bidi: setting,\n disabled,\n }),\n m('.helpText', app.translator.trans('clarkwinkelmann-carving-contest.admin.colors.custom-help')),\n ] : null,\n ]),\n ];\n })\n .registerPermission({\n icon: 'fas fa-spider',\n label: app.translator.trans('clarkwinkelmann-carving-contest.admin.permissions.view'),\n permission: 'carving-contest.view',\n allowGuest: true,\n }, 'view')\n .registerPermission({\n icon: 'fas fa-spider',\n label: app.translator.trans('clarkwinkelmann-carving-contest.admin.permissions.like'),\n permission: 'carving-contest.like',\n }, 'reply')\n .registerPermission({\n icon: 'fas fa-spider',\n label: app.translator.trans('clarkwinkelmann-carving-contest.admin.permissions.participate'),\n permission: 'carving-contest.participate',\n }, 'reply')\n .registerPermission({\n icon: 'fas fa-spider',\n label: app.translator.trans('clarkwinkelmann-carving-contest.admin.permissions.moderate'),\n permission: 'carving-contest.moderate',\n }, 'moderate');\n});\n"],"sourceRoot":""} \ No newline at end of file diff --git a/js/dist/forum.js b/js/dist/forum.js index e9dc8c5..c354cc2 100644 --- a/js/dist/forum.js +++ b/js/dist/forum.js @@ -1,2 +1,2 @@ -module.exports=function(t){var e={};function n(o){if(e[o])return e[o].exports;var a=e[o]={i:o,l:!1,exports:{}};return t[o].call(a.exports,a,a.exports,n),a.l=!0,a.exports}return n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var a in t)n.d(o,a,function(e){return t[e]}.bind(null,a));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=17)}([function(t,e){t.exports=flarum.core.compat.app},function(t,e){t.exports=flarum.core.compat["common/components/Button"]},function(t,e){t.exports=flarum.core.compat["common/Model"]},function(t,e){t.exports=flarum.core.compat["common/helpers/username"]},function(t,e){t.exports=flarum.core.compat["common/helpers/icon"]},function(t,e){t.exports=flarum.core.compat["common/components/Link"]},function(t,e){t.exports=flarum.core.compat["common/helpers/avatar"]},function(t,e){t.exports=flarum.core.compat["common/components/Modal"]},function(t,e){t.exports=flarum.core.compat["common/extend"]},function(t,e){t.exports=flarum.core.compat["forum/components/IndexPage"]},function(t,e){t.exports=flarum.core.compat["common/components/LinkButton"]},function(t,e){t.exports=flarum.core.compat["common/components/Page"]},function(t,e){t.exports=flarum.core.compat["common/components/LoadingIndicator"]},function(t,e){t.exports=flarum.core.compat["common/components/Dropdown"]},function(t,e){t.exports=flarum.core.compat["common/helpers/humanTime"]},function(t,e){t.exports=flarum.core.compat["common/helpers/punctuateSeries"]},function(t,e){t.exports=flarum.core.compat["common/utils/extractText"]},function(t,e,n){"use strict";n.r(e);var o=n(8),a=n(0),r=n.n(a),i=n(9),s=n.n(i),c=n(10),u=n.n(c);function l(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function f(t,e){return(f=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function p(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,f(t,e)}function d(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var h=n(2),v=n.n(h),g=function(t){function e(){for(var e,n=arguments.length,o=new Array(n),a=0;a0&&(e.data[o]=0,e.data[o+1]=0,e.data[o+2]=0,e.data[o+3]=0);this.previewContext.clearRect(0,0,426,426),this.previewContext.putImageData(e,0,0),t&&(this.previewContext.strokeStyle="rgba(0,0,0,0.5)",this.previewContext.lineWidth=3,this.drawWithTool(this.previewContext,t.x,t.y))}},t}(),z="clarkwinkelmann-carving-contest.forum.modal.",V=function(t){function e(){for(var e,n=arguments.length,o=new Array(n),a=0;a4,o=e.sort((function(t){return t===r.a.session.user?-1:1})).slice(0,n?3:4).map((function(t){return m(E.a,{href:r.a.route.user(t)},t===r.a.session.user?r.a.translator.trans("flarum-likes.forum.post.you_text"):O()(t))}));if(n){var a=e.length-o.length;o.push(m("a",{href:"#",onclick:function(e){e.preventDefault(),r.a.modal.show(X,{entry:t})}},r.a.translator.transChoice("flarum-likes.forum.post.others_link",a,{count:a})))}return m(".Entry-likedBy",[N()("far fa-thumbs-up"),r.a.translator.transChoice("flarum-likes.forum.post.liked_by"+(e[0]===r.a.session.user?"_self":"")+"_text",o.length,{count:o.length,users:D()(o)})])}},n.participateButton=function(){var t=this;return r.a.session.user?r.a.session.user.attribute("carvingContestCanParticipate")?w.a.component({className:"Button Button--primary",onclick:function(){r.a.modal.show(V,{onsave:function(){r.a.modal.close(),t.refresh()}})}},r.a.translator.trans(Y+"participate")):r.a.session.user.attribute("carvingContestCouldParticipate")?w.a.component({className:"Button Button--primary",disabled:!0},r.a.translator.trans(Y+"already-participated")):null:null},n.view=function(){var t=this;if(null===this.entries)return m(".container",m("p",r.a.translator.trans(Y+"loading")));var e={"-likesCount":r.a.translator.trans(Y+"sort.mostLikes"),likesCount:r.a.translator.trans(Y+"sort.fewerLikes"),"-createdAt":r.a.translator.trans(Y+"sort.mostRecent"),createdAt:r.a.translator.trans(Y+"sort.leastRecent")};return m(".container",[m("h2",r.a.translator.trans(Y+"title")),this.participateButton()," ",S.a.component({buttonClassName:"Button",label:e[this.sort]},Object.keys(e).map((function(n){var o=e[n],a=t.sort===n;return w.a.component({icon:!a||"fas fa-check",onclick:function(){t.sort=n,t.refresh()},active:a},o)})))," ",w.a.component({icon:"fas fa-sync",className:"Button",onclick:function(){t.refresh()}},r.a.translator.trans(Y+"refresh")),m("div",this.entries.map((function(e){return m(".CarvingContestEntry",{key:e.id()},[m(U,{image:e.image()}),m("h3.CarvingContestEntry--name",e.name()),m("p",[_()(e.user()),O()(e.user())," - ",L()(e.createdAt())]),r.a.forum.attribute("carvingContestCanModerate")?w.a.component({className:"Button Button--icon CarvingContestEntry--delete",icon:"fas fa-trash",onclick:function(){confirm(T()(r.a.translator.trans(Y+"delete-confirmation",{name:e.name(),user:e.user()})))&&e.delete().then((function(){t.refresh()}))}}):null,m(".CarvingContestEntry--vote",[t.likeButton(e),t.whoLiked(e)])])}))),this.loading?C.a.component():this.moreResults?w.a.component({className:"Button",onclick:this.loadMore.bind(this)},r.a.translator.trans(Y+"load-more")):null])},e}(b.a);r.a.initializers.add("carving-contest",(function(){r.a.store.models["carving-contest-entries"]=g,r.a.routes.carvingContest={path:"/carving-contest",component:G},Object(o.extend)(s.a.prototype,"navItems",(function(t){r.a.forum.attribute("carvingContestCanView")&&t.add("carving-contest",u.a.component({icon:"fas fa-spider",href:r.a.route("carvingContest")},r.a.translator.trans("clarkwinkelmann-carving-contest.forum.nav.contest")))}))}))}]); +module.exports=function(t){var e={};function n(o){if(e[o])return e[o].exports;var r=e[o]={i:o,l:!1,exports:{}};return t[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}return n.m=t,n.c=e,n.d=function(t,e,o){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:o})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var r in t)n.d(o,r,function(e){return t[e]}.bind(null,r));return o},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=17)}([function(t,e){t.exports=flarum.core.compat.app},function(t,e){t.exports=flarum.core.compat["common/components/Button"]},function(t,e){t.exports=flarum.core.compat["common/Model"]},function(t,e){t.exports=flarum.core.compat["common/helpers/username"]},function(t,e){t.exports=flarum.core.compat["common/helpers/icon"]},function(t,e){t.exports=flarum.core.compat["common/components/Link"]},function(t,e){t.exports=flarum.core.compat["common/helpers/avatar"]},function(t,e){t.exports=flarum.core.compat["common/components/Modal"]},function(t,e){t.exports=flarum.core.compat["common/extend"]},function(t,e){t.exports=flarum.core.compat["forum/components/IndexPage"]},function(t,e){t.exports=flarum.core.compat["common/components/LinkButton"]},function(t,e){t.exports=flarum.core.compat["common/components/Page"]},function(t,e){t.exports=flarum.core.compat["common/components/LoadingIndicator"]},function(t,e){t.exports=flarum.core.compat["common/components/Dropdown"]},function(t,e){t.exports=flarum.core.compat["common/helpers/humanTime"]},function(t,e){t.exports=flarum.core.compat["common/helpers/punctuateSeries"]},function(t,e){t.exports=flarum.core.compat["common/utils/extractText"]},function(t,e,n){"use strict";n.r(e);var o=n(8),r=n(0),a=n.n(r),i=n(9),s=n.n(i),c=n(10),u=n.n(c);function l(t){if(void 0===t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return t}function f(t,e){return(f=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function h(t,e){t.prototype=Object.create(e.prototype),t.prototype.constructor=t,f(t,e)}function d(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var p=n(2),v=n.n(p),g=function(t){function e(){for(var e,n=arguments.length,o=new Array(n),r=0;r0&&(e.data[o]=0,e.data[o+1]=0,e.data[o+2]=0,e.data[o+3]=0);this.previewContext.putImageData(e,0,0)}t&&(this.previewContext.strokeStyle="rgba(0,0,0,0.5)",this.previewContext.lineWidth=3,this.drawWithTool(this.previewContext,t.x,t.y))}},t}(),z=function(){d(this,"color",null),d(this,"shape","circle"),d(this,"width",30)},V="clarkwinkelmann-carving-contest.forum.modal.",X=function(t){function e(){for(var e,n=arguments.length,o=new Array(n),r=0;r4,o=e.sort((function(t){return t===a.a.session.user?-1:1})).slice(0,n?3:4).map((function(t){return m(E.a,{href:a.a.route.user(t)},t===a.a.session.user?a.a.translator.trans("flarum-likes.forum.post.you_text"):O()(t))}));if(n){var r=e.length-o.length;o.push(m("a",{href:"#",onclick:function(e){e.preventDefault(),a.a.modal.show(Y,{entry:t})}},a.a.translator.transChoice("flarum-likes.forum.post.others_link",r,{count:r})))}return m(".Entry-likedBy",[N()("far fa-thumbs-up"),a.a.translator.transChoice("flarum-likes.forum.post.liked_by"+(e[0]===a.a.session.user?"_self":"")+"_text",o.length,{count:o.length,users:T()(o)})])}},n.participateButton=function(){var t=this;return a.a.session.user?a.a.session.user.attribute("carvingContestCanParticipate")?k.a.component({className:"Button Button--primary",onclick:function(){a.a.modal.show(X,{onsave:function(){a.a.modal.close(),t.refresh()}})}},a.a.translator.trans(G+"participate")):a.a.session.user.attribute("carvingContestCouldParticipate")?k.a.component({className:"Button Button--primary",disabled:!0},a.a.translator.trans(G+"already-participated")):null:null},n.view=function(){var t=this;if(null===this.entries)return m(".container",m("p",a.a.translator.trans(G+"loading")));var e={"-likesCount":a.a.translator.trans(G+"sort.mostLikes"),likesCount:a.a.translator.trans(G+"sort.fewerLikes"),"-createdAt":a.a.translator.trans(G+"sort.mostRecent"),createdAt:a.a.translator.trans(G+"sort.leastRecent")};return m(".container",[m("h2",a.a.translator.trans(G+"title")),this.participateButton()," ",M.a.component({buttonClassName:"Button",label:e[this.sort]},Object.keys(e).map((function(n){var o=e[n],r=t.sort===n;return k.a.component({icon:!r||"fas fa-check",onclick:function(){t.sort=n,t.refresh()},active:r},o)})))," ",k.a.component({icon:"fas fa-sync",className:"Button",onclick:function(){t.refresh()}},a.a.translator.trans(G+"refresh")),m("div",this.entries.map((function(e){return m(".CarvingContestEntry",{key:e.id()},[m(U,{mode:a.a.forum.attribute("carvingContestColorMode")?"color":"carve",image:e.image()}),m("h3.CarvingContestEntry--name",e.name()),m("p",[R()(e.user()),O()(e.user())," - ",S()(e.createdAt())]),a.a.forum.attribute("carvingContestCanModerate")?k.a.component({className:"Button Button--icon CarvingContestEntry--delete",icon:"fas fa-trash",onclick:function(){confirm(q()(a.a.translator.trans(G+"delete-confirmation",{name:e.name(),user:e.user()})))&&e.delete().then((function(){t.refresh()}))}}):null,m(".CarvingContestEntry--vote",[t.likeButton(e),t.whoLiked(e)])])}))),this.loading?x.a.component():this.moreResults?k.a.component({className:"Button",onclick:this.loadMore.bind(this)},a.a.translator.trans(G+"load-more")):null])},e}(C.a);a.a.initializers.add("carving-contest",(function(){a.a.store.models["carving-contest-entries"]=g,a.a.routes.carvingContest={path:"/carving-contest",component:H},Object(o.extend)(s.a.prototype,"navItems",(function(t){a.a.forum.attribute("carvingContestCanView")&&t.add("carving-contest",u.a.component({icon:"fas fa-spider",href:a.a.route("carvingContest")},a.a.translator.trans("clarkwinkelmann-carving-contest.forum.nav.contest")))}))}))}]); //# sourceMappingURL=forum.js.map \ No newline at end of file diff --git a/js/dist/forum.js.map b/js/dist/forum.js.map index 4ca9822..e07c8c2 100644 --- a/js/dist/forum.js.map +++ b/js/dist/forum.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack://@clarkwinkelmann/carving-contest/webpack/bootstrap","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['app']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Button']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/Model']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/username']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/icon']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Link']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/avatar']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Modal']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/extend']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['forum/components/IndexPage']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/LinkButton']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Page']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/LoadingIndicator']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Dropdown']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/humanTime']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/punctuateSeries']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/utils/extractText']\"","webpack://@clarkwinkelmann/carving-contest/./node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js","webpack://@clarkwinkelmann/carving-contest/./node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js","webpack://@clarkwinkelmann/carving-contest/./node_modules/@babel/runtime/helpers/esm/inheritsLoose.js","webpack://@clarkwinkelmann/carving-contest/./node_modules/@babel/runtime/helpers/esm/defineProperty.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/models/Entry.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/components/PumpkinCanvas.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/components/ParticipateModal.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/components/EntryLikesModal.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/components/ContestPage.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/index.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","flarum","core","compat","_assertThisInitialized","self","ReferenceError","_setPrototypeOf","setPrototypeOf","__proto__","_inheritsLoose","subClass","superClass","constructor","_defineProperty","obj","configurable","writable","Entry","Model","attribute","transformDate","hasOne","hasMany","apiEndpoint","this","exists","data","id","PumpkinCanvas","oninit","vnode","previewContext","imageSourceCanvas","document","createElement","width","height","imageSourceContext","getContext","image","Image","src","app","forum","onload","drawImage","updatePreview","drawCanvas","drawContext","startingImage","attrs","onerror","err","console","error","onmouseup","drawEnabled","oncreate","addEventListener","dom","event","mouseMove","querySelector","onremove","removeEventListener","view","toolWidth","toolShape","rect","target","getBoundingClientRect","x","clientX","left","y","clientY","top","fillStyle","drawWithTool","onchange","canvas","toDataURL","context","fill","beginPath","arc","Math","PI","stroke","fillRect","toolPosition","imageSourceData","getImageData","drawData","length","clearRect","putImageData","strokeStyle","lineWidth","translationPrefix","ParticipateModal","className","title","translator","trans","checkIfDisabled","previouslyDisabled","disabled","redraw","content","Button","component","icon","onclick","type","step","min","max","parseInt","loading","store","createRecord","save","then","onsave","Modal","PostLikesModal","entry","likes","map","user","Link","href","route","avatar","username","ContestPage","moreResults","entries","sort","refresh","loadResults","offset","preloadedEntries","preloadedApiDocument","Promise","resolve","find","page","results","parseResults","loadMore","push","apply","payload","links","next","likeButton","canLike","isLiked","session","some","relationships","like","splice","unshift","whoLiked","overLimit","names","a","slice","limit","count","e","preventDefault","modal","show","EntryLikesModal","transChoice","users","punctuateSeries","participateButton","close","sortOptions","Dropdown","buttonClassName","label","keys","active","humanTime","createdAt","confirm","extractText","LoadingIndicator","Page","initializers","add","models","routes","carvingContest","path","extend","IndexPage","items","LinkButton"],"mappings":"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","file":"forum.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, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\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\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 17);\n","module.exports = flarum.core.compat['app'];","module.exports = flarum.core.compat['common/components/Button'];","module.exports = flarum.core.compat['common/Model'];","module.exports = flarum.core.compat['common/helpers/username'];","module.exports = flarum.core.compat['common/helpers/icon'];","module.exports = flarum.core.compat['common/components/Link'];","module.exports = flarum.core.compat['common/helpers/avatar'];","module.exports = flarum.core.compat['common/components/Modal'];","module.exports = flarum.core.compat['common/extend'];","module.exports = flarum.core.compat['forum/components/IndexPage'];","module.exports = flarum.core.compat['common/components/LinkButton'];","module.exports = flarum.core.compat['common/components/Page'];","module.exports = flarum.core.compat['common/components/LoadingIndicator'];","module.exports = flarum.core.compat['common/components/Dropdown'];","module.exports = flarum.core.compat['common/helpers/humanTime'];","module.exports = flarum.core.compat['common/helpers/punctuateSeries'];","module.exports = flarum.core.compat['common/utils/extractText'];","export default function _assertThisInitialized(self) {\n if (self === void 0) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return self;\n}","export default function _setPrototypeOf(o, p) {\n _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n };\n\n return _setPrototypeOf(o, p);\n}","import setPrototypeOf from \"./setPrototypeOf.js\";\nexport default function _inheritsLoose(subClass, superClass) {\n subClass.prototype = Object.create(superClass.prototype);\n subClass.prototype.constructor = subClass;\n setPrototypeOf(subClass, superClass);\n}","export default function _defineProperty(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n\n return obj;\n}","import Model from 'flarum/common/Model';\n\nexport default class Entry extends Model {\n name = Model.attribute('name');\n image = Model.attribute('image');\n createdAt = Model.attribute('createdAt', Model.transformDate);\n canLike = Model.attribute('canLike');\n\n user = Model.hasOne('user');\n likes = Model.hasMany('likes');\n\n apiEndpoint() {\n return '/carving-contest/entries' + (this.exists ? '/' + this.data.id : '');\n }\n}\n","import app from 'flarum/app';\n\n/* global m */\n\nconst IMAGE_WIDTH = 426;\nconst IMAGE_HEIGHT = 426;\n\nexport default class PumpkinCanvas {\n oninit(vnode) {\n this.previewContext = null;\n\n const imageSourceCanvas = document.createElement('canvas');\n imageSourceCanvas.width = IMAGE_WIDTH;\n imageSourceCanvas.height = IMAGE_HEIGHT;\n this.imageSourceContext = imageSourceCanvas.getContext('2d');\n const image = new Image();\n image.src = app.forum.attribute('baseUrl') + '/assets/extensions/clarkwinkelmann-carving-contest/pumpkin.jpg';\n image.onload = () => {\n this.imageSourceContext.drawImage(image, 0, 0);\n\n this.updatePreview();\n };\n\n const drawCanvas = document.createElement('canvas');\n drawCanvas.width = IMAGE_WIDTH;\n drawCanvas.height = IMAGE_HEIGHT;\n this.drawContext = drawCanvas.getContext('2d');\n\n const startingImage = vnode.attrs.image;\n if (startingImage) {\n const image = new Image();\n image.src = startingImage;\n image.onload = () => {\n this.drawContext.drawImage(image, 0, 0);\n\n this.updatePreview();\n };\n image.onerror = err => {\n console.error('Error loading image', err);\n };\n }\n\n this.onmouseup = () => {\n this.drawEnabled = false;\n };\n }\n\n oncreate(vnode) {\n document.addEventListener('mouseup', this.onmouseup);\n\n vnode.dom.addEventListener('mousedown', event => {\n this.drawEnabled = true;\n\n this.mouseMove(vnode, event);\n });\n vnode.dom.addEventListener('mousemove', this.mouseMove.bind(this, vnode));\n vnode.dom.addEventListener('mouseleave', () => {\n // To remove the tool from preview\n this.updatePreview();\n });\n\n this.previewContext = vnode.dom.querySelector('canvas').getContext('2d');\n\n this.updatePreview();\n }\n\n onremove() {\n document.removeEventListener('mouseup', this.onmouseup);\n }\n\n view(vnode) {\n this.toolWidth = vnode.attrs.toolWidth;\n this.toolShape = vnode.attrs.toolShape;\n\n return m('.CarvingContestPumpkin', m('canvas', {\n width: IMAGE_WIDTH,\n height: IMAGE_HEIGHT,\n }));\n }\n\n mouseMove(vnode, event) {\n const rect = event.target.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n\n if (this.drawEnabled) {\n this.drawContext.fillStyle = '#000';\n this.drawWithTool(this.drawContext, x, y, true);\n\n vnode.attrs.onchange(this.drawContext.canvas.toDataURL('image/png'));\n }\n\n this.updatePreview({\n x,\n y,\n });\n }\n\n drawWithTool(context, x, y, fill = false) {\n const width = this.toolWidth;\n\n switch (this.toolShape) {\n case 'circle':\n context.beginPath();\n context.arc(x, y, width / 2, 0, 2 * Math.PI);\n\n if (fill) {\n context.fill();\n } else {\n context.stroke();\n }\n break;\n case 'square':\n context.fillRect(x - (width / 2), y - (width / 2), width, width);\n break;\n }\n }\n\n updatePreview(toolPosition = null) {\n if (!this.previewContext) {\n return;\n }\n\n const imageSourceData = this.imageSourceContext.getImageData(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);\n const drawData = this.drawContext.getImageData(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);\n\n for (let i = 0; i < imageSourceData.data.length; i += 4) {\n // If the pixel in that area has an alpha value greater than 0, we create a hole in the image data\n // Returning 0 for every index will give rgba(0,0,0,0)\n if (drawData.data[i + 3] > 0) {\n imageSourceData.data[i] = 0;\n imageSourceData.data[i + 1] = 0;\n imageSourceData.data[i + 2] = 0;\n imageSourceData.data[i + 3] = 0;\n }\n }\n\n this.previewContext.clearRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);\n this.previewContext.putImageData(imageSourceData, 0, 0);\n\n if (toolPosition) {\n this.previewContext.strokeStyle = 'rgba(0,0,0,0.5)';\n this.previewContext.lineWidth = 3;\n this.drawWithTool(this.previewContext, toolPosition.x, toolPosition.y);\n }\n }\n}\n","import app from 'flarum/app';\nimport Modal from 'flarum/common/components/Modal';\nimport Button from 'flarum/common/components/Button';\nimport PumpkinCanvas from './PumpkinCanvas';\n\nconst translationPrefix = 'clarkwinkelmann-carving-contest.forum.modal.';\n\n/* global m */\n\nexport default class ParticipateModal extends Modal {\n toolShape = 'circle';\n toolWidth = 30;\n name = '';\n image = '';\n disabled = true;\n loading = false;\n\n className() {\n return 'Modal--large';\n }\n\n title() {\n return app.translator.trans(translationPrefix + 'title');\n }\n\n checkIfDisabled() {\n const previouslyDisabled = this.disabled;\n\n this.disabled = this.name === '' || this.image === '';\n\n // Handle disabled state redraw when the image changes (because we don't redraw every time it changes)\n if (previouslyDisabled !== this.disabled) {\n m.redraw();\n }\n }\n\n content() {\n return m('.Modal-body', [\n m('.Form-group', [\n m('.CarvingContestTools', [\n Button.component({\n disabled: this.toolShape === 'circle',\n icon: 'fas fa-circle',\n className: 'Button',\n onclick: () => {\n this.toolShape = 'circle';\n },\n }, app.translator.trans(translationPrefix + 'tools.circle')),\n Button.component({\n disabled: this.toolShape === 'square',\n icon: 'fas fa-square',\n className: 'Button',\n onclick: () => {\n this.toolShape = 'square';\n },\n }, app.translator.trans(translationPrefix + 'tools.square')),\n m('input', {\n type: 'range',\n step: 2,\n min: 10,\n max: 50,\n value: this.toolWidth,\n onchange: event => {\n this.toolWidth = parseInt(event.target.value);\n },\n }),\n ]),\n m(PumpkinCanvas, {\n toolShape: this.toolShape,\n toolWidth: this.toolWidth,\n image: this.image,\n onchange: value => {\n this.image = value;\n\n this.checkIfDisabled();\n },\n }),\n ]),\n m('.Form-group', [\n m('label', app.translator.trans(translationPrefix + 'name')),\n m('input[type=text].FormControl', {\n value: this.name,\n onchange: event => {\n this.name = event.target.value;\n\n this.checkIfDisabled();\n },\n }),\n ]),\n m('.Form-group', [\n Button.component({\n loading: this.loading,\n disabled: this.disabled,\n className: 'Button Button--primary',\n onclick: () => {\n app.store.createRecord('carving-contest-entries').save({\n name: this.name,\n image: this.image,\n }).then(() => {\n this.attrs.onsave();\n });\n },\n }, app.translator.trans(translationPrefix + 'submit')),\n ]),\n ]);\n }\n}\n","import app from 'flarum/app';\nimport Modal from 'flarum/common/components/Modal';\nimport Link from 'flarum/common/components/Link';\nimport avatar from 'flarum/common/helpers/avatar';\nimport username from 'flarum/common/helpers/username';\n\n/* global m */\n\nexport default class PostLikesModal extends Modal {\n className() {\n return 'EntryLikesModal Modal--small';\n }\n\n title() {\n return app.translator.trans('clarkwinkelmann-carving-contest.forum.likes_modal.title');\n }\n\n content() {\n return m('.Modal-body', m('ul.EntryLikesModal-list', this.attrs.entry.likes().map(user => m('li', m(Link, {\n href: app.route.user(user),\n }, [\n avatar(user),\n ' ',\n username(user),\n ])))));\n }\n}\n","import app from 'flarum/app';\nimport Page from 'flarum/common/components/Page';\nimport Button from 'flarum/common/components/Button';\nimport LoadingIndicator from 'flarum/common/components/LoadingIndicator';\nimport Dropdown from 'flarum/common/components/Dropdown';\nimport Link from 'flarum/common/components/Link';\nimport humanTime from 'flarum/common/helpers/humanTime';\nimport avatar from 'flarum/common/helpers/avatar';\nimport username from 'flarum/common/helpers/username';\nimport icon from 'flarum/common/helpers/icon';\nimport punctuateSeries from 'flarum/common/helpers/punctuateSeries';\nimport extractText from 'flarum/common/utils/extractText';\nimport ParticipateModal from './ParticipateModal';\nimport PumpkinCanvas from './PumpkinCanvas';\nimport EntryLikesModal from './EntryLikesModal';\n\n/* global m */\n\nconst translationPrefix = 'clarkwinkelmann-carving-contest.forum.page.';\n\nexport default class ContestPage extends Page {\n oninit(vnode) {\n super.oninit(vnode);\n\n this.loading = true;\n this.moreResults = false;\n this.entries = [];\n this.sort = '-createdAt';\n\n this.refresh();\n }\n\n loadResults(offset) {\n const preloadedEntries = app.preloadedApiDocument();\n\n if (preloadedEntries) {\n return Promise.resolve(preloadedEntries);\n } else {\n return app.store.find('carving-contest/entries', {\n page: {\n offset,\n },\n sort: this.sort,\n });\n }\n }\n\n refresh() {\n this.loading = true;\n this.entries = null;\n\n return this.loadResults().then(\n results => {\n this.entries = [];\n this.parseResults(results);\n },\n () => {\n this.loading = false;\n m.redraw();\n }\n );\n }\n\n loadMore() {\n this.loading = true;\n\n this.loadResults(this.entries.length)\n .then(this.parseResults.bind(this));\n }\n\n parseResults(results) {\n [].push.apply(this.entries, results);\n\n this.loading = false;\n this.moreResults = !!results.payload.links.next;\n\n m.redraw();\n }\n\n likeButton(entry) {\n if (!entry.canLike()) {\n return null;\n }\n\n const likes = entry.likes();\n const isLiked = app.session.user && likes && likes.some(user => user === app.session.user);\n\n return Button.component({\n className: 'Button Button--block' + (isLiked ? ' Button--primary Button-already-liked' : ''),\n onclick: () => {\n entry.save({\n isLiked: !isLiked,\n });\n\n // We've saved the fact that we do or don't like the entry, but in order\n // to provide instantaneous feedback to the user, we'll need to add or\n // remove the like from the relationship data manually.\n const data = entry.data.relationships.likes.data;\n data.some((like, i) => {\n if (like.id === app.session.user.id()) {\n data.splice(i, 1);\n return true;\n }\n });\n\n if (!isLiked) {\n data.unshift({type: 'users', id: app.session.user.id()});\n }\n }\n }, isLiked ? [\n m('span.already-liked', [\n icon('far fa-thumbs-up'),\n ' ',\n app.translator.trans(translationPrefix + 'already-liked'),\n ]),\n m('span.remove-like', [\n icon('far fa-thumbs-down'),\n ' ',\n app.translator.trans(translationPrefix + 'unlike'),\n ])\n ] : [\n icon('far fa-thumbs-up'),\n ' ',\n app.translator.trans(translationPrefix + 'like'),\n ]);\n }\n\n whoLiked(entry) {\n const likes = entry.likes();\n\n if (!likes || !likes.length) {\n return;\n }\n\n const limit = 4;\n const overLimit = likes.length > limit;\n\n // Construct a list of names of users who have liked this post. Make sure the\n // current user is first in the list, and cap a maximum of 4 items.\n const names = likes.sort(a => a === app.session.user ? -1 : 1)\n .slice(0, overLimit ? limit - 1 : limit)\n .map(user => m(Link, {\n href: app.route.user(user),\n }, user === app.session.user ? app.translator.trans('flarum-likes.forum.post.you_text') : username(user)));\n\n // If there are more users that we've run out of room to display, add a \"x\n // others\" name to the end of the list. Clicking on it will display a modal\n // with a full list of names.\n if (overLimit) {\n const count = likes.length - names.length;\n\n names.push(m('a', {\n href: '#',\n onclick: e => {\n e.preventDefault();\n app.modal.show(EntryLikesModal, {\n entry,\n });\n },\n }, app.translator.transChoice('flarum-likes.forum.post.others_link', count, {count})));\n }\n\n return m('.Entry-likedBy', [\n icon('far fa-thumbs-up'),\n app.translator.transChoice('flarum-likes.forum.post.liked_by' + (likes[0] === app.session.user ? '_self' : '') + '_text', names.length, {\n count: names.length,\n users: punctuateSeries(names)\n }),\n ]);\n }\n\n participateButton() {\n if (!app.session.user) {\n return null;\n }\n\n if (app.session.user.attribute('carvingContestCanParticipate')) {\n return Button.component({\n className: 'Button Button--primary',\n onclick: () => {\n app.modal.show(ParticipateModal, {\n onsave: () => {\n app.modal.close();\n this.refresh();\n },\n });\n },\n }, app.translator.trans(translationPrefix + 'participate'));\n }\n\n if (app.session.user.attribute('carvingContestCouldParticipate')) {\n return Button.component({\n className: 'Button Button--primary',\n disabled: true,\n }, app.translator.trans(translationPrefix + 'already-participated'));\n }\n\n return null;\n }\n\n view() {\n if (this.entries === null) {\n return m('.container', m('p', app.translator.trans(translationPrefix + 'loading')));\n }\n\n const sortOptions = {\n '-likesCount': app.translator.trans(translationPrefix + 'sort.mostLikes'),\n 'likesCount': app.translator.trans(translationPrefix + 'sort.fewerLikes'),\n '-createdAt': app.translator.trans(translationPrefix + 'sort.mostRecent'),\n 'createdAt': app.translator.trans(translationPrefix + 'sort.leastRecent'),\n };\n\n return m('.container', [\n m('h2', app.translator.trans(translationPrefix + 'title')),\n this.participateButton(),\n ' ',\n Dropdown.component({\n buttonClassName: 'Button',\n label: sortOptions[this.sort],\n }, Object.keys(sortOptions).map(value => {\n const label = sortOptions[value];\n const active = this.sort === value;\n\n return Button.component({\n icon: active ? 'fas fa-check' : true,\n onclick: () => {\n this.sort = value;\n this.refresh();\n },\n active,\n }, label);\n })),\n ' ',\n Button.component({\n icon: 'fas fa-sync',\n className: 'Button',\n onclick: () => {\n this.refresh();\n },\n }, app.translator.trans(translationPrefix + 'refresh')),\n m('div', this.entries.map(entry => m('.CarvingContestEntry', {\n key: entry.id(), // Without this, canvas are re-used, causing incorrect images to be shown when one is deleted\n }, [\n m(PumpkinCanvas, {\n image: entry.image(),\n }),\n m('h3.CarvingContestEntry--name', entry.name()),\n m('p', [\n avatar(entry.user()),\n username(entry.user()),\n ' - ',\n humanTime(entry.createdAt()),\n ]),\n app.forum.attribute('carvingContestCanModerate') ? Button.component({\n className: 'Button Button--icon CarvingContestEntry--delete',\n icon: 'fas fa-trash',\n onclick: () => {\n if (!confirm(extractText(app.translator.trans(translationPrefix + 'delete-confirmation', {\n name: entry.name(),\n user: entry.user(),\n })))) {\n return;\n }\n\n entry.delete().then(() => {\n this.refresh();\n });\n },\n }) : null,\n m('.CarvingContestEntry--vote', [\n this.likeButton(entry),\n this.whoLiked(entry),\n ]),\n ]))),\n this.loading ? LoadingIndicator.component() : (this.moreResults ? Button.component({\n className: 'Button',\n onclick: this.loadMore.bind(this),\n }, app.translator.trans(translationPrefix + 'load-more')) : null),\n ]);\n }\n}\n","import {extend} from 'flarum/common/extend';\nimport app from 'flarum/app';\nimport IndexPage from 'flarum/forum/components/IndexPage';\nimport LinkButton from 'flarum/common/components/LinkButton';\nimport Entry from './models/Entry';\nimport ContestPage from './components/ContestPage';\n\n/* global m */\n\napp.initializers.add('carving-contest', () => {\n app.store.models['carving-contest-entries'] = Entry;\n\n app.routes.carvingContest = {\n path: '/carving-contest',\n component: ContestPage,\n };\n\n extend(IndexPage.prototype, 'navItems', function (items) {\n if (!app.forum.attribute('carvingContestCanView')) {\n return;\n }\n\n items.add('carving-contest', LinkButton.component({\n icon: 'fas fa-spider',\n href: app.route('carvingContest'),\n }, app.translator.trans('clarkwinkelmann-carving-contest.forum.nav.contest')));\n });\n});\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack://@clarkwinkelmann/carving-contest/webpack/bootstrap","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['app']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Button']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/Model']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/username']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/icon']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Link']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/avatar']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Modal']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/extend']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['forum/components/IndexPage']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/LinkButton']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Page']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/LoadingIndicator']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/components/Dropdown']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/humanTime']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/helpers/punctuateSeries']\"","webpack://@clarkwinkelmann/carving-contest/external \"flarum.core.compat['common/utils/extractText']\"","webpack://@clarkwinkelmann/carving-contest/./node_modules/@babel/runtime/helpers/esm/assertThisInitialized.js","webpack://@clarkwinkelmann/carving-contest/./node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js","webpack://@clarkwinkelmann/carving-contest/./node_modules/@babel/runtime/helpers/esm/inheritsLoose.js","webpack://@clarkwinkelmann/carving-contest/./node_modules/@babel/runtime/helpers/esm/defineProperty.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/models/Entry.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/components/PumpkinCanvas.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/states/BrushState.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/components/ParticipateModal.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/components/EntryLikesModal.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/components/ContestPage.js","webpack://@clarkwinkelmann/carving-contest/./src/forum/index.js"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","flarum","core","compat","_assertThisInitialized","self","ReferenceError","_setPrototypeOf","setPrototypeOf","__proto__","_inheritsLoose","subClass","superClass","constructor","_defineProperty","obj","configurable","writable","Entry","Model","attribute","transformDate","hasOne","hasMany","apiEndpoint","this","exists","data","id","PumpkinCanvas","oninit","vnode","attrs","brush","previewContext","imageSourceCanvas","document","createElement","width","height","imageSourceContext","getContext","image","Image","src","app","forum","onload","drawImage","updatePreview","drawCanvas","drawContext","startingImage","onerror","err","console","error","onmouseup","drawEnabled","oncreate","addEventListener","dom","event","mouseMove","querySelector","onremove","removeEventListener","view","rect","target","getBoundingClientRect","x","clientX","left","y","clientY","top","fillStyle","color","drawWithTool","onchange","canvas","toDataURL","context","fill","beginPath","shape","arc","Math","PI","stroke","toolPosition","clearRect","imageSourceData","getImageData","drawData","length","putImageData","strokeStyle","lineWidth","BrushState","translationPrefix","ParticipateModal","className","title","translator","trans","checkIfDisabled","previouslyDisabled","disabled","redraw","colorChoice","colorOptions","colors","type","split","map","style","backgroundColor","onclick","colorTools","content","Button","component","icon","step","min","max","parseInt","loading","store","createRecord","save","then","onsave","Modal","PostLikesModal","entry","likes","user","Link","href","route","avatar","username","ContestPage","moreResults","entries","sort","refresh","loadResults","offset","preloadedEntries","preloadedApiDocument","Promise","resolve","find","page","results","parseResults","loadMore","push","apply","payload","links","next","likeButton","canLike","isLiked","session","some","relationships","like","splice","unshift","whoLiked","overLimit","names","a","slice","limit","count","e","preventDefault","modal","show","EntryLikesModal","transChoice","users","punctuateSeries","participateButton","close","sortOptions","Dropdown","buttonClassName","label","keys","active","humanTime","createdAt","confirm","extractText","LoadingIndicator","Page","initializers","add","models","routes","carvingContest","path","extend","IndexPage","items","LinkButton"],"mappings":"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","file":"forum.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, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\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\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 17);\n","module.exports = flarum.core.compat['app'];","module.exports = flarum.core.compat['common/components/Button'];","module.exports = flarum.core.compat['common/Model'];","module.exports = flarum.core.compat['common/helpers/username'];","module.exports = flarum.core.compat['common/helpers/icon'];","module.exports = flarum.core.compat['common/components/Link'];","module.exports = flarum.core.compat['common/helpers/avatar'];","module.exports = flarum.core.compat['common/components/Modal'];","module.exports = flarum.core.compat['common/extend'];","module.exports = flarum.core.compat['forum/components/IndexPage'];","module.exports = flarum.core.compat['common/components/LinkButton'];","module.exports = flarum.core.compat['common/components/Page'];","module.exports = flarum.core.compat['common/components/LoadingIndicator'];","module.exports = flarum.core.compat['common/components/Dropdown'];","module.exports = flarum.core.compat['common/helpers/humanTime'];","module.exports = flarum.core.compat['common/helpers/punctuateSeries'];","module.exports = flarum.core.compat['common/utils/extractText'];","export default function _assertThisInitialized(self) {\n if (self === void 0) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return self;\n}","export default function _setPrototypeOf(o, p) {\n _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n };\n\n return _setPrototypeOf(o, p);\n}","import setPrototypeOf from \"./setPrototypeOf.js\";\nexport default function _inheritsLoose(subClass, superClass) {\n subClass.prototype = Object.create(superClass.prototype);\n subClass.prototype.constructor = subClass;\n setPrototypeOf(subClass, superClass);\n}","export default function _defineProperty(obj, key, value) {\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n\n return obj;\n}","import Model from 'flarum/common/Model';\n\nexport default class Entry extends Model {\n name = Model.attribute('name');\n image = Model.attribute('image');\n createdAt = Model.attribute('createdAt', Model.transformDate);\n canLike = Model.attribute('canLike');\n\n user = Model.hasOne('user');\n likes = Model.hasMany('likes');\n\n apiEndpoint() {\n return '/carving-contest/entries' + (this.exists ? '/' + this.data.id : '');\n }\n}\n","import app from 'flarum/app';\n\n/* global m */\n\nconst IMAGE_WIDTH = 426;\nconst IMAGE_HEIGHT = 426;\n\nexport default class PumpkinCanvas {\n oninit(vnode) {\n this.mode = vnode.attrs.mode;\n this.brush = vnode.attrs.brush;\n\n this.previewContext = null;\n\n this.imageSourceCanvas = document.createElement('canvas');\n this.imageSourceCanvas.width = IMAGE_WIDTH;\n this.imageSourceCanvas.height = IMAGE_HEIGHT;\n this.imageSourceContext = this.imageSourceCanvas.getContext('2d');\n const image = new Image();\n image.src = app.forum.attribute('baseUrl') + '/assets/extensions/clarkwinkelmann-carving-contest/pumpkin.jpg';\n image.onload = () => {\n this.imageSourceContext.drawImage(image, 0, 0);\n\n this.updatePreview();\n };\n\n this.drawCanvas = document.createElement('canvas');\n this.drawCanvas.width = IMAGE_WIDTH;\n this.drawCanvas.height = IMAGE_HEIGHT;\n this.drawContext = this.drawCanvas.getContext('2d');\n\n const startingImage = vnode.attrs.image;\n if (startingImage) {\n const image = new Image();\n image.src = startingImage;\n image.onload = () => {\n this.drawContext.drawImage(image, 0, 0);\n\n this.updatePreview();\n };\n image.onerror = err => {\n console.error('Error loading image', err);\n };\n }\n\n this.onmouseup = () => {\n this.drawEnabled = false;\n };\n }\n\n oncreate(vnode) {\n document.addEventListener('mouseup', this.onmouseup);\n\n vnode.dom.addEventListener('mousedown', event => {\n this.drawEnabled = true;\n\n this.mouseMove(vnode, event);\n });\n vnode.dom.addEventListener('mousemove', this.mouseMove.bind(this, vnode));\n vnode.dom.addEventListener('mouseleave', () => {\n // To remove the tool from preview\n this.updatePreview();\n });\n\n this.previewContext = vnode.dom.querySelector('canvas').getContext('2d');\n\n this.updatePreview();\n }\n\n onremove() {\n document.removeEventListener('mouseup', this.onmouseup);\n }\n\n view() {\n return m('.CarvingContestPumpkin', m('canvas', {\n width: IMAGE_WIDTH,\n height: IMAGE_HEIGHT,\n }));\n }\n\n mouseMove(vnode, event) {\n const rect = event.target.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n\n if (this.drawEnabled && this.brush) {\n if (this.mode === 'color') {\n this.drawContext.fillStyle = this.brush.color;\n } else {\n this.drawContext.fillStyle = '#000';\n }\n this.drawWithTool(this.drawContext, x, y, true);\n\n vnode.attrs.onchange(this.drawContext.canvas.toDataURL('image/png'));\n }\n\n this.updatePreview({\n x,\n y,\n });\n }\n\n drawWithTool(context, x, y, fill = false) {\n if (!this.brush) {\n return;\n }\n\n const width = this.brush.width;\n\n context.beginPath();\n\n switch (this.brush.shape) {\n case 'circle':\n context.arc(x, y, width / 2, 0, 2 * Math.PI);\n break;\n case 'square':\n context.rect(x - (width / 2), y - (width / 2), width, width);\n break;\n }\n\n if (fill) {\n context.fill();\n } else {\n context.stroke();\n }\n }\n\n updatePreview(toolPosition = null) {\n if (!this.previewContext) {\n return;\n }\n\n this.previewContext.clearRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);\n\n if (this.mode === 'color') {\n // In paint mode, we draw the two images on top of another\n this.previewContext.drawImage(this.imageSourceCanvas, 0, 0);\n this.previewContext.drawImage(this.drawCanvas, 0, 0);\n } else {\n // In carve mode, we subtract the drawing from the source\n const imageSourceData = this.imageSourceContext.getImageData(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);\n const drawData = this.drawContext.getImageData(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT);\n\n for (let i = 0; i < imageSourceData.data.length; i += 4) {\n // If the pixel in that area has an alpha value greater than 0, we create a hole in the image data\n // Returning 0 for every index will give rgba(0,0,0,0)\n if (drawData.data[i + 3] > 0) {\n imageSourceData.data[i] = 0;\n imageSourceData.data[i + 1] = 0;\n imageSourceData.data[i + 2] = 0;\n imageSourceData.data[i + 3] = 0;\n }\n }\n\n this.previewContext.putImageData(imageSourceData, 0, 0);\n }\n\n if (toolPosition) {\n this.previewContext.strokeStyle = 'rgba(0,0,0,0.5)';\n this.previewContext.lineWidth = 3;\n this.drawWithTool(this.previewContext, toolPosition.x, toolPosition.y);\n }\n }\n}\n","export default class BrushState {\n color = null;\n shape = 'circle';\n width = 30;\n}\n","import app from 'flarum/app';\nimport Modal from 'flarum/common/components/Modal';\nimport Button from 'flarum/common/components/Button';\nimport PumpkinCanvas from './PumpkinCanvas';\nimport BrushState from '../states/BrushState';\n\nconst translationPrefix = 'clarkwinkelmann-carving-contest.forum.modal.';\n\n/* global m */\n\nexport default class ParticipateModal extends Modal {\n brush = new BrushState();\n name = '';\n image = '';\n disabled = true;\n loading = false;\n\n className() {\n return 'Modal--large';\n }\n\n title() {\n return app.translator.trans(translationPrefix + 'title');\n }\n\n checkIfDisabled() {\n const previouslyDisabled = this.disabled;\n\n this.disabled = this.name === '' || this.image === '';\n\n // Handle disabled state redraw when the image changes (because we don't redraw every time it changes)\n if (previouslyDisabled !== this.disabled) {\n m.redraw();\n }\n }\n\n colorChoice() {\n const colors = app.forum.attribute('carvingContestColors');\n\n if (colors === 'all') {\n return m('input', {\n type: 'color',\n value: this.brush.color,\n onchange: event => {\n this.brush.color = event.target.value;\n },\n });\n }\n\n let colorOptions;\n\n if (colors === 'simple') {\n colorOptions = [\n '#f32501', // Red\n '#ff8d12', // Orange\n '#ffe884', // Yellow\n '#94ae3f', // Green\n '#084f93', // Blue\n '#000000', // Black\n ];\n } else {\n colorOptions = app.forum.attribute('carvingContestColors').split(',');\n }\n\n return m('div', colorOptions.map(color => m('.CarvingContest-ColorChoice', {\n style: {\n backgroundColor: color,\n },\n onclick: () => {\n this.brush.color = color;\n },\n className: this.brush.color === color ? 'selected' : '',\n })));\n }\n\n colorTools() {\n if (!app.forum.attribute('carvingContestColorMode')) {\n return null;\n }\n\n return m('.CarvingContestTools', [\n this.colorChoice(),\n ]);\n }\n\n content() {\n return m('.Modal-body', [\n m('.Form-group', [\n this.colorTools(),\n m('.CarvingContestTools', [\n Button.component({\n disabled: this.brush.shape === 'circle',\n icon: 'fas fa-circle',\n className: 'Button',\n onclick: () => {\n this.brush.shape = 'circle';\n },\n }, app.translator.trans(translationPrefix + 'tools.circle')),\n Button.component({\n disabled: this.brush.shape === 'square',\n icon: 'fas fa-square',\n className: 'Button',\n onclick: () => {\n this.brush.shape = 'square';\n },\n }, app.translator.trans(translationPrefix + 'tools.square')),\n m('input', {\n type: 'range',\n step: 2,\n min: 10,\n max: 50,\n value: this.brush.width,\n onchange: event => {\n this.brush.width = parseInt(event.target.value);\n },\n }),\n ]),\n m(PumpkinCanvas, {\n mode: app.forum.attribute('carvingContestColorMode') ? 'color' : 'carve',\n brush: this.brush,\n image: this.image,\n onchange: value => {\n this.image = value;\n\n this.checkIfDisabled();\n },\n }),\n ]),\n m('.Form-group', [\n m('label', app.translator.trans(translationPrefix + 'name')),\n m('input[type=text].FormControl', {\n value: this.name,\n onchange: event => {\n this.name = event.target.value;\n\n this.checkIfDisabled();\n },\n }),\n ]),\n m('.Form-group', [\n Button.component({\n loading: this.loading,\n disabled: this.disabled,\n className: 'Button Button--primary',\n onclick: () => {\n app.store.createRecord('carving-contest-entries').save({\n name: this.name,\n image: this.image,\n }).then(() => {\n this.attrs.onsave();\n });\n },\n }, app.translator.trans(translationPrefix + 'submit')),\n ]),\n ]);\n }\n}\n","import app from 'flarum/app';\nimport Modal from 'flarum/common/components/Modal';\nimport Link from 'flarum/common/components/Link';\nimport avatar from 'flarum/common/helpers/avatar';\nimport username from 'flarum/common/helpers/username';\n\n/* global m */\n\nexport default class PostLikesModal extends Modal {\n className() {\n return 'EntryLikesModal Modal--small';\n }\n\n title() {\n return app.translator.trans('clarkwinkelmann-carving-contest.forum.likes_modal.title');\n }\n\n content() {\n return m('.Modal-body', m('ul.EntryLikesModal-list', this.attrs.entry.likes().map(user => m('li', m(Link, {\n href: app.route.user(user),\n }, [\n avatar(user),\n ' ',\n username(user),\n ])))));\n }\n}\n","import app from 'flarum/app';\nimport Page from 'flarum/common/components/Page';\nimport Button from 'flarum/common/components/Button';\nimport LoadingIndicator from 'flarum/common/components/LoadingIndicator';\nimport Dropdown from 'flarum/common/components/Dropdown';\nimport Link from 'flarum/common/components/Link';\nimport humanTime from 'flarum/common/helpers/humanTime';\nimport avatar from 'flarum/common/helpers/avatar';\nimport username from 'flarum/common/helpers/username';\nimport icon from 'flarum/common/helpers/icon';\nimport punctuateSeries from 'flarum/common/helpers/punctuateSeries';\nimport extractText from 'flarum/common/utils/extractText';\nimport ParticipateModal from './ParticipateModal';\nimport PumpkinCanvas from './PumpkinCanvas';\nimport EntryLikesModal from './EntryLikesModal';\n\n/* global m */\n\nconst translationPrefix = 'clarkwinkelmann-carving-contest.forum.page.';\n\nexport default class ContestPage extends Page {\n oninit(vnode) {\n super.oninit(vnode);\n\n this.loading = true;\n this.moreResults = false;\n this.entries = [];\n this.sort = '-createdAt';\n\n this.refresh();\n }\n\n loadResults(offset) {\n const preloadedEntries = app.preloadedApiDocument();\n\n if (preloadedEntries) {\n return Promise.resolve(preloadedEntries);\n } else {\n return app.store.find('carving-contest/entries', {\n page: {\n offset,\n },\n sort: this.sort,\n });\n }\n }\n\n refresh() {\n this.loading = true;\n this.entries = null;\n\n return this.loadResults().then(\n results => {\n this.entries = [];\n this.parseResults(results);\n },\n () => {\n this.loading = false;\n m.redraw();\n }\n );\n }\n\n loadMore() {\n this.loading = true;\n\n this.loadResults(this.entries.length)\n .then(this.parseResults.bind(this));\n }\n\n parseResults(results) {\n [].push.apply(this.entries, results);\n\n this.loading = false;\n this.moreResults = !!results.payload.links.next;\n\n m.redraw();\n }\n\n likeButton(entry) {\n if (!entry.canLike()) {\n return null;\n }\n\n const likes = entry.likes();\n const isLiked = app.session.user && likes && likes.some(user => user === app.session.user);\n\n return Button.component({\n className: 'Button Button--block' + (isLiked ? ' Button--primary Button-already-liked' : ''),\n onclick: () => {\n entry.save({\n isLiked: !isLiked,\n });\n\n // We've saved the fact that we do or don't like the entry, but in order\n // to provide instantaneous feedback to the user, we'll need to add or\n // remove the like from the relationship data manually.\n const data = entry.data.relationships.likes.data;\n data.some((like, i) => {\n if (like.id === app.session.user.id()) {\n data.splice(i, 1);\n return true;\n }\n });\n\n if (!isLiked) {\n data.unshift({type: 'users', id: app.session.user.id()});\n }\n }\n }, isLiked ? [\n m('span.already-liked', [\n icon('far fa-thumbs-up'),\n ' ',\n app.translator.trans(translationPrefix + 'already-liked'),\n ]),\n m('span.remove-like', [\n icon('far fa-thumbs-down'),\n ' ',\n app.translator.trans(translationPrefix + 'unlike'),\n ])\n ] : [\n icon('far fa-thumbs-up'),\n ' ',\n app.translator.trans(translationPrefix + 'like'),\n ]);\n }\n\n whoLiked(entry) {\n const likes = entry.likes();\n\n if (!likes || !likes.length) {\n return;\n }\n\n const limit = 4;\n const overLimit = likes.length > limit;\n\n // Construct a list of names of users who have liked this post. Make sure the\n // current user is first in the list, and cap a maximum of 4 items.\n const names = likes.sort(a => a === app.session.user ? -1 : 1)\n .slice(0, overLimit ? limit - 1 : limit)\n .map(user => m(Link, {\n href: app.route.user(user),\n }, user === app.session.user ? app.translator.trans('flarum-likes.forum.post.you_text') : username(user)));\n\n // If there are more users that we've run out of room to display, add a \"x\n // others\" name to the end of the list. Clicking on it will display a modal\n // with a full list of names.\n if (overLimit) {\n const count = likes.length - names.length;\n\n names.push(m('a', {\n href: '#',\n onclick: e => {\n e.preventDefault();\n app.modal.show(EntryLikesModal, {\n entry,\n });\n },\n }, app.translator.transChoice('flarum-likes.forum.post.others_link', count, {count})));\n }\n\n return m('.Entry-likedBy', [\n icon('far fa-thumbs-up'),\n app.translator.transChoice('flarum-likes.forum.post.liked_by' + (likes[0] === app.session.user ? '_self' : '') + '_text', names.length, {\n count: names.length,\n users: punctuateSeries(names)\n }),\n ]);\n }\n\n participateButton() {\n if (!app.session.user) {\n return null;\n }\n\n if (app.session.user.attribute('carvingContestCanParticipate')) {\n return Button.component({\n className: 'Button Button--primary',\n onclick: () => {\n app.modal.show(ParticipateModal, {\n onsave: () => {\n app.modal.close();\n this.refresh();\n },\n });\n },\n }, app.translator.trans(translationPrefix + 'participate'));\n }\n\n if (app.session.user.attribute('carvingContestCouldParticipate')) {\n return Button.component({\n className: 'Button Button--primary',\n disabled: true,\n }, app.translator.trans(translationPrefix + 'already-participated'));\n }\n\n return null;\n }\n\n view() {\n if (this.entries === null) {\n return m('.container', m('p', app.translator.trans(translationPrefix + 'loading')));\n }\n\n const sortOptions = {\n '-likesCount': app.translator.trans(translationPrefix + 'sort.mostLikes'),\n 'likesCount': app.translator.trans(translationPrefix + 'sort.fewerLikes'),\n '-createdAt': app.translator.trans(translationPrefix + 'sort.mostRecent'),\n 'createdAt': app.translator.trans(translationPrefix + 'sort.leastRecent'),\n };\n\n return m('.container', [\n m('h2', app.translator.trans(translationPrefix + 'title')),\n this.participateButton(),\n ' ',\n Dropdown.component({\n buttonClassName: 'Button',\n label: sortOptions[this.sort],\n }, Object.keys(sortOptions).map(value => {\n const label = sortOptions[value];\n const active = this.sort === value;\n\n return Button.component({\n icon: active ? 'fas fa-check' : true,\n onclick: () => {\n this.sort = value;\n this.refresh();\n },\n active,\n }, label);\n })),\n ' ',\n Button.component({\n icon: 'fas fa-sync',\n className: 'Button',\n onclick: () => {\n this.refresh();\n },\n }, app.translator.trans(translationPrefix + 'refresh')),\n m('div', this.entries.map(entry => m('.CarvingContestEntry', {\n key: entry.id(), // Without this, canvas are re-used, causing incorrect images to be shown when one is deleted\n }, [\n m(PumpkinCanvas, {\n mode: app.forum.attribute('carvingContestColorMode') ? 'color' : 'carve',\n image: entry.image(),\n }),\n m('h3.CarvingContestEntry--name', entry.name()),\n m('p', [\n avatar(entry.user()),\n username(entry.user()),\n ' - ',\n humanTime(entry.createdAt()),\n ]),\n app.forum.attribute('carvingContestCanModerate') ? Button.component({\n className: 'Button Button--icon CarvingContestEntry--delete',\n icon: 'fas fa-trash',\n onclick: () => {\n if (!confirm(extractText(app.translator.trans(translationPrefix + 'delete-confirmation', {\n name: entry.name(),\n user: entry.user(),\n })))) {\n return;\n }\n\n entry.delete().then(() => {\n this.refresh();\n });\n },\n }) : null,\n m('.CarvingContestEntry--vote', [\n this.likeButton(entry),\n this.whoLiked(entry),\n ]),\n ]))),\n this.loading ? LoadingIndicator.component() : (this.moreResults ? Button.component({\n className: 'Button',\n onclick: this.loadMore.bind(this),\n }, app.translator.trans(translationPrefix + 'load-more')) : null),\n ]);\n }\n}\n","import {extend} from 'flarum/common/extend';\nimport app from 'flarum/app';\nimport IndexPage from 'flarum/forum/components/IndexPage';\nimport LinkButton from 'flarum/common/components/LinkButton';\nimport Entry from './models/Entry';\nimport ContestPage from './components/ContestPage';\n\n/* global m */\n\napp.initializers.add('carving-contest', () => {\n app.store.models['carving-contest-entries'] = Entry;\n\n app.routes.carvingContest = {\n path: '/carving-contest',\n component: ContestPage,\n };\n\n extend(IndexPage.prototype, 'navItems', function (items) {\n if (!app.forum.attribute('carvingContestCanView')) {\n return;\n }\n\n items.add('carving-contest', LinkButton.component({\n icon: 'fas fa-spider',\n href: app.route('carvingContest'),\n }, app.translator.trans('clarkwinkelmann-carving-contest.forum.nav.contest')));\n });\n});\n"],"sourceRoot":""} \ No newline at end of file diff --git a/js/src/admin/index.js b/js/src/admin/index.js index 121fe2f..a1daeb7 100644 --- a/js/src/admin/index.js +++ b/js/src/admin/index.js @@ -15,6 +15,60 @@ app.initializers.add('carving-contest', () => { }), ]); }) + .registerSetting({ + type: 'switch', + setting: 'carving-contest.colorMode', + label: app.translator.trans('clarkwinkelmann-carving-contest.admin.settings.colorMode'), + }) + .registerSetting(function () { + const setting = this.setting('carving-contest.colors', 'simple'); + const disabled = !this.setting('carving-contest.colorMode')(); + + return [ + m('.Form-group.CarvingContest-Subgroup', [ + m('label', [ + m('input', { + type: 'radio', + name: 'carving-contest-color', + checked: setting() === 'simple', + onchange: () => setting('simple'), + disabled, + }), + ' ', + app.translator.trans('clarkwinkelmann-carving-contest.admin.colors.simple'), + ]), + m('label', [ + m('input', { + type: 'radio', + name: 'carving-contest-color', + checked: setting() === 'all', + onchange: () => setting('all'), + disabled, + }), + ' ', + app.translator.trans('clarkwinkelmann-carving-contest.admin.colors.all'), + ]), + m('label', [ + m('input', { + type: 'radio', + name: 'carving-contest-color', + checked: setting() !== 'simple' && setting() !== 'all', + onchange: () => setting(''), + disabled, + }), + ' ', + app.translator.trans('clarkwinkelmann-carving-contest.admin.colors.custom'), + ]), + setting() !== 'simple' && setting() !== 'all' ? [ + m('input.FormControl', { + bidi: setting, + disabled, + }), + m('.helpText', app.translator.trans('clarkwinkelmann-carving-contest.admin.colors.custom-help')), + ] : null, + ]), + ]; + }) .registerPermission({ icon: 'fas fa-spider', label: app.translator.trans('clarkwinkelmann-carving-contest.admin.permissions.view'), diff --git a/js/src/forum/components/ContestPage.js b/js/src/forum/components/ContestPage.js index 0971df2..b6f3bb2 100644 --- a/js/src/forum/components/ContestPage.js +++ b/js/src/forum/components/ContestPage.js @@ -242,6 +242,7 @@ export default class ContestPage extends Page { key: entry.id(), // Without this, canvas are re-used, causing incorrect images to be shown when one is deleted }, [ m(PumpkinCanvas, { + mode: app.forum.attribute('carvingContestColorMode') ? 'color' : 'carve', image: entry.image(), }), m('h3.CarvingContestEntry--name', entry.name()), diff --git a/js/src/forum/components/ParticipateModal.js b/js/src/forum/components/ParticipateModal.js index 2d58806..cc5c2f3 100644 --- a/js/src/forum/components/ParticipateModal.js +++ b/js/src/forum/components/ParticipateModal.js @@ -2,14 +2,14 @@ import app from 'flarum/app'; import Modal from 'flarum/common/components/Modal'; import Button from 'flarum/common/components/Button'; import PumpkinCanvas from './PumpkinCanvas'; +import BrushState from '../states/BrushState'; const translationPrefix = 'clarkwinkelmann-carving-contest.forum.modal.'; /* global m */ export default class ParticipateModal extends Modal { - toolShape = 'circle'; - toolWidth = 30; + brush = new BrushState(); name = ''; image = ''; disabled = true; @@ -34,24 +34,74 @@ export default class ParticipateModal extends Modal { } } + colorChoice() { + const colors = app.forum.attribute('carvingContestColors'); + + if (colors === 'all') { + return m('input', { + type: 'color', + value: this.brush.color, + onchange: event => { + this.brush.color = event.target.value; + }, + }); + } + + let colorOptions; + + if (colors === 'simple') { + colorOptions = [ + '#f32501', // Red + '#ff8d12', // Orange + '#ffe884', // Yellow + '#94ae3f', // Green + '#084f93', // Blue + '#000000', // Black + ]; + } else { + colorOptions = app.forum.attribute('carvingContestColors').split(','); + } + + return m('div', colorOptions.map(color => m('.CarvingContest-ColorChoice', { + style: { + backgroundColor: color, + }, + onclick: () => { + this.brush.color = color; + }, + className: this.brush.color === color ? 'selected' : '', + }))); + } + + colorTools() { + if (!app.forum.attribute('carvingContestColorMode')) { + return null; + } + + return m('.CarvingContestTools', [ + this.colorChoice(), + ]); + } + content() { return m('.Modal-body', [ m('.Form-group', [ + this.colorTools(), m('.CarvingContestTools', [ Button.component({ - disabled: this.toolShape === 'circle', + disabled: this.brush.shape === 'circle', icon: 'fas fa-circle', className: 'Button', onclick: () => { - this.toolShape = 'circle'; + this.brush.shape = 'circle'; }, }, app.translator.trans(translationPrefix + 'tools.circle')), Button.component({ - disabled: this.toolShape === 'square', + disabled: this.brush.shape === 'square', icon: 'fas fa-square', className: 'Button', onclick: () => { - this.toolShape = 'square'; + this.brush.shape = 'square'; }, }, app.translator.trans(translationPrefix + 'tools.square')), m('input', { @@ -59,15 +109,15 @@ export default class ParticipateModal extends Modal { step: 2, min: 10, max: 50, - value: this.toolWidth, + value: this.brush.width, onchange: event => { - this.toolWidth = parseInt(event.target.value); + this.brush.width = parseInt(event.target.value); }, }), ]), m(PumpkinCanvas, { - toolShape: this.toolShape, - toolWidth: this.toolWidth, + mode: app.forum.attribute('carvingContestColorMode') ? 'color' : 'carve', + brush: this.brush, image: this.image, onchange: value => { this.image = value; diff --git a/js/src/forum/components/PumpkinCanvas.js b/js/src/forum/components/PumpkinCanvas.js index ad7662c..0d222b9 100644 --- a/js/src/forum/components/PumpkinCanvas.js +++ b/js/src/forum/components/PumpkinCanvas.js @@ -7,12 +7,15 @@ const IMAGE_HEIGHT = 426; export default class PumpkinCanvas { oninit(vnode) { + this.mode = vnode.attrs.mode; + this.brush = vnode.attrs.brush; + this.previewContext = null; - const imageSourceCanvas = document.createElement('canvas'); - imageSourceCanvas.width = IMAGE_WIDTH; - imageSourceCanvas.height = IMAGE_HEIGHT; - this.imageSourceContext = imageSourceCanvas.getContext('2d'); + this.imageSourceCanvas = document.createElement('canvas'); + this.imageSourceCanvas.width = IMAGE_WIDTH; + this.imageSourceCanvas.height = IMAGE_HEIGHT; + this.imageSourceContext = this.imageSourceCanvas.getContext('2d'); const image = new Image(); image.src = app.forum.attribute('baseUrl') + '/assets/extensions/clarkwinkelmann-carving-contest/pumpkin.jpg'; image.onload = () => { @@ -21,10 +24,10 @@ export default class PumpkinCanvas { this.updatePreview(); }; - const drawCanvas = document.createElement('canvas'); - drawCanvas.width = IMAGE_WIDTH; - drawCanvas.height = IMAGE_HEIGHT; - this.drawContext = drawCanvas.getContext('2d'); + this.drawCanvas = document.createElement('canvas'); + this.drawCanvas.width = IMAGE_WIDTH; + this.drawCanvas.height = IMAGE_HEIGHT; + this.drawContext = this.drawCanvas.getContext('2d'); const startingImage = vnode.attrs.image; if (startingImage) { @@ -68,10 +71,7 @@ export default class PumpkinCanvas { document.removeEventListener('mouseup', this.onmouseup); } - view(vnode) { - this.toolWidth = vnode.attrs.toolWidth; - this.toolShape = vnode.attrs.toolShape; - + view() { return m('.CarvingContestPumpkin', m('canvas', { width: IMAGE_WIDTH, height: IMAGE_HEIGHT, @@ -83,8 +83,12 @@ export default class PumpkinCanvas { const x = event.clientX - rect.left; const y = event.clientY - rect.top; - if (this.drawEnabled) { - this.drawContext.fillStyle = '#000'; + if (this.drawEnabled && this.brush) { + if (this.mode === 'color') { + this.drawContext.fillStyle = this.brush.color; + } else { + this.drawContext.fillStyle = '#000'; + } this.drawWithTool(this.drawContext, x, y, true); vnode.attrs.onchange(this.drawContext.canvas.toDataURL('image/png')); @@ -97,23 +101,28 @@ export default class PumpkinCanvas { } drawWithTool(context, x, y, fill = false) { - const width = this.toolWidth; + if (!this.brush) { + return; + } - switch (this.toolShape) { + const width = this.brush.width; + + context.beginPath(); + + switch (this.brush.shape) { case 'circle': - context.beginPath(); context.arc(x, y, width / 2, 0, 2 * Math.PI); - - if (fill) { - context.fill(); - } else { - context.stroke(); - } break; case 'square': - context.fillRect(x - (width / 2), y - (width / 2), width, width); + context.rect(x - (width / 2), y - (width / 2), width, width); break; } + + if (fill) { + context.fill(); + } else { + context.stroke(); + } } updatePreview(toolPosition = null) { @@ -121,22 +130,30 @@ export default class PumpkinCanvas { return; } - const imageSourceData = this.imageSourceContext.getImageData(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); - const drawData = this.drawContext.getImageData(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); - - for (let i = 0; i < imageSourceData.data.length; i += 4) { - // If the pixel in that area has an alpha value greater than 0, we create a hole in the image data - // Returning 0 for every index will give rgba(0,0,0,0) - if (drawData.data[i + 3] > 0) { - imageSourceData.data[i] = 0; - imageSourceData.data[i + 1] = 0; - imageSourceData.data[i + 2] = 0; - imageSourceData.data[i + 3] = 0; + this.previewContext.clearRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); + + if (this.mode === 'color') { + // In paint mode, we draw the two images on top of another + this.previewContext.drawImage(this.imageSourceCanvas, 0, 0); + this.previewContext.drawImage(this.drawCanvas, 0, 0); + } else { + // In carve mode, we subtract the drawing from the source + const imageSourceData = this.imageSourceContext.getImageData(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); + const drawData = this.drawContext.getImageData(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); + + for (let i = 0; i < imageSourceData.data.length; i += 4) { + // If the pixel in that area has an alpha value greater than 0, we create a hole in the image data + // Returning 0 for every index will give rgba(0,0,0,0) + if (drawData.data[i + 3] > 0) { + imageSourceData.data[i] = 0; + imageSourceData.data[i + 1] = 0; + imageSourceData.data[i + 2] = 0; + imageSourceData.data[i + 3] = 0; + } } - } - this.previewContext.clearRect(0, 0, IMAGE_WIDTH, IMAGE_HEIGHT); - this.previewContext.putImageData(imageSourceData, 0, 0); + this.previewContext.putImageData(imageSourceData, 0, 0); + } if (toolPosition) { this.previewContext.strokeStyle = 'rgba(0,0,0,0.5)'; diff --git a/js/src/forum/states/BrushState.js b/js/src/forum/states/BrushState.js new file mode 100644 index 0000000..71b87c0 --- /dev/null +++ b/js/src/forum/states/BrushState.js @@ -0,0 +1,5 @@ +export default class BrushState { + color = null; + shape = 'circle'; + width = 30; +} diff --git a/resources/less/admin.less b/resources/less/admin.less new file mode 100644 index 0000000..33c394b --- /dev/null +++ b/resources/less/admin.less @@ -0,0 +1,3 @@ +.CarvingContest-Subgroup { + padding-left: 50px; +} diff --git a/resources/less/forum.less b/resources/less/forum.less index 19d33c2..8fdb0ed 100644 --- a/resources/less/forum.less +++ b/resources/less/forum.less @@ -132,9 +132,32 @@ text-decoration: underline; } } + .Avatar { .Avatar--size(32px); vertical-align: middle; margin-right: 5px; } } + +.CarvingContest-ColorChoice { + display: inline-block; + width: 24px; + height: 24px; + border-radius: 2px; + cursor: pointer; + border: 2px solid white; + box-shadow: 0 0 2px rgba(0, 0, 0, 0.5); + + &:not(:first-child) { + margin-left: 5px; + } + + &:hover { + border-color: #ccc; + } + + &.selected { + border-color: red; + } +} diff --git a/resources/locale/en.yml b/resources/locale/en.yml index ba81caf..9446745 100644 --- a/resources/locale/en.yml +++ b/resources/locale/en.yml @@ -45,3 +45,10 @@ clarkwinkelmann-carving-contest: settings: maxEntriesPerUser: Max submissions per user + colorMode: Use color mode instead of carve mode + + colors: + simple: Simple color set + all: Any color + custom: Custom color list + custom-help: 'Comma-separated list of #hex or rgb() values'