224 lines
6.3 KiB
HTML
224 lines
6.3 KiB
HTML
<script type="text/discourse-plugin" version="0.8.30">
|
|
api.decorateCooked(($cooked, postWidget) => {
|
|
const VALID_TAGS = "h1, h2, h3, h4, h5, h6, p, code, blockquote, .md-table, li";
|
|
const DELIMITER = "=";
|
|
const mappings = [];
|
|
const placeholders = {};
|
|
|
|
// http://davidwalsh.name/javascript-debounce-function
|
|
function debounce(func, wait, immediate) {
|
|
let timeout;
|
|
|
|
return function() {
|
|
const context = this,
|
|
args = arguments;
|
|
|
|
const later = function() {
|
|
timeout = null;
|
|
if (!immediate) func.apply(context, args);
|
|
};
|
|
|
|
const callNow = immediate && !timeout;
|
|
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(later, wait);
|
|
|
|
if (callNow) func.apply(context, args);
|
|
};
|
|
}
|
|
|
|
function processChange($cooked, inputEvent, mappings) {
|
|
const value = inputEvent.target.value;
|
|
const key = inputEvent.target.dataset.key;
|
|
|
|
if (postWidget) {
|
|
const placeholderIdentifier = `d-placeholder-${postWidget.widget.attrs.topicId}-${postWidget.widget.attrs.id}-${key}`;
|
|
if (value) {
|
|
$.cookie(placeholderIdentifier, value);
|
|
} else {
|
|
$.removeCookie(placeholderIdentifier);
|
|
}
|
|
}
|
|
|
|
let newValue;
|
|
if (value && value.length && value !== "none") {
|
|
newValue = value;
|
|
} else {
|
|
newValue = `${DELIMITER}${key}${DELIMITER}`;
|
|
}
|
|
|
|
$cooked.find(VALID_TAGS).each((index, elem) => {
|
|
let replaced = false;
|
|
const mapping = mappings[index];
|
|
let newInnnerHTML = elem.innerHTML;
|
|
let diff = 0;
|
|
|
|
if (!mapping) {
|
|
return;
|
|
}
|
|
|
|
mapping.forEach(m => {
|
|
if (m.pattern !== `${DELIMITER}${key}${DELIMITER}`) {
|
|
m.position = m.position + diff;
|
|
return;
|
|
}
|
|
|
|
replaced = true;
|
|
|
|
const previousLength = m.length;
|
|
const prefix = newInnnerHTML.slice(0, m.position + diff);
|
|
const suffix = newInnnerHTML.slice(
|
|
m.position + diff + m.length,
|
|
newInnnerHTML.length
|
|
);
|
|
newInnnerHTML = `${prefix}${newValue}${suffix}`;
|
|
|
|
m.length = newValue.length;
|
|
m.position = m.position + diff;
|
|
diff = diff + newValue.length - previousLength;
|
|
});
|
|
|
|
if (replaced) {
|
|
elem.innerHTML = newInnnerHTML;
|
|
}
|
|
});
|
|
}
|
|
|
|
function addSelectOption(select, options = {}) {
|
|
const option = document.createElement("option");
|
|
option.classList.add("discourse-placeholder-option");
|
|
option.value = options.value;
|
|
option.text = options.description || options.value;
|
|
|
|
if (options.selected) {
|
|
option.setAttribute("selected", true);
|
|
}
|
|
|
|
select.appendChild(option);
|
|
}
|
|
|
|
function processPlaceholders(placeholders, $cooked, mappings) {
|
|
const keys = Object.keys(placeholders);
|
|
const pattern = `(${DELIMITER}(?:${keys.join("|")})${DELIMITER})`;
|
|
const regex = new RegExp(pattern, "g");
|
|
|
|
$cooked.find(VALID_TAGS).each((index, elem) => {
|
|
const innerHTML = elem.innerHTML;
|
|
let match;
|
|
|
|
mappings[index] = mappings[index] || [];
|
|
|
|
while ((match = regex.exec(innerHTML)) != null) {
|
|
mappings[index].push({
|
|
pattern: match[1],
|
|
position: match.index,
|
|
length: match[1].length
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
$cooked.find(".d-wrap[data-wrap=placeholder]:not(.placeholdered)").each((index, elem) => {
|
|
const dataKey = elem.dataset.key;
|
|
if (!dataKey) {
|
|
return;
|
|
}
|
|
|
|
let valueFromCookie;
|
|
if (postWidget) {
|
|
const placeholderIdentifier = `d-placeholder-${postWidget.widget.attrs.topicId}-${postWidget.widget.attrs.id}`;
|
|
valueFromCookie = $.cookie(`${placeholderIdentifier}-${dataKey}`);
|
|
}
|
|
|
|
const defaultValue = valueFromCookie || elem.dataset.default;
|
|
const defaultValues = (elem.dataset.defaults || "").split(",").filter(x => x);
|
|
const description = elem.dataset.description;
|
|
|
|
placeholders[dataKey] = {
|
|
default: defaultValue,
|
|
defaults: defaultValues,
|
|
description
|
|
}
|
|
|
|
elem.classList.add("placeholdered")
|
|
|
|
const span = document.createElement("span");
|
|
span.classList.add("discourse-placeholder-name")
|
|
span.innerText = dataKey;
|
|
elem.appendChild(span)
|
|
|
|
if (defaultValues && defaultValues.length) {
|
|
const select = document.createElement("select");
|
|
select.classList.add("discourse-placeholder-select")
|
|
select.dataset.key = dataKey;
|
|
|
|
if (description) {
|
|
addSelectOption(select, { value: "none", description });
|
|
}
|
|
|
|
defaultValues.forEach(value =>
|
|
addSelectOption(select, {
|
|
value,
|
|
selected: defaultValue === value
|
|
})
|
|
);
|
|
|
|
elem.appendChild(select);
|
|
} else {
|
|
const input = document.createElement("input");
|
|
input.classList.add("discourse-placeholder-value")
|
|
input.dataset.key = dataKey;
|
|
|
|
if (description) {
|
|
input.setAttribute("placeholder", description);
|
|
}
|
|
|
|
if (valueFromCookie || defaultValue) {
|
|
input.value = valueFromCookie || defaultValue;
|
|
}
|
|
|
|
elem.appendChild(input)
|
|
}
|
|
})
|
|
|
|
$cooked
|
|
.on(
|
|
"input",
|
|
".discourse-placeholder-value",
|
|
debounce(inputEvent => {
|
|
processChange($cooked, inputEvent, mappings);
|
|
}, 250)
|
|
)
|
|
.on(
|
|
"change",
|
|
".discourse-placeholder-select",
|
|
debounce(inputEvent => {
|
|
processChange($cooked, inputEvent, mappings);
|
|
}, 250)
|
|
);
|
|
|
|
Ember.run.later(() => {
|
|
if (Object.keys(placeholders).length > 0) {
|
|
processPlaceholders(placeholders, $cooked, mappings);
|
|
}
|
|
|
|
// trigger fake event to setup initial state
|
|
Object.keys(placeholders).forEach(placeholderKey => {
|
|
const placeholder = placeholders[placeholderKey];
|
|
|
|
const value =
|
|
placeholder.default ||
|
|
(placeholder.defaults.length && !placeholder.description
|
|
? placeholder.defaults[0]
|
|
: null);
|
|
|
|
processChange(
|
|
$cooked,
|
|
{ target: { value, dataset: { key: placeholderKey } } },
|
|
mappings
|
|
);
|
|
});
|
|
}, 500);
|
|
});
|
|
</script>
|