Spiegel von
https://github.com/paviliondev/discourse-custom-wizard.git
synchronisiert 2024-11-09 11:52:54 +01:00
Merge branch 'main' into add_combo_box_field
Dieser Commit ist enthalten in:
Commit
057b3f989f
6 geänderte Dateien mit 103 neuen und 30 gelöschten Zeilen
|
@ -18,6 +18,8 @@ import { inject as service } from "@ember/service";
|
||||||
const IMAGE_MARKDOWN_REGEX =
|
const IMAGE_MARKDOWN_REGEX =
|
||||||
/!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?(.*?)\]\((upload:\/\/.*?)\)(?!(.*`))/g;
|
/!\[(.*?)\|(\d{1,4}x\d{1,4})(,\s*\d{1,3}%)?(.*?)\]\((upload:\/\/.*?)\)(?!(.*`))/g;
|
||||||
|
|
||||||
|
export const wizardComposerEdtiorEventPrefix = "wizard-editor";
|
||||||
|
|
||||||
export default ComposerEditor.extend({
|
export default ComposerEditor.extend({
|
||||||
modal: service(),
|
modal: service(),
|
||||||
|
|
||||||
|
@ -33,29 +35,15 @@ export default ComposerEditor.extend({
|
||||||
draftStatus: "null",
|
draftStatus: "null",
|
||||||
replyPlaceholder: alias("field.translatedPlaceholder"),
|
replyPlaceholder: alias("field.translatedPlaceholder"),
|
||||||
wizardEventFieldId: null,
|
wizardEventFieldId: null,
|
||||||
composerEventPrefix: "wizard-editor",
|
composerEventPrefix: wizardComposerEdtiorEventPrefix,
|
||||||
|
|
||||||
@on("didInsertElement")
|
@on("didInsertElement")
|
||||||
_composerEditorInit() {
|
_composerEditorInit() {
|
||||||
|
this._super(...arguments);
|
||||||
|
|
||||||
|
if (this.siteSettings.mentionables_enabled) {
|
||||||
const $input = $(this.element.querySelector(".d-editor-input"));
|
const $input = $(this.element.querySelector(".d-editor-input"));
|
||||||
|
|
||||||
if (this.siteSettings.enable_mentions) {
|
|
||||||
$input.autocomplete({
|
|
||||||
template: findRawTemplate("user-selector-autocomplete"),
|
|
||||||
dataSource: (term) => this._userSearchTerm.call(this, term),
|
|
||||||
key: "@",
|
|
||||||
transformComplete: (v) => v.username || v.name,
|
|
||||||
afterComplete: (value) => {
|
|
||||||
this.composer.set("reply", value);
|
|
||||||
scheduleOnce("afterRender", () => $input.blur().focus());
|
|
||||||
},
|
|
||||||
triggerRule: (textarea) =>
|
|
||||||
!inCodeBlock(textarea.value, caretPosition(textarea)),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const siteSettings = this.siteSettings;
|
|
||||||
if (siteSettings.mentionables_enabled) {
|
|
||||||
Site.currentProp("mentionable_items", this.wizard.mentionable_items);
|
Site.currentProp("mentionable_items", this.wizard.mentionable_items);
|
||||||
const { SEPARATOR } = requirejs(
|
const { SEPARATOR } = requirejs(
|
||||||
"discourse/plugins/discourse-mentionables/discourse/lib/discourse-markdown/mentionable-items"
|
"discourse/plugins/discourse-mentionables/discourse/lib/discourse-markdown/mentionable-items"
|
||||||
|
@ -73,15 +61,14 @@ export default ComposerEditor.extend({
|
||||||
},
|
},
|
||||||
transformComplete: (item) => item.model.slug,
|
transformComplete: (item) => item.model.slug,
|
||||||
dataSource: (term) =>
|
dataSource: (term) =>
|
||||||
term.match(/\s/) ? null : searchMentionableItem(term, siteSettings),
|
term.match(/\s/)
|
||||||
|
? null
|
||||||
|
: searchMentionableItem(term, this.siteSettings),
|
||||||
triggerRule: (textarea) =>
|
triggerRule: (textarea) =>
|
||||||
!inCodeBlock(textarea.value, caretPosition(textarea)),
|
!inCodeBlock(textarea.value, caretPosition(textarea)),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
$input.on("scroll", this._throttledSyncEditorAndPreviewScroll);
|
|
||||||
this._bindUploadTarget();
|
|
||||||
|
|
||||||
const field = this.field;
|
const field = this.field;
|
||||||
this.editorInputClass = `.${dasherize(field.type)}-${dasherize(
|
this.editorInputClass = `.${dasherize(field.type)}-${dasherize(
|
||||||
field.id
|
field.id
|
||||||
|
|
|
@ -7,8 +7,19 @@ import { cook } from "discourse/lib/text";
|
||||||
import CustomWizard, {
|
import CustomWizard, {
|
||||||
updateCachedWizard,
|
updateCachedWizard,
|
||||||
} from "discourse/plugins/discourse-custom-wizard/discourse/models/custom-wizard";
|
} from "discourse/plugins/discourse-custom-wizard/discourse/models/custom-wizard";
|
||||||
import { alias, not } from "@ember/object/computed";
|
import { alias, not, or } from "@ember/object/computed";
|
||||||
import discourseLater from "discourse-common/lib/later";
|
import discourseLater from "discourse-common/lib/later";
|
||||||
|
import { wizardComposerEdtiorEventPrefix } from "./custom-wizard-composer-editor";
|
||||||
|
|
||||||
|
const uploadStartedEventKeys = ["upload-started"];
|
||||||
|
const uploadEndedEventKeys = [
|
||||||
|
"upload-success",
|
||||||
|
"upload-error",
|
||||||
|
"upload-cancelled",
|
||||||
|
"uploads-cancelled",
|
||||||
|
"uploads-aborted",
|
||||||
|
"all-uploads-complete",
|
||||||
|
];
|
||||||
|
|
||||||
export default Component.extend({
|
export default Component.extend({
|
||||||
classNameBindings: [":wizard-step", "step.id"],
|
classNameBindings: [":wizard-step", "step.id"],
|
||||||
|
@ -28,6 +39,17 @@ export default Component.extend({
|
||||||
cook(this.step.translatedDescription).then((cookedDescription) => {
|
cook(this.step.translatedDescription).then((cookedDescription) => {
|
||||||
this.set("cookedDescription", cookedDescription);
|
this.set("cookedDescription", cookedDescription);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
uploadStartedEventKeys.forEach((key) => {
|
||||||
|
this.appEvents.on(`${wizardComposerEdtiorEventPrefix}:${key}`, () => {
|
||||||
|
this.set("uploading", true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
uploadEndedEventKeys.forEach((key) => {
|
||||||
|
this.appEvents.on(`${wizardComposerEdtiorEventPrefix}:${key}`, () => {
|
||||||
|
this.set("uploading", false);
|
||||||
|
});
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
didInsertElement() {
|
didInsertElement() {
|
||||||
|
@ -40,6 +62,7 @@ export default Component.extend({
|
||||||
|
|
||||||
showNextButton: not("step.final"),
|
showNextButton: not("step.final"),
|
||||||
showDoneButton: alias("step.final"),
|
showDoneButton: alias("step.final"),
|
||||||
|
btnsDisabled: or("saving", "uploading"),
|
||||||
|
|
||||||
@discourseComputed(
|
@discourseComputed(
|
||||||
"step.index",
|
"step.index",
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="wizard-btn next primary"
|
class="wizard-btn next primary"
|
||||||
{{action "nextStep"}}
|
{{action "nextStep"}}
|
||||||
disabled={{saving}}
|
disabled={{btnsDisabled}}
|
||||||
tabindex={{primaryButtonIndex}}
|
tabindex={{primaryButtonIndex}}
|
||||||
>
|
>
|
||||||
{{i18n "wizard.next"}}
|
{{i18n "wizard.next"}}
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
type="button"
|
type="button"
|
||||||
class="wizard-btn done"
|
class="wizard-btn done"
|
||||||
{{action "done"}}
|
{{action "done"}}
|
||||||
disabled={{saving}}
|
disabled={{btnsDisabled}}
|
||||||
tabindex={{primaryButtonIndex}}
|
tabindex={{primaryButtonIndex}}
|
||||||
>
|
>
|
||||||
{{i18n "wizard.done_custom"}}
|
{{i18n "wizard.done_custom"}}
|
||||||
|
|
|
@ -160,6 +160,10 @@ body.custom-wizard {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.powered-by-discourse {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* IE11 hacks */
|
/* IE11 hacks */
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
# name: discourse-custom-wizard
|
# name: discourse-custom-wizard
|
||||||
# about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more.
|
# about: Forms for Discourse. Better onboarding, structured posting, data enrichment, automated actions and much more.
|
||||||
# version: 2.6.8
|
# version: 2.6.11
|
||||||
# authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever, Juan Marcos Gutierrez Ramos
|
# authors: Angus McLeod, Faizaan Gagan, Robert Barrow, Keegan George, Kaitlin Maddever, Juan Marcos Gutierrez Ramos
|
||||||
# url: https://github.com/paviliondev/discourse-custom-wizard
|
# url: https://github.com/paviliondev/discourse-custom-wizard
|
||||||
# contact_emails: development@pavilion.tech
|
# contact_emails: development@pavilion.tech
|
||||||
|
@ -185,17 +185,17 @@ after_initialize do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
add_to_serializer(:site, :include_wizard_required?) do
|
add_to_class(:site_serializer, :include_wizard_required?) do
|
||||||
scope.is_admin? && Wizard.new(scope.user).requires_completion?
|
scope.is_admin? && Wizard.new(scope.user).requires_completion?
|
||||||
end
|
end
|
||||||
|
|
||||||
add_to_serializer(:site, :complete_custom_wizard) do
|
add_to_class(:site_serializer, :complete_custom_wizard) do
|
||||||
if scope.user && requires_completion = CustomWizard::Wizard.prompt_completion(scope.user)
|
if scope.user && requires_completion = CustomWizard::Wizard.prompt_completion(scope.user)
|
||||||
requires_completion.map { |w| { name: w[:name], url: "/w/#{w[:id]}" } }
|
requires_completion.map { |w| { name: w[:name], url: "/w/#{w[:id]}" } }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
add_to_serializer(:site, :include_complete_custom_wizard?) do
|
add_to_class(:site_serializer, :include_complete_custom_wizard?) do
|
||||||
complete_custom_wizard.present?
|
complete_custom_wizard.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
import { click, fillIn, triggerKeyEvent, visit } from "@ember/test-helpers";
|
import { getOwner } from "@ember/application";
|
||||||
|
import {
|
||||||
|
click,
|
||||||
|
fillIn,
|
||||||
|
settled,
|
||||||
|
triggerKeyEvent,
|
||||||
|
visit,
|
||||||
|
} from "@ember/test-helpers";
|
||||||
import { test } from "qunit";
|
import { test } from "qunit";
|
||||||
import {
|
import {
|
||||||
acceptance,
|
acceptance,
|
||||||
count,
|
count,
|
||||||
|
createFile,
|
||||||
exists,
|
exists,
|
||||||
query,
|
query,
|
||||||
visible,
|
visible,
|
||||||
|
@ -11,6 +19,8 @@ import { allFieldsWizard } from "../helpers/wizard";
|
||||||
import tagsJson from "../fixtures/tags";
|
import tagsJson from "../fixtures/tags";
|
||||||
import usersJson from "../fixtures/users";
|
import usersJson from "../fixtures/users";
|
||||||
|
|
||||||
|
const wizardComposerEdtiorEventPrefix = "wizard-editor";
|
||||||
|
|
||||||
acceptance("Field | Fields", function (needs) {
|
acceptance("Field | Fields", function (needs) {
|
||||||
needs.pretender((server, helper) => {
|
needs.pretender((server, helper) => {
|
||||||
server.get("/w/wizard.json", () => helper.response(allFieldsWizard));
|
server.get("/w/wizard.json", () => helper.response(allFieldsWizard));
|
||||||
|
@ -18,6 +28,28 @@ acceptance("Field | Fields", function (needs) {
|
||||||
helper.response({ results: tagsJson["tags"] })
|
helper.response({ results: tagsJson["tags"] })
|
||||||
);
|
);
|
||||||
server.get("/u/search/users", () => helper.response(usersJson));
|
server.get("/u/search/users", () => helper.response(usersJson));
|
||||||
|
|
||||||
|
server.post(
|
||||||
|
"/uploads.json",
|
||||||
|
() => {
|
||||||
|
return helper.response({
|
||||||
|
extension: "jpeg",
|
||||||
|
filesize: 126177,
|
||||||
|
height: 800,
|
||||||
|
human_filesize: "123 KB",
|
||||||
|
id: 202,
|
||||||
|
original_filename: "avatar.PNG.jpg",
|
||||||
|
retain_hours: null,
|
||||||
|
short_path: "/uploads/short-url/yoj8pf9DdIeHRRULyw7i57GAYdz.jpeg",
|
||||||
|
short_url: "upload://yoj8pf9DdIeHRRULyw7i57GAYdz.jpeg",
|
||||||
|
thumbnail_height: 320,
|
||||||
|
thumbnail_width: 690,
|
||||||
|
url: "/images/discourse-logo-sketch-small.png",
|
||||||
|
width: 1920,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
500 // this delay is important to slow down the uploads a bit so we can let elements of the interface update
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("Text", async function (assert) {
|
test("Text", async function (assert) {
|
||||||
|
@ -54,6 +86,33 @@ acceptance("Field | Fields", function (needs) {
|
||||||
"Input in composer"
|
"Input in composer"
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("Composer - Upload Disables Next Button", async function (assert) {
|
||||||
|
await visit("/w/wizard");
|
||||||
|
const appEvents = getOwner(this).lookup("service:app-events");
|
||||||
|
const done = assert.async();
|
||||||
|
|
||||||
|
appEvents.on(
|
||||||
|
`${wizardComposerEdtiorEventPrefix}:all-uploads-complete`,
|
||||||
|
async () => {
|
||||||
|
await settled();
|
||||||
|
assert.ok(!exists(".wizard-btn.next.primary:disabled"));
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
appEvents.on(
|
||||||
|
`${wizardComposerEdtiorEventPrefix}:upload-started`,
|
||||||
|
async () => {
|
||||||
|
await settled();
|
||||||
|
assert.ok(exists(".wizard-btn.next.primary:disabled"));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const image = createFile("avatar.png");
|
||||||
|
appEvents.trigger(`${wizardComposerEdtiorEventPrefix}:add-files`, image);
|
||||||
|
});
|
||||||
|
|
||||||
test("Composer - Hyperlink", async function (assert) {
|
test("Composer - Hyperlink", async function (assert) {
|
||||||
await visit("/w/wizard");
|
await visit("/w/wizard");
|
||||||
assert.ok(
|
assert.ok(
|
||||||
|
|
Laden …
In neuem Issue referenzieren