discourse-placeholder-theme.../common/header.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>