diff --git a/js/dist/forum.js b/js/dist/forum.js index acd386f..8d6c795 100644 --- a/js/dist/forum.js +++ b/js/dist/forum.js @@ -1,2 +1,2 @@ -module.exports=function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=22)}([,function(e,t){e.exports=flarum.core.compat["common/Model"]},function(e,t){e.exports=flarum.core.compat["forum/app"]},function(e,t,n){"use strict";function r(e,t){return(r=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}function o(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,r(e,t)}n.d(t,"a",(function(){return o}))},function(e,t){e.exports=flarum.core.compat["common/helpers/icon"]},function(e,t){e.exports=flarum.core.compat["common/components/Button"]},function(e,t){e.exports=flarum.core.compat["common/Component"]},function(e,t,n){"use strict";n.d(t,"a",(function(){return a}));var r=n(3),o=n(1),i=n.n(o),a=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o('fieldId', (fieldId: string) => {\n return app.store.getById('masquerade-field', fieldId);\n });\n userId = Model.attribute('user_id');\n}\n","import icon from 'flarum/common/helpers/icon';\n\n/* global m */\n\nexport default class BaseField {\n constructor({ field, set, value }) {\n this.field = field;\n this.set = set;\n this.value = value;\n }\n\n readAttribute(object, attribute) {\n if (typeof object[attribute] === 'function') {\n return object[attribute]();\n }\n\n return object[attribute];\n }\n\n /**\n * Gets all Laravel validation rules split by rule\n * @returns {Array}\n */\n validationRules() {\n return this.readAttribute(this.field, 'validation').split('|');\n }\n\n /**\n * Gets a Laravel validation rule by name\n * @param {string} ruleName\n * @returns {string|null}\n */\n validationRule(ruleName) {\n let ruleContent = null;\n\n this.validationRules().forEach((rule) => {\n const split = rule.split(':', 2);\n\n if (split[0] === ruleName) {\n ruleContent = split[1];\n }\n });\n\n return ruleContent;\n }\n\n editorField() {\n return (\n
\n \n\n
\n {this.field.prefix() ? m('.prefix', this.field.prefix()) : null}\n {this.editorInput()}\n {this.field.description() ?
{this.field.description()}
: null}\n
\n
\n );\n }\n\n editorInput() {\n return ;\n }\n\n editorInputAttrs() {\n return {\n className: 'FormControl',\n oninput: (event) => {\n this.set(event.target.value);\n },\n value: this.value,\n required: this.field.required(),\n };\n }\n\n answerField() {\n const iconName = this.readAttribute(this.field, 'icon');\n\n return (\n
\n \n {iconName && <>{icon(iconName)} }\n {this.readAttribute(this.field, 'name')}:{' '}\n \n {this.answerContent()}\n
\n );\n }\n\n answerContent() {\n return this.value;\n }\n\n hasAnswer() {\n const answerContent = this.answerContent();\n\n if (answerContent === null) {\n return false;\n }\n\n if (typeof answerContent === 'object') {\n return !!Object.keys(answerContent).length;\n }\n\n return !!answerContent?.length;\n }\n\n static isNoOptionSelectedValue(value) {\n // The value can be null when coming from the API\n // The value can be '' when the field does not exist on the user (the empty string is set in ProfileConfigurePane)\n return value === null || value === '';\n }\n}\n","import icon from 'flarum/common/helpers/icon';\nimport BaseField from './BaseField';\n\nexport default class BooleanField extends BaseField {\n editorInput() {\n return this.options().map((option) =>\n m(\n 'div',\n m('label', [\n m('input[type=radio]', {\n checked: option.selected(this.value),\n onclick: () => {\n this.set(option.key);\n },\n }),\n ' ' + option.label,\n ])\n )\n );\n }\n\n options() {\n let options = [];\n\n if (!this.readAttribute(this.field, 'required')) {\n options.push({\n selected: (value) => BaseField.isNoOptionSelectedValue(value),\n key: null,\n label: app.translator.trans('fof-masquerade.forum.fields.select.none-optional'),\n });\n }\n\n options.push({\n selected: (value) => ['true', '1', 1, true, 'yes'].indexOf(value) !== -1,\n key: 'true',\n label: app.translator.trans('fof-masquerade.forum.fields.boolean.yes'),\n });\n\n options.push({\n selected: (value) => ['false', '0', 0, false, 'no'].indexOf(value) !== -1,\n key: 'false',\n label: app.translator.trans('fof-masquerade.forum.fields.boolean.no'),\n });\n\n // This is probably overkill because it looks like the backend casts the value anyway\n if (!BaseField.isNoOptionSelectedValue(this.value) && ['true', '1', 1, true, 'yes', 'false', '0', 0, false, 'no'].indexOf(this.value) === -1) {\n options.push({\n selected: () => true,\n key: this.value,\n label: '(invalid) ' + this.value,\n });\n }\n\n return options;\n }\n\n answerContent() {\n if (BaseField.isNoOptionSelectedValue(this.value)) {\n return '';\n }\n\n return [1, '1', true, 'true', 'yes'].indexOf(this.value) !== -1\n ? [icon('far fa-check-square'), ' ', app.translator.trans('fof-masquerade.forum.fields.boolean.yes')]\n : [icon('far fa-square'), ' ', app.translator.trans('fof-masquerade.forum.fields.boolean.no')];\n }\n}\n","import Button from 'flarum/common/components/Button';\nimport BaseField from './BaseField';\n\nexport default class EmailField extends BaseField {\n editorInputAttrs() {\n let attrs = super.editorInputAttrs();\n\n attrs.type = 'email';\n attrs.placeholder = 'you@example.com';\n\n return attrs;\n }\n\n answerContent() {\n const value = this.value;\n\n if (!value) {\n return null;\n }\n\n const email = value\n .split(/@|\\./)\n .map((segment) => {\n return segment.replace(/(.{2})./g, '$1*');\n })\n .join('*');\n\n return Button.component(\n {\n onclick: () => this.mailTo(),\n className: 'Button Button--text',\n icon: 'far fa-envelope',\n },\n email\n );\n }\n\n mailTo() {\n window.location = 'mailto:' + this.value;\n }\n}\n","import Select from 'flarum/common/components/Select';\nimport BaseField from './BaseField';\n\nconst NO_OPTION_SELECTED_KEY = 'fof_masquerade_no_option_selected';\n\nexport default class SelectField extends BaseField {\n editorInput() {\n return Select.component({\n onchange: (value) => {\n if (value === NO_OPTION_SELECTED_KEY) {\n value = null;\n }\n\n this.set(value);\n },\n value: BaseField.isNoOptionSelectedValue(this.value) ? NO_OPTION_SELECTED_KEY : this.value,\n options: this.options(),\n });\n }\n\n options() {\n let options = {};\n\n if (!this.readAttribute(this.field, 'required')) {\n options[NO_OPTION_SELECTED_KEY] = app.translator.trans('fof-masquerade.forum.fields.select.none-optional');\n } else if (BaseField.isNoOptionSelectedValue(this.value)) {\n options[NO_OPTION_SELECTED_KEY] = app.translator.trans('fof-masquerade.forum.fields.select.none-required');\n }\n\n const validationIn = this.validationRule('in');\n\n if (validationIn) {\n validationIn.split(',').forEach((value) => {\n options[value] = value;\n });\n }\n\n if (!BaseField.isNoOptionSelectedValue(this.value) && typeof options[this.value] === 'undefined') {\n options[this.value] = '(invalid) ' + this.value;\n }\n\n return options;\n }\n}\n","import Button from 'flarum/common/components/Button';\nimport BaseField from './BaseField';\n\nexport default class UrlField extends BaseField {\n editorInputAttrs() {\n let attrs = super.editorInputAttrs();\n\n attrs.type = 'url';\n attrs.placeholder = 'https://example.com';\n\n return attrs;\n }\n\n answerContent() {\n const value = this.value;\n\n if (!value) {\n return null;\n }\n\n return Button.component(\n {\n onclick: () => this.to(),\n className: 'Button Button--text',\n icon: 'fas fa-link',\n },\n value.replace(/^https?:\\/\\//, '')\n );\n }\n\n to() {\n const popup = window.open();\n popup.location = this.value;\n }\n}\n","import BaseField from './BaseField';\nimport BooleanField from './BooleanField';\nimport EmailField from './EmailField';\nimport SelectField from './SelectField';\nimport UrlField from './UrlField';\n\nexport default class TypeFactory {\n static typeForField({ field, set = undefined, value }) {\n let className = BaseField;\n\n const type = this.identify(field);\n\n if (type) {\n className = this.types()[type];\n }\n\n return new className({\n field,\n set,\n value,\n });\n }\n\n static fieldAttribute(field, attribute) {\n if (typeof field[attribute] === 'function') {\n return field[attribute]();\n }\n\n return field[attribute];\n }\n\n static types() {\n return {\n boolean: BooleanField,\n email: EmailField,\n select: SelectField,\n url: UrlField,\n };\n }\n\n /**\n * Identifies how to parse the field answer.\n * @returns {null|string}\n */\n static identify(field) {\n const validation = (this.fieldAttribute(field, 'validation') || '').split(',');\n let identified = null;\n\n // If the field has a type we use it\n const fieldType = this.fieldAttribute(field, 'type');\n if (typeof this.types()[fieldType] !== 'undefined') {\n return fieldType;\n }\n\n // If it's an advanced field with no type we then guess the best type\n validation.forEach((rule) => {\n rule = rule.trim();\n\n if (typeof this.types()[rule] !== 'undefined') {\n identified = rule;\n }\n });\n\n return identified;\n }\n}\n","import app from 'flarum/forum/app';\n\nimport Component from 'flarum/common/Component';\nimport TypeFactory from '../types/TypeFactory';\nimport type Answer from '../../lib/models/Answer';\nimport type Field from 'src/lib/models/Field';\nimport type User from 'flarum/common/models/User';\n\nexport default class ProfilePane extends Component {\n answers!: Answer[];\n user!: User;\n\n oninit(vnode) {\n super.oninit(vnode);\n this.loading = true;\n\n this.answers = [];\n this.user = this.attrs.user;\n\n this.load(this.user);\n }\n\n view() {\n return (\n
\n
\n {app.store\n .all('masquerade-field')\n .sort((a, b) => a.sort() - b.sort())\n .map((field) => {\n const answer = this.answers.find((a) => a.field().id() === field.id());\n\n return this.field(field, answer?.content() || '');\n })}\n
\n
\n );\n }\n\n field(field: Field, content) {\n const type = TypeFactory.typeForField({\n field,\n value: content,\n });\n\n return type.answerField();\n }\n\n load() {\n this.answers = this.user.masqueradeAnswers();\n\n if (this.answers === false) {\n this.answers = [];\n app.store.find('users', this.user.id(), { include: 'masqueradeAnswers' }).then(() => {\n this.answers = this.user.masqueradeAnswers();\n m.redraw();\n });\n }\n\n m.redraw();\n }\n}\n","import app from 'flarum/forum/app';\n\nimport Button from 'flarum/common/components/Button';\nimport Link from 'flarum/common/components/Link';\nimport TypeFactory from '../types/TypeFactory';\nimport Component from 'flarum/common/Component';\n\nexport default class ProfileConfigurePane extends Component {\n oninit(vnode) {\n super.oninit(vnode);\n this.loading = true;\n\n this.enforceProfileCompletion = app.forum.attribute('masquerade.force-profile-completion') || false;\n this.profileCompleted = app.forum.attribute('masquerade.profile-completed') || false;\n this.profileNowCompleted = false; // Show \"after required\" text\n this.answers = [];\n this.answerValues = {};\n this.user = this.attrs.user;\n this.load();\n\n // Show disabled state if everything is saved\n // Unless the profile isn't complete, in which case show enabled button so it's obvious you will need to save\n this.dirty = !this.profileCompleted;\n }\n\n view() {\n return (\n
\n {!!(this.enforceProfileCompletion && !this.profileCompleted) && (\n
{app.translator.trans('fof-masquerade.forum.alerts.profile-completion-required')}
\n )}\n\n
\n {app.store\n .all('masquerade-field')\n .sort((a, b) => a.sort() - b.sort())\n .map((field) => {\n return this.field(field);\n })}\n
\n\n \n\n {!!this.profileNowCompleted && (\n \n {app.translator.trans('fof-masquerade.forum.alerts.profile-completed', {\n a: ,\n })}\n \n )}\n
\n );\n }\n\n field(field) {\n const type = TypeFactory.typeForField({\n field,\n set: this.set.bind(this, field),\n value: this.answerValues[field.id()],\n });\n\n return type.editorField();\n }\n\n load() {\n this.answers = this.user.masqueradeAnswers();\n\n if (this.answers === false) {\n this.answers = [];\n app.store.find('users', this.user.id(), { include: 'masqueradeAnswers' }).then(() => {\n this.answers = this.user.masqueradeAnswers();\n this.answerValues = {};\n\n app.store.all('masquerade-field').forEach((field) => {\n const answer = this.answers.find((a) => a.field().id() === field.id());\n\n this.answerValues[field.id()] = answer ? answer.content() : '';\n });\n\n this.loading = false;\n m.redraw();\n });\n } else {\n this.loading = false;\n\n app.store.all('masquerade-field').forEach((field) => {\n const answer = this.answers.find((a) => a.field().id() === field.id());\n\n this.answerValues[field.id()] = answer ? answer.content() : '';\n });\n }\n\n m.redraw();\n }\n\n set(field, value) {\n this.answerValues[field.id()] = value;\n this.dirty = true;\n }\n\n update(e) {\n e.preventDefault();\n\n this.loading = true;\n\n app\n .request({\n method: 'POST',\n url: app.forum.attribute('apiUrl') + '/masquerade/configure/' + this.user.id(),\n body: this.answerValues,\n })\n .then((response) => {\n this.dirty = false;\n\n if (!this.profileCompleted) {\n this.profileCompleted = true;\n this.profileNowCompleted = true;\n }\n\n this.parseResponse(response);\n })\n .catch(() => {\n this.loading = false;\n m.redraw();\n });\n }\n\n parseResponse(response) {\n console.log(response);\n this.answers = app.store.pushPayload(response);\n this.loading = false;\n m.redraw();\n }\n}\n","import UserPage from 'flarum/forum/components/UserPage';\nimport LoadingIndicator from 'flarum/common/components/LoadingIndicator';\nimport ProfilePane from './ProfilePane';\nimport ProfileConfigurePane from './ProfileConfigurePane';\n\nexport default class RootMasqueradePane extends UserPage {\n loading = true;\n\n oninit(vnode) {\n super.oninit(vnode);\n\n this.loadUser(m.route.param('username'));\n }\n\n pageContentComponent() {\n if (!this.user) return null;\n\n if (this.user.canEditMasqueradeProfile()) return ;\n else return ;\n }\n\n show(user) {\n super.show(user);\n\n this.loading = false;\n m.redraw();\n }\n\n content() {\n return (\n
\n {this.loading && }\n {this.pageContentComponent()}\n
\n );\n }\n}\n","import app from 'flarum/forum/app';\nimport User from 'flarum/common/models/User';\nimport Field from './../lib/models/Field';\nimport Answer from './../lib/models/Answer';\nimport Model from 'flarum/common/Model';\n\nimport addProfilePane from './addProfilePane';\nimport mutateUserHero from './mutateUserHero';\n\n// Exports\nimport ProfileConfigurePane from './panes/ProfileConfigurePane';\nimport ProfilePane from './panes/ProfilePane';\nimport RootMasqueradePane from './panes/RootMasqueradePane';\nimport BaseField from './types/BaseField';\nimport BooleanField from './types/BooleanField';\nimport EmailField from './types/EmailField';\nimport SelectField from './types/SelectField';\nimport TypeFactory from './types/TypeFactory';\nimport UrlField from './types/UrlField';\n\napp.initializers.add('fof-masquerade', (app) => {\n app.store.models['masquerade-field'] = Field;\n app.store.models['masquerade-answer'] = Answer;\n\n User.prototype.bioFields = Model.hasMany('bioFields');\n User.prototype.masqueradeAnswers = Model.hasMany('masqueradeAnswers');\n User.prototype.canEditMasqueradeProfile = Model.attribute('canEditMasqueradeProfile');\n\n addProfilePane();\n\n mutateUserHero();\n});\n\nconst components = {\n ProfileConfigurePane,\n ProfilePane,\n RootMasqueradePane,\n};\n\nconst types = {\n BaseField,\n BooleanField,\n EmailField,\n SelectField,\n TypeFactory,\n UrlField,\n};\n\nexport { components, types };\n","import app from 'flarum/forum/app';\n\nimport { extend } from 'flarum/common/extend';\nimport LinkButton from 'flarum/common/components/LinkButton';\nimport UserPage from 'flarum/forum/components/UserPage';\nimport RootMasqueradePane from './panes/RootMasqueradePane';\n\nexport default function addProfilePane() {\n app.routes['fof-masquerade'] = {\n path: '/u/:username/masquerade',\n resolver: {\n onmatch() {\n if (!app.forum.attribute('canViewMasquerade')) throw new Error();\n\n return RootMasqueradePane;\n },\n },\n };\n\n extend(UserPage.prototype, 'navItems', function (items) {\n if (app.forum.attribute('canViewMasquerade') || this.user.canEditMasqueradeProfile()) {\n const edit = this.user.canEditMasqueradeProfile();\n\n items.add(\n 'masquerade',\n LinkButton.component(\n {\n href: app.route('fof-masquerade', { username: this.user.slug() }),\n icon: 'far fa-id-card',\n 'data-editProfile': edit,\n },\n app.translator.trans(`fof-masquerade.forum.buttons.${edit ? 'edit' : 'view'}-profile`)\n ),\n 200\n );\n }\n });\n}\n","import { extend } from 'flarum/common/extend';\nimport app from 'flarum/forum/app';\nimport UserCard from 'flarum/forum/components/UserCard';\nimport TypeFactory from './types/TypeFactory';\n\nexport default function mutateUserHero() {\n extend(UserCard.prototype, 'infoItems', function (items) {\n const answers = app.forum.attribute('canViewMasquerade') ? this.attrs.user.bioFields() || [] : [];\n\n items.add(\n 'masquerade-bio',\n
\n {answers.map((answer) => {\n const field = answer.attribute('field');\n const type = TypeFactory.typeForField({\n field,\n value: answer.content(),\n });\n\n return type.answerField();\n })}\n
\n );\n });\n}\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack://@fof/masquerade/webpack/bootstrap","webpack://@fof/masquerade/external \"flarum.core.compat['common/Model']\"","webpack://@fof/masquerade/external \"flarum.core.compat['forum/app']\"","webpack://@fof/masquerade/./node_modules/@babel/runtime/helpers/esm/setPrototypeOf.js","webpack://@fof/masquerade/./node_modules/@babel/runtime/helpers/esm/inheritsLoose.js","webpack://@fof/masquerade/external \"flarum.core.compat['common/helpers/icon']\"","webpack://@fof/masquerade/external \"flarum.core.compat['common/components/Button']\"","webpack://@fof/masquerade/external \"flarum.core.compat['common/Component']\"","webpack://@fof/masquerade/./src/lib/models/Field.js","webpack://@fof/masquerade/external \"flarum.core.compat['common/components/Select']\"","webpack://@fof/masquerade/external \"flarum.core.compat['common/extend']\"","webpack://@fof/masquerade/external \"flarum.core.compat['forum/components/UserPage']\"","webpack://@fof/masquerade/external \"flarum.core.compat['common/models/User']\"","webpack://@fof/masquerade/external \"flarum.core.compat['common/app']\"","webpack://@fof/masquerade/external \"flarum.core.compat['common/utils/computed']\"","webpack://@fof/masquerade/external \"flarum.core.compat['common/components/LinkButton']\"","webpack://@fof/masquerade/external \"flarum.core.compat['common/components/LoadingIndicator']\"","webpack://@fof/masquerade/external \"flarum.core.compat['common/components/Link']\"","webpack://@fof/masquerade/external \"flarum.core.compat['forum/components/UserCard']\"","webpack://@fof/masquerade/./src/lib/models/Answer.ts","webpack://@fof/masquerade/./src/forum/types/BaseField.js","webpack://@fof/masquerade/./src/forum/types/BooleanField.js","webpack://@fof/masquerade/./src/forum/types/EmailField.js","webpack://@fof/masquerade/./src/forum/types/SelectField.js","webpack://@fof/masquerade/./src/forum/types/UrlField.js","webpack://@fof/masquerade/./src/forum/types/TypeFactory.js","webpack://@fof/masquerade/./src/forum/panes/ProfilePane.tsx","webpack://@fof/masquerade/./src/forum/panes/ProfileConfigurePane.js","webpack://@fof/masquerade/./src/forum/panes/RootMasqueradePane.tsx","webpack://@fof/masquerade/./src/forum/index.js","webpack://@fof/masquerade/./src/forum/addProfilePane.js","webpack://@fof/masquerade/./src/forum/mutateUserHero.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","_setPrototypeOf","setPrototypeOf","__proto__","_inheritsLoose","subClass","superClass","constructor","Field","Model","attribute","description","type","validation","required","prefix","icon","sort","deleted_at","transformDate","answer","hasOne","on_bio","apiEndpoint","this","exists","data","id","Answer","content","fieldId","field","computed","app","store","getById","userId","BaseField","set","readAttribute","validationRules","split","validationRule","ruleName","ruleContent","forEach","rule","editorField","class","editorInput","editorInputAttrs","className","oninput","event","target","answerField","iconName","hasAnswer","answerContent","keys","length","isNoOptionSelectedValue","BooleanField","options","map","option","checked","selected","onclick","label","push","translator","trans","indexOf","EmailField","attrs","placeholder","email","segment","replace","join","Button","component","mailTo","window","location","SelectField","Select","onchange","validationIn","UrlField","to","open","TypeFactory","typeForField","undefined","identify","types","fieldAttribute","boolean","select","url","identified","fieldType","trim","ProfilePane","answers","user","oninit","vnode","loading","load","view","all","a","b","find","masqueradeAnswers","include","then","redraw","Component","ProfileConfigurePane","enforceProfileCompletion","forum","profileCompleted","profileNowCompleted","answerValues","dirty","onsubmit","update","disabled","href","route","e","preventDefault","request","method","body","response","parseResponse","console","log","pushPayload","RootMasqueradePane","loadUser","param","pageContentComponent","canEditMasqueradeProfile","show","UserPage","initializers","add","models","User","bioFields","hasMany","routes","path","resolver","onmatch","Error","extend","items","edit","LinkButton","username","slug","UserCard","components"],"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 = 22);\n","module.exports = flarum.core.compat['common/Model'];","module.exports = flarum.core.compat['forum/app'];","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}","module.exports = flarum.core.compat['common/helpers/icon'];","module.exports = flarum.core.compat['common/components/Button'];","module.exports = flarum.core.compat['common/Component'];","import Model from 'flarum/common/Model';\n\nexport default class Field extends Model {\n name = Model.attribute('name');\n description = Model.attribute('description');\n type = Model.attribute('type');\n validation = Model.attribute('validation');\n required = Model.attribute('required');\n prefix = Model.attribute('prefix');\n icon = Model.attribute('icon');\n sort = Model.attribute('sort');\n deleted_at = Model.attribute('deleted_at', Model.transformDate);\n answer = Model.hasOne('answer');\n on_bio = Model.attribute('on_bio');\n\n apiEndpoint() {\n return '/masquerade/fields' + (this.exists ? '/' + this.data.id : '');\n }\n}\n","module.exports = flarum.core.compat['common/components/Select'];","module.exports = flarum.core.compat['common/extend'];","module.exports = flarum.core.compat['forum/components/UserPage'];","module.exports = flarum.core.compat['common/models/User'];","module.exports = flarum.core.compat['common/app'];","module.exports = flarum.core.compat['common/utils/computed'];","module.exports = flarum.core.compat['common/components/LinkButton'];","module.exports = flarum.core.compat['common/components/LoadingIndicator'];","module.exports = flarum.core.compat['common/components/Link'];","module.exports = flarum.core.compat['forum/components/UserCard'];","import app from 'flarum/common/app';\nimport Model from 'flarum/common/Model';\nimport computed from 'flarum/common/utils/computed';\n\nimport type Field from './Field';\n\nexport default class Answer extends Model {\n content = Model.attribute('content');\n fieldId = Model.attribute('fieldId');\n field = computed('fieldId', (fieldId: string) => {\n return app.store.getById('masquerade-field', fieldId);\n });\n userId = Model.attribute('user_id');\n}\n","import icon from 'flarum/common/helpers/icon';\n\n/* global m */\n\nexport default class BaseField {\n constructor({ field, set, value }) {\n this.field = field;\n this.set = set;\n this.value = value;\n }\n\n readAttribute(object, attribute) {\n if (typeof object[attribute] === 'function') {\n return object[attribute]();\n }\n\n return object[attribute];\n }\n\n /**\n * Gets all Laravel validation rules split by rule\n * @returns {Array}\n */\n validationRules() {\n return this.readAttribute(this.field, 'validation').split('|');\n }\n\n /**\n * Gets a Laravel validation rule by name\n * @param {string} ruleName\n * @returns {string|null}\n */\n validationRule(ruleName) {\n let ruleContent = null;\n\n this.validationRules().forEach((rule) => {\n const split = rule.split(':', 2);\n\n if (split[0] === ruleName) {\n ruleContent = split[1];\n }\n });\n\n return ruleContent;\n }\n\n editorField() {\n return (\n
\n \n\n
\n {this.field.prefix() ? m('.prefix', this.field.prefix()) : null}\n {this.editorInput()}\n {this.field.description() ?
{this.field.description()}
: null}\n
\n
\n );\n }\n\n editorInput() {\n return ;\n }\n\n editorInputAttrs() {\n return {\n className: 'FormControl',\n oninput: (event) => {\n this.set(event.target.value);\n },\n value: this.value,\n required: this.field.required(),\n };\n }\n\n answerField() {\n const iconName = this.readAttribute(this.field, 'icon');\n\n return (\n
\n \n {iconName && <>{icon(iconName)} }\n {this.readAttribute(this.field, 'name')}:{' '}\n \n {this.answerContent()}\n
\n );\n }\n\n answerContent() {\n return this.value;\n }\n\n hasAnswer() {\n const answerContent = this.answerContent();\n\n if (answerContent === null) {\n return false;\n }\n\n if (typeof answerContent === 'object') {\n return !!Object.keys(answerContent).length;\n }\n\n return !!answerContent?.length;\n }\n\n static isNoOptionSelectedValue(value) {\n // The value can be null when coming from the API\n // The value can be '' when the field does not exist on the user (the empty string is set in ProfileConfigurePane)\n return value === null || value === '';\n }\n}\n","import icon from 'flarum/common/helpers/icon';\nimport BaseField from './BaseField';\n\nexport default class BooleanField extends BaseField {\n editorInput() {\n return this.options().map((option) =>\n m(\n 'div',\n m('label', [\n m('input[type=radio]', {\n checked: option.selected(this.value),\n onclick: () => {\n this.set(option.key);\n },\n }),\n ' ' + option.label,\n ])\n )\n );\n }\n\n options() {\n let options = [];\n\n if (!this.readAttribute(this.field, 'required')) {\n options.push({\n selected: (value) => BaseField.isNoOptionSelectedValue(value),\n key: null,\n label: app.translator.trans('fof-masquerade.forum.fields.select.none-optional'),\n });\n }\n\n options.push({\n selected: (value) => ['true', '1', 1, true, 'yes'].indexOf(value) !== -1,\n key: 'true',\n label: app.translator.trans('fof-masquerade.forum.fields.boolean.yes'),\n });\n\n options.push({\n selected: (value) => ['false', '0', 0, false, 'no'].indexOf(value) !== -1,\n key: 'false',\n label: app.translator.trans('fof-masquerade.forum.fields.boolean.no'),\n });\n\n // This is probably overkill because it looks like the backend casts the value anyway\n if (!BaseField.isNoOptionSelectedValue(this.value) && ['true', '1', 1, true, 'yes', 'false', '0', 0, false, 'no'].indexOf(this.value) === -1) {\n options.push({\n selected: () => true,\n key: this.value,\n label: '(invalid) ' + this.value,\n });\n }\n\n return options;\n }\n\n answerContent() {\n if (BaseField.isNoOptionSelectedValue(this.value)) {\n return '';\n }\n\n return [1, '1', true, 'true', 'yes'].indexOf(this.value) !== -1\n ? [icon('far fa-check-square'), ' ', app.translator.trans('fof-masquerade.forum.fields.boolean.yes')]\n : [icon('far fa-square'), ' ', app.translator.trans('fof-masquerade.forum.fields.boolean.no')];\n }\n}\n","import Button from 'flarum/common/components/Button';\nimport BaseField from './BaseField';\n\nexport default class EmailField extends BaseField {\n editorInputAttrs() {\n let attrs = super.editorInputAttrs();\n\n attrs.type = 'email';\n attrs.placeholder = 'you@example.com';\n\n return attrs;\n }\n\n answerContent() {\n const value = this.value;\n\n if (!value) {\n return null;\n }\n\n const email = value\n .split(/@|\\./)\n .map((segment) => {\n return segment.replace(/(.{2})./g, '$1*');\n })\n .join('*');\n\n return Button.component(\n {\n onclick: () => this.mailTo(),\n className: 'Button Button--text',\n icon: 'far fa-envelope',\n },\n email\n );\n }\n\n mailTo() {\n window.location = 'mailto:' + this.value;\n }\n}\n","import Select from 'flarum/common/components/Select';\nimport BaseField from './BaseField';\n\nconst NO_OPTION_SELECTED_KEY = 'fof_masquerade_no_option_selected';\n\nexport default class SelectField extends BaseField {\n editorInput() {\n return Select.component({\n onchange: (value) => {\n if (value === NO_OPTION_SELECTED_KEY) {\n value = null;\n }\n\n this.set(value);\n },\n value: BaseField.isNoOptionSelectedValue(this.value) ? NO_OPTION_SELECTED_KEY : this.value,\n options: this.options(),\n });\n }\n\n options() {\n let options = {};\n\n if (!this.readAttribute(this.field, 'required')) {\n options[NO_OPTION_SELECTED_KEY] = app.translator.trans('fof-masquerade.forum.fields.select.none-optional');\n } else if (BaseField.isNoOptionSelectedValue(this.value)) {\n options[NO_OPTION_SELECTED_KEY] = app.translator.trans('fof-masquerade.forum.fields.select.none-required');\n }\n\n const validationIn = this.validationRule('in');\n\n if (validationIn) {\n validationIn.split(',').forEach((value) => {\n options[value] = value;\n });\n }\n\n if (!BaseField.isNoOptionSelectedValue(this.value) && typeof options[this.value] === 'undefined') {\n options[this.value] = '(invalid) ' + this.value;\n }\n\n return options;\n }\n}\n","import Button from 'flarum/common/components/Button';\nimport BaseField from './BaseField';\n\nexport default class UrlField extends BaseField {\n editorInputAttrs() {\n let attrs = super.editorInputAttrs();\n\n attrs.type = 'url';\n attrs.placeholder = 'https://example.com';\n\n return attrs;\n }\n\n answerContent() {\n const value = this.value;\n\n if (!value) {\n return null;\n }\n\n return Button.component(\n {\n onclick: () => this.to(),\n className: 'Button Button--text',\n icon: 'fas fa-link',\n },\n value.replace(/^https?:\\/\\//, '')\n );\n }\n\n to() {\n const popup = window.open();\n popup.location = this.value;\n }\n}\n","import BaseField from './BaseField';\nimport BooleanField from './BooleanField';\nimport EmailField from './EmailField';\nimport SelectField from './SelectField';\nimport UrlField from './UrlField';\n\nexport default class TypeFactory {\n static typeForField({ field, set = undefined, value }) {\n let className = BaseField;\n\n const type = this.identify(field);\n\n if (type) {\n className = this.types()[type];\n }\n\n return new className({\n field,\n set,\n value,\n });\n }\n\n static fieldAttribute(field, attribute) {\n if (typeof field[attribute] === 'function') {\n return field[attribute]();\n }\n\n return field[attribute];\n }\n\n static types() {\n return {\n boolean: BooleanField,\n email: EmailField,\n select: SelectField,\n url: UrlField,\n };\n }\n\n /**\n * Identifies how to parse the field answer.\n * @returns {null|string}\n */\n static identify(field) {\n const validation = (this.fieldAttribute(field, 'validation') || '').split(',');\n let identified = null;\n\n // If the field has a type we use it\n const fieldType = this.fieldAttribute(field, 'type');\n if (typeof this.types()[fieldType] !== 'undefined') {\n return fieldType;\n }\n\n // If it's an advanced field with no type we then guess the best type\n validation.forEach((rule) => {\n rule = rule.trim();\n\n if (typeof this.types()[rule] !== 'undefined') {\n identified = rule;\n }\n });\n\n return identified;\n }\n}\n","import app from 'flarum/forum/app';\n\nimport Component from 'flarum/common/Component';\nimport TypeFactory from '../types/TypeFactory';\nimport type Answer from '../../lib/models/Answer';\nimport type Field from 'src/lib/models/Field';\nimport type User from 'flarum/common/models/User';\n\nexport default class ProfilePane extends Component {\n answers!: Answer[];\n user!: User;\n\n oninit(vnode) {\n super.oninit(vnode);\n this.loading = true;\n\n this.answers = [];\n this.user = this.attrs.user;\n\n this.load(this.user);\n }\n\n view() {\n return (\n
\n
\n {app.store\n .all('masquerade-field')\n .sort((a, b) => a.sort() - b.sort())\n .map((field) => {\n const answer = this.answers.find((a) => a.field()?.id() === field.id());\n\n return this.field(field, answer?.content() || '');\n })}\n
\n
\n );\n }\n\n field(field: Field, content) {\n const type = TypeFactory.typeForField({\n field,\n value: content,\n });\n\n return type.answerField();\n }\n\n load() {\n this.answers = this.user.masqueradeAnswers();\n\n if (this.answers === false) {\n this.answers = [];\n app.store.find('users', this.user.id(), { include: 'masqueradeAnswers' }).then(() => {\n this.answers = this.user.masqueradeAnswers();\n m.redraw();\n });\n }\n\n m.redraw();\n }\n}\n","import app from 'flarum/forum/app';\n\nimport Button from 'flarum/common/components/Button';\nimport Link from 'flarum/common/components/Link';\nimport TypeFactory from '../types/TypeFactory';\nimport Component from 'flarum/common/Component';\n\nexport default class ProfileConfigurePane extends Component {\n oninit(vnode) {\n super.oninit(vnode);\n this.loading = true;\n\n this.enforceProfileCompletion = app.forum.attribute('masquerade.force-profile-completion') || false;\n this.profileCompleted = app.forum.attribute('masquerade.profile-completed') || false;\n this.profileNowCompleted = false; // Show \"after required\" text\n this.answers = [];\n this.answerValues = {};\n this.user = this.attrs.user;\n this.load();\n\n // Show disabled state if everything is saved\n // Unless the profile isn't complete, in which case show enabled button so it's obvious you will need to save\n this.dirty = !this.profileCompleted;\n }\n\n view() {\n return (\n
\n {!!(this.enforceProfileCompletion && !this.profileCompleted) && (\n
{app.translator.trans('fof-masquerade.forum.alerts.profile-completion-required')}
\n )}\n\n
\n {app.store\n .all('masquerade-field')\n .sort((a, b) => a.sort() - b.sort())\n .map((field) => {\n return this.field(field);\n })}\n
\n\n \n\n {!!this.profileNowCompleted && (\n \n {app.translator.trans('fof-masquerade.forum.alerts.profile-completed', {\n a: ,\n })}\n \n )}\n
\n );\n }\n\n field(field) {\n const type = TypeFactory.typeForField({\n field,\n set: this.set.bind(this, field),\n value: this.answerValues[field.id()],\n });\n\n return type.editorField();\n }\n\n load() {\n this.answers = this.user.masqueradeAnswers();\n\n if (this.answers === false) {\n this.answers = [];\n app.store.find('users', this.user.id(), { include: 'masqueradeAnswers' }).then(() => {\n this.answers = this.user.masqueradeAnswers();\n this.answerValues = {};\n\n app.store.all('masquerade-field').forEach((field) => {\n const answer = this.answers.find((a) => a.field()?.id() === field.id());\n\n this.answerValues[field.id()] = answer ? answer.content() : '';\n });\n\n this.loading = false;\n m.redraw();\n });\n } else {\n this.loading = false;\n\n app.store.all('masquerade-field').forEach((field) => {\n const answer = this.answers.find((a) => a.field()?.id() === field.id());\n\n this.answerValues[field.id()] = answer ? answer.content() : '';\n });\n }\n\n m.redraw();\n }\n\n set(field, value) {\n this.answerValues[field.id()] = value;\n this.dirty = true;\n }\n\n update(e) {\n e.preventDefault();\n\n this.loading = true;\n\n app\n .request({\n method: 'POST',\n url: app.forum.attribute('apiUrl') + '/masquerade/configure/' + this.user.id(),\n body: this.answerValues,\n })\n .then((response) => {\n this.dirty = false;\n\n if (!this.profileCompleted) {\n this.profileCompleted = true;\n this.profileNowCompleted = true;\n }\n\n this.parseResponse(response);\n })\n .catch(() => {\n this.loading = false;\n m.redraw();\n });\n }\n\n parseResponse(response) {\n console.log(response);\n this.answers = app.store.pushPayload(response);\n this.loading = false;\n m.redraw();\n }\n}\n","import UserPage from 'flarum/forum/components/UserPage';\nimport LoadingIndicator from 'flarum/common/components/LoadingIndicator';\nimport ProfilePane from './ProfilePane';\nimport ProfileConfigurePane from './ProfileConfigurePane';\n\nexport default class RootMasqueradePane extends UserPage {\n loading = true;\n\n oninit(vnode) {\n super.oninit(vnode);\n\n this.loadUser(m.route.param('username'));\n }\n\n pageContentComponent() {\n if (!this.user) return null;\n\n if (this.user.canEditMasqueradeProfile()) return ;\n else return ;\n }\n\n show(user) {\n super.show(user);\n\n this.loading = false;\n m.redraw();\n }\n\n content() {\n return (\n
\n {this.loading && }\n {this.pageContentComponent()}\n
\n );\n }\n}\n","import app from 'flarum/forum/app';\nimport User from 'flarum/common/models/User';\nimport Field from './../lib/models/Field';\nimport Answer from './../lib/models/Answer';\nimport Model from 'flarum/common/Model';\n\nimport addProfilePane from './addProfilePane';\nimport mutateUserHero from './mutateUserHero';\n\n// Exports\nimport ProfileConfigurePane from './panes/ProfileConfigurePane';\nimport ProfilePane from './panes/ProfilePane';\nimport RootMasqueradePane from './panes/RootMasqueradePane';\nimport BaseField from './types/BaseField';\nimport BooleanField from './types/BooleanField';\nimport EmailField from './types/EmailField';\nimport SelectField from './types/SelectField';\nimport TypeFactory from './types/TypeFactory';\nimport UrlField from './types/UrlField';\n\napp.initializers.add('fof-masquerade', (app) => {\n app.store.models['masquerade-field'] = Field;\n app.store.models['masquerade-answer'] = Answer;\n\n User.prototype.bioFields = Model.hasMany('bioFields');\n User.prototype.masqueradeAnswers = Model.hasMany('masqueradeAnswers');\n User.prototype.canEditMasqueradeProfile = Model.attribute('canEditMasqueradeProfile');\n\n addProfilePane();\n\n mutateUserHero();\n});\n\nconst components = {\n ProfileConfigurePane,\n ProfilePane,\n RootMasqueradePane,\n};\n\nconst types = {\n BaseField,\n BooleanField,\n EmailField,\n SelectField,\n TypeFactory,\n UrlField,\n};\n\nexport { components, types };\n","import app from 'flarum/forum/app';\n\nimport { extend } from 'flarum/common/extend';\nimport LinkButton from 'flarum/common/components/LinkButton';\nimport UserPage from 'flarum/forum/components/UserPage';\nimport RootMasqueradePane from './panes/RootMasqueradePane';\n\nexport default function addProfilePane() {\n app.routes['fof-masquerade'] = {\n path: '/u/:username/masquerade',\n resolver: {\n onmatch() {\n if (!app.forum.attribute('canViewMasquerade')) throw new Error();\n\n return RootMasqueradePane;\n },\n },\n };\n\n extend(UserPage.prototype, 'navItems', function (items) {\n if (app.forum.attribute('canViewMasquerade') || this.user.canEditMasqueradeProfile()) {\n const edit = this.user.canEditMasqueradeProfile();\n\n items.add(\n 'masquerade',\n LinkButton.component(\n {\n href: app.route('fof-masquerade', { username: this.user.slug() }),\n icon: 'far fa-id-card',\n 'data-editProfile': edit,\n },\n app.translator.trans(`fof-masquerade.forum.buttons.${edit ? 'edit' : 'view'}-profile`)\n ),\n 200\n );\n }\n });\n}\n","import { extend } from 'flarum/common/extend';\nimport app from 'flarum/forum/app';\nimport UserCard from 'flarum/forum/components/UserCard';\nimport TypeFactory from './types/TypeFactory';\n\nexport default function mutateUserHero() {\n extend(UserCard.prototype, 'infoItems', function (items) {\n const answers = app.forum.attribute('canViewMasquerade') ? this.attrs.user.bioFields() || [] : [];\n\n items.add(\n 'masquerade-bio',\n
\n {answers.map((answer) => {\n const field = answer.attribute('field');\n const type = TypeFactory.typeForField({\n field,\n value: answer.content(),\n });\n\n return type.answerField();\n })}\n
\n );\n });\n}\n"],"sourceRoot":""} \ No newline at end of file