Merge pull request #65 from paviliondev/text-counter
FEATURE: text length counter for text type fields
Dieser Commit ist enthalten in:
Commit
505043922e
14 geänderte Dateien mit 84 neuen und 10 gelöschten Zeilen
|
@ -21,7 +21,7 @@ export default Component.extend(UndoChanges, {
|
||||||
showPrefill: or('isText', 'isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
showPrefill: or('isText', 'isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
||||||
showContent: or('isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
showContent: or('isCategory', 'isTag', 'isGroup', 'isDropdown'),
|
||||||
showLimit: or('isCategory', 'isTag'),
|
showLimit: or('isCategory', 'isTag'),
|
||||||
showLengthControls: or('isText', 'isTextarea', 'isComposer'),
|
isTextType: or('isText', 'isTextarea', 'isComposer'),
|
||||||
categoryPropertyTypes: selectKitContent(['id', 'slug']),
|
categoryPropertyTypes: selectKitContent(['id', 'slug']),
|
||||||
showAdvanced: alias('field.type'),
|
showAdvanced: alias('field.type'),
|
||||||
messageUrl: 'https://thepavilion.io/t/2809',
|
messageUrl: 'https://thepavilion.io/t/2809',
|
||||||
|
|
|
@ -70,7 +70,7 @@
|
||||||
url=messageUrl
|
url=messageUrl
|
||||||
component='field'}}
|
component='field'}}
|
||||||
|
|
||||||
{{#if showLengthControls}}
|
{{#if isTextType}}
|
||||||
<div class="setting">
|
<div class="setting">
|
||||||
<div class="setting-label">
|
<div class="setting-label">
|
||||||
<label>{{i18n 'admin.wizard.field.min_length'}}</label>
|
<label>{{i18n 'admin.wizard.field.min_length'}}</label>
|
||||||
|
@ -98,6 +98,19 @@
|
||||||
class="small"}}
|
class="small"}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="setting">
|
||||||
|
<div class="setting-label">
|
||||||
|
<label>{{i18n 'admin.wizard.field.char_counter'}}</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="setting-value">
|
||||||
|
<span>{{i18n 'admin.wizard.field.char_counter_placeholder'}}</span>
|
||||||
|
{{input
|
||||||
|
type="checkbox"
|
||||||
|
checked=field.char_counter}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
{{#if isUpload}}
|
{{#if isUpload}}
|
||||||
|
|
15
assets/javascripts/wizard/helpers/char-counter.js.es6
Normale Datei
15
assets/javascripts/wizard/helpers/char-counter.js.es6
Normale Datei
|
@ -0,0 +1,15 @@
|
||||||
|
import { registerUnbound } from "discourse-common/lib/helpers";
|
||||||
|
import I18n from "I18n";
|
||||||
|
|
||||||
|
export default registerUnbound("char-counter", function(body, maxLength) {
|
||||||
|
let bodyLength = body ? body.length : 0;
|
||||||
|
let finalString;
|
||||||
|
|
||||||
|
if (maxLength) {
|
||||||
|
finalString = `<div class="body-length">${bodyLength} / ${I18n.t('wizard.x_characters', { count: parseInt(maxLength) })}</div>`;
|
||||||
|
} else {
|
||||||
|
finalString = `<div class="body-length">${I18n.t('wizard.x_characters', { count: parseInt(bodyLength) })}</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Handlebars.SafeString(finalString);
|
||||||
|
});
|
|
@ -1,4 +1,5 @@
|
||||||
import { dasherize } from "@ember/string";
|
import { dasherize } from "@ember/string";
|
||||||
|
import discourseComputed from "discourse-common/utils/decorators";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "custom-wizard-field",
|
name: "custom-wizard-field",
|
||||||
|
@ -15,6 +16,11 @@ export default {
|
||||||
FieldComponent.reopen({
|
FieldComponent.reopen({
|
||||||
classNameBindings: ["field.id"],
|
classNameBindings: ["field.id"],
|
||||||
|
|
||||||
|
@discourseComputed("field.type")
|
||||||
|
textType(fieldType) {
|
||||||
|
return ['text', 'textarea'].includes(fieldType);
|
||||||
|
},
|
||||||
|
|
||||||
cookedDescription: function () {
|
cookedDescription: function () {
|
||||||
return cook(this.get("field.description"));
|
return cook(this.get("field.description"));
|
||||||
}.property("field.description"),
|
}.property("field.description"),
|
||||||
|
|
|
@ -7,6 +7,12 @@
|
||||||
togglePreview=(action "togglePreview")
|
togglePreview=(action "togglePreview")
|
||||||
afterRefresh=(action "afterRefresh")}}
|
afterRefresh=(action "afterRefresh")}}
|
||||||
|
|
||||||
|
<div class="bottom-bar">
|
||||||
<button class='wizard-btn toggle-preview' {{action 'togglePreview'}}>
|
<button class='wizard-btn toggle-preview' {{action 'togglePreview'}}>
|
||||||
<span class="d-button-label">{{wizard-i18n togglePreviewLabel}}</span>
|
<span class="d-button-label">{{wizard-i18n togglePreviewLabel}}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
{{#if field.char_counter}}
|
||||||
|
{{char-counter field.value field.max_length}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
|
|
@ -16,6 +16,12 @@
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
||||||
|
{{#if field.char_counter}}
|
||||||
|
{{#if textType}}
|
||||||
|
{{char-counter field.value field.max_length}}
|
||||||
|
{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
{{#if field.errorDescription}}
|
{{#if field.errorDescription}}
|
||||||
<div class='field-error-description'>{{{field.errorDescription}}}</div>
|
<div class='field-error-description'>{{{field.errorDescription}}}</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
|
|
@ -80,3 +80,6 @@ textarea {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.body-length {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
|
@ -50,10 +50,6 @@
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-wizard .wizard-field-composer .toggle-preview {
|
|
||||||
margin-top: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.d-editor-textarea-wrapper,
|
.d-editor-textarea-wrapper,
|
||||||
.d-editor-preview-wrapper {
|
.d-editor-preview-wrapper {
|
||||||
background-color: var(--secondary);
|
background-color: var(--secondary);
|
||||||
|
@ -230,3 +226,10 @@
|
||||||
bottom: -40px;
|
bottom: -40px;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bottom-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content:space-between;
|
||||||
|
margin-top: 20px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
|
@ -166,6 +166,8 @@ en:
|
||||||
min_length_placeholder: "Minimum length in characters"
|
min_length_placeholder: "Minimum length in characters"
|
||||||
max_length: "Max Length"
|
max_length: "Max Length"
|
||||||
max_length_placeholder: "Maximum length in characters"
|
max_length_placeholder: "Maximum length in characters"
|
||||||
|
char_counter: "Character Counter"
|
||||||
|
char_counter_placeholder: "Display Character Counter"
|
||||||
file_types: "File Types"
|
file_types: "File Types"
|
||||||
limit: "Limit"
|
limit: "Limit"
|
||||||
property: "Property"
|
property: "Property"
|
||||||
|
@ -469,6 +471,9 @@ en:
|
||||||
requires_login: "You need to be logged in to access this wizard."
|
requires_login: "You need to be logged in to access this wizard."
|
||||||
reset: "Reset this wizard."
|
reset: "Reset this wizard."
|
||||||
step_not_permitted: "You're not permitted to view this step."
|
step_not_permitted: "You're not permitted to view this step."
|
||||||
|
x_characters:
|
||||||
|
one: "%{count} Character"
|
||||||
|
other: "%{count} Characters"
|
||||||
|
|
||||||
wizard_composer:
|
wizard_composer:
|
||||||
show_preview: "Preview Post"
|
show_preview: "Preview Post"
|
||||||
|
|
|
@ -98,6 +98,7 @@ class CustomWizard::AdminWizardController < CustomWizard::AdminController
|
||||||
:type,
|
:type,
|
||||||
:min_length,
|
:min_length,
|
||||||
:max_length,
|
:max_length,
|
||||||
|
:char_counter,
|
||||||
:file_types,
|
:file_types,
|
||||||
:format,
|
:format,
|
||||||
:limit,
|
:limit,
|
||||||
|
|
|
@ -6,6 +6,7 @@ module CustomWizardFieldExtension
|
||||||
:key,
|
:key,
|
||||||
:min_length,
|
:min_length,
|
||||||
:max_length,
|
:max_length,
|
||||||
|
:char_counter,
|
||||||
:file_types,
|
:file_types,
|
||||||
:format,
|
:format,
|
||||||
:limit,
|
:limit,
|
||||||
|
@ -21,6 +22,7 @@ module CustomWizardFieldExtension
|
||||||
@key = attrs[:key]
|
@key = attrs[:key]
|
||||||
@min_length = attrs[:min_length]
|
@min_length = attrs[:min_length]
|
||||||
@max_length = attrs[:max_length]
|
@max_length = attrs[:max_length]
|
||||||
|
@char_counter = attrs[:char_counter]
|
||||||
@file_types = attrs[:file_types]
|
@file_types = attrs[:file_types]
|
||||||
@format = attrs[:format]
|
@format = attrs[:format]
|
||||||
@limit = attrs[:limit]
|
@limit = attrs[:limit]
|
||||||
|
|
|
@ -160,6 +160,7 @@ class CustomWizard::Builder
|
||||||
params[:key] = field_template['key'] if field_template['key']
|
params[:key] = field_template['key'] if field_template['key']
|
||||||
params[:min_length] = field_template['min_length'] if field_template['min_length']
|
params[:min_length] = field_template['min_length'] if field_template['min_length']
|
||||||
params[:max_length] = field_template['max_length'] if field_template['max_length']
|
params[:max_length] = field_template['max_length'] if field_template['max_length']
|
||||||
|
params[:char_counter] = field_template['char_counter'] if field_template['char_counter']
|
||||||
params[:value] = prefill_field(field_template, step_template)
|
params[:value] = prefill_field(field_template, step_template)
|
||||||
|
|
||||||
if !build_opts[:reset] && (submission = @wizard.current_submission)
|
if !build_opts[:reset] && (submission = @wizard.current_submission)
|
||||||
|
|
|
@ -4,16 +4,19 @@ class CustomWizard::Field
|
||||||
text: {
|
text: {
|
||||||
min_length: nil,
|
min_length: nil,
|
||||||
max_length: nil,
|
max_length: nil,
|
||||||
prefill: nil
|
prefill: nil,
|
||||||
|
char_counter: nil
|
||||||
},
|
},
|
||||||
textarea: {
|
textarea: {
|
||||||
min_length: nil,
|
min_length: nil,
|
||||||
max_length: nil,
|
max_length: nil,
|
||||||
prefill: nil
|
prefill: nil,
|
||||||
|
char_counter: nil
|
||||||
},
|
},
|
||||||
composer: {
|
composer: {
|
||||||
min_length: nil,
|
min_length: nil,
|
||||||
max_length: nil,
|
max_length: nil,
|
||||||
|
char_counter: nil
|
||||||
},
|
},
|
||||||
text_only: {},
|
text_only: {},
|
||||||
date: {
|
date: {
|
||||||
|
|
|
@ -8,6 +8,8 @@ class CustomWizard::FieldSerializer < ::WizardFieldSerializer
|
||||||
:limit,
|
:limit,
|
||||||
:property,
|
:property,
|
||||||
:content,
|
:content,
|
||||||
|
:max_length,
|
||||||
|
:char_counter,
|
||||||
:number
|
:number
|
||||||
|
|
||||||
def label
|
def label
|
||||||
|
@ -56,6 +58,14 @@ class CustomWizard::FieldSerializer < ::WizardFieldSerializer
|
||||||
object.choices.present?
|
object.choices.present?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def max_length
|
||||||
|
object.max_length
|
||||||
|
end
|
||||||
|
|
||||||
|
def char_counter
|
||||||
|
object.char_counter
|
||||||
|
end
|
||||||
|
|
||||||
def number
|
def number
|
||||||
object.number
|
object.number
|
||||||
end
|
end
|
||||||
|
|
Laden …
In neuem Issue referenzieren