first commit

This commit is contained in:
Roman Pyrih
2025-08-26 10:50:15 +02:00
commit 97352dcdc9
6905 changed files with 2717203 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
"use strict"
const { createElement, Fragment, useState } = wp.element;
const { withSelect, withDispatch } = wp.data;
const { compose } = wp.compose;
function CheckBoxCustom(props) {
const [isChecked, setIsChecked] = useState(props.meta.inline_featured_image);
const {
meta,
updateInlineFeaturedSvg,
} = props;
return createElement(
wp.components.CheckboxControl,
{
label: "Render this SVG inline (Advanced)",
checked: isChecked,
onChange: (value) => {
setIsChecked(value);
updateInlineFeaturedSvg(value, meta);
},
__nextHasNoMarginBottom: true
}
);
}
const composedCheckBox = compose([
withSelect((select) => {
const currentMeta = select('core/editor').getCurrentPostAttribute('meta');
const editedMeta = select('core/editor').getEditedPostAttribute('meta');
return {
meta: { ...currentMeta, ...editedMeta },
};
}),
withDispatch((dispatch) => ({
updateInlineFeaturedSvg(value, meta) {
meta = {
...meta,
inline_featured_image: value,
};
dispatch('core/editor').editPost({ meta });
},
})),
])(CheckBoxCustom);
function wrapPostFeaturedImage(OriginalComponent) {
return function(props) {
return createElement(
Fragment,
{},
'',
createElement(
OriginalComponent,
props
),
createElement(
composedCheckBox
)
);
}
}
wp.hooks.addFilter(
'editor.PostFeaturedImage',
'bodhi-svgs-featured-image/render-inline-image-checkbox',
wrapPostFeaturedImage
);

View File

@@ -0,0 +1,643 @@
;
(function ($) {
'use strict';
function noop() { }
function throttle(func, wait, options) {
var context, args, result;
var timeout = null;
// 上次执行时间点
var previous = 0;
if (!options) options = {};
// 延迟执行函数
var later = function () {
// 若设定了开始边界不执行选项上次执行时间始终为0
previous = options.leading === false ? 0 : new Date().getTime();
timeout = null;
result = func.apply(context, args);
if (!timeout) context = args = null;
};
return function () {
var now = new Date().getTime();
// 首次执行时,如果设定了开始边界不执行选项,将上次执行时间设定为当前时间。
if (!previous && options.leading === false) previous = now;
// 延迟执行时间间隔
var remaining = wait - (now - previous);
context = this;
args = arguments;
// 延迟时间间隔remaining小于等于0表示上次执行至此所间隔时间已经超过一个时间窗口
// remaining大于时间窗口wait表示客户端系统时间被调整过
if (remaining <= 0 || remaining > wait) {
clearTimeout(timeout);
timeout = null;
previous = now;
result = func.apply(context, args);
if (!timeout) context = args = null;
//如果延迟执行不存在,且没有设定结尾边界不执行选项
} else if (!timeout && options.trailing !== false) {
timeout = setTimeout(later, remaining);
}
return result;
};
}
var isSafari = function () {
var ua = navigator.userAgent.toLowerCase();
if (ua.indexOf('safari') !== -1) {
return ua.indexOf('chrome') > -1 ? false : true;
}
}();
var settings = {
readonly: false,
minCount: 0,
minCountErrorMessage: '',
limitCount: Infinity,
limitCountErrorMessage: '',
input: '<input type="text" maxLength="20" placeholder="Search...">',
data: [],
searchable: true,
searchNoData: '<li style="color:#ddd">No Results.</li>',
init: noop,
choice: noop,
extendProps: []
};
var KEY_CODE = {
up: 38,
down: 40,
enter: 13
};
var EVENT_SPACE = {
click: 'click.iui-dropdown',
focus: 'focus.iui-dropdown',
keydown: 'keydown.iui-dropdown',
keyup: 'keyup.iui-dropdown'
};
var ALERT_TIMEOUT_PERIOD = 1000;
// 创建模板
function createTemplate() {
var isLabelMode = this.isLabelMode;
var searchable = this.config.searchable;
var templateSearch = searchable ? '<span class="dropdown-search">' + this.config.input + '</span>' : '';
return isLabelMode ? '<div class="dropdown-display-label"><div class="dropdown-chose-list">' + templateSearch + '</div></div><div class="dropdown-main">{{ul}}</div>' : '<a href="javascript:;" class="dropdown-display" tabindex="0"><span class="dropdown-chose-list"></span><a href="javascript:;" class="dropdown-clear-all" tabindex="0">\xD7</a></a><div class="dropdown-main">' + templateSearch + '{{ul}}</div>';
}
// 小于minCount提示的元素
function minItemsAlert() {
var _dropdown = this;
var _config = _dropdown.config;
var $el = _dropdown.$el;
var $alert = $el.find('.dropdown-minItem-alert');
var alertMessage = _config.minCountErrorMessage;
clearTimeout(_dropdown.itemCountAlertTimer);
if ($alert.length === 0) {
if (!alertMessage) {
alertMessage = '\u6700\u4f4e\u9009\u62e9' + _config.minCount + '\u4E2A';
}
$alert = $('<div class="dropdown-minItem-alert">' + alertMessage + '</div>');
}
$el.append($alert);
_dropdown.itemCountAlertTimer = setTimeout(function () {
$el.find('.dropdown-minItem-alert').remove();
}, ALERT_TIMEOUT_PERIOD);
}
// 超出限制提示
function maxItemAlert() {
var _dropdown = this;
var _config = _dropdown.config;
var $el = _dropdown.$el;
var $alert = $el.find('.dropdown-maxItem-alert');
var alertMessage = _config.limitCountErrorMessage;
clearTimeout(_dropdown.itemLimitAlertTimer);
if ($alert.length === 0) {
if (!alertMessage) {
alertMessage = '\u6700\u591A\u53EF\u9009\u62E9' + _config.limitCount + '\u4E2A';
}
$alert = $('<div class="dropdown-maxItem-alert">' + alertMessage + '</div>');
}
$el.append($alert);
_dropdown.itemLimitAlertTimer = setTimeout(function () {
$el.find('.dropdown-maxItem-alert').remove();
}, ALERT_TIMEOUT_PERIOD);
}
// select-option 转 ul-li
function selectToDiv(str) {
var result = str || '';
// 移除select标签
result = result.replace(/<select[^>]*>/gi, '').replace('</select>', '');
// 移除 optgroup 结束标签
result = result.replace(/<\/optgroup>/gi, '');
result = result.replace(/<optgroup[^>]*>/gi, function (matcher) {
var groupName = /label="(.[^"]*)"(\s|>)/.exec(matcher);
var groupId = /data\-group\-id="(.[^"]*)"(\s|>)/.exec(matcher);
return '<li class="dropdown-group" data-group-id="' + (groupId ? groupId[1] : '') + '">' + (groupName ? groupName[1] : '') + '</li>';
});
result = result.replace(/<option(.*?)<\/option>/gi, function (matcher) {
// var value = /value="?([\w\u4E00-\u9FA5\uF900-\uFA2D]+)"?/.exec(matcher);
var value = $(matcher).val();
var name = />(.*)<\//.exec(matcher);
// 强制要求html中使用selected/disabled而不是selected="selected","disabled="disabled"
var isSelected = matcher.indexOf('selected') > -1 ? true : false;
var isDisabled = matcher.indexOf('disabled') > -1 ? true : false;
var extendAttr = ''
var extendProps = matcher.replace(/data-(\w+)="?(.[^"]+)"?/g, function ($1) {
extendAttr += $1 + ' '
});
return '<li ' + (isDisabled ? ' disabled' : ' tabindex="0"') + ' data-value="' + (value || '') + '" class="dropdown-option ' + (isSelected ? 'dropdown-chose' : '') + '" ' + extendAttr + '>' + (name ? name[1] : '') + '</li>';
});
return result;
}
// object-data 转 select-option
function objectToSelect(data) {
var dropdown = this;
var map = {};
var result = '';
var name = [];
var selectAmount = 0;
var extendProps = dropdown.config.extendProps;
if (!data || !data.length) {
return false;
}
$.each(data, function (index, val) {
// disable 权重高于 selected
var hasGroup = val.groupId;
var isDisabled = val.disabled ? ' disabled' : '';
var isSelected = val.selected && !isDisabled ? ' selected' : '';
var extendAttr = ''
$.each(extendProps, function (index, value) {
if (val[value]) {
extendAttr += 'data-' + value + '="' + val[value] + '" '
}
})
var temp = '<option' + isDisabled + isSelected + ' value="' + val.id + '" ' + extendAttr + '>' + val.name + '</option>';
if (isSelected) {
name.push('<span class="dropdown-selected">' + val.name + '<i class="del" data-id="' + val.id + '"></i></span>');
selectAmount++;
}
// 判断是否有分组
if (hasGroup) {
if (map[val.groupId]) {
map[val.groupId] += temp;
} else {
// &janking& just a separator
map[val.groupId] = val.groupName + '&janking&' + temp;
}
} else {
map[index] = temp;
}
});
$.each(map, function (index, val) {
var option = val.split('&janking&');
// 判断是否有分组
if (option.length === 2) {
var groupName = option[0];
var items = option[1];
result += '<optgroup label="' + groupName + '" data-group-id="' + index + '">' + items + '</optgroup>';
} else {
result += val;
}
});
return [result, name, selectAmount];
}
// select-option 转 object-data
//
function selectToObject(el) {
var $select = el;
var result = [];
function readOption(key, el) {
var $option = $(el);
this.id = $option.prop('value');
this.name = $option.text();
this.disabled = $option.prop('disabled');
this.selected = $option.prop('selected');
}
$.each($select.children(), function (key, el) {
var tmp = {};
var tmpGroup = {};
var $el = $(el);
if (el.nodeName === 'OPTGROUP') {
tmpGroup.groupId = $el.data('groupId');
tmpGroup.groupName = $el.attr('label');
$.each($el.children(), $.proxy(readOption, tmp));
$.extend(tmp, tmpGroup);
} else {
$.each($el, $.proxy(readOption, tmp));
}
result.push(tmp);
});
return result;
}
var action = {
show: function (event) {
event.stopPropagation();
var _dropdown = this;
$(document).trigger('click.dropdown');
_dropdown.$el.addClass('active');
},
search: throttle(function (event) {
var _dropdown = this;
var _config = _dropdown.config;
var $el = _dropdown.$el;
var $input = $(event.target);
var intputValue = $input.val();
var data = _dropdown.config.data;
var result = [];
if (event.keyCode > 36 && event.keyCode < 41) {
return;
}
$.each(data, function (key, value) {
if ((value.groupName && value.groupName.toLowerCase().indexOf(intputValue.toLowerCase()) > -1) || value.name.toLowerCase().indexOf(intputValue.toLowerCase()) > -1 || '' + value.id === '' + intputValue) {
result.push(value);
}
});
$el.find('ul').html(selectToDiv(objectToSelect.call(_dropdown, result)[0]) || _config.searchNoData);
}, 300),
control: function (event) {
var keyCode = event.keyCode;
var KC = KEY_CODE;
var index = 0;
var direct;
var itemIndex;
var $items;
if (keyCode === KC.down || keyCode === KC.up) {
// 方向
direct = keyCode === KC.up ? -1 : 1;
$items = this.$el.find('[tabindex]');
itemIndex = $items.index($(document.activeElement));
// 初始
if (itemIndex === -1) {
index = direct + 1 ? -1 : 0;
} else {
index = itemIndex;
}
// 确认位序
index = index + direct;
// 最后位循环
if (index === $items.length) {
index = 0;
}
$items.eq(index).focus();
event.preventDefault();
}
},
multiChoose: function (event, status) {
var _dropdown = this;
var _config = _dropdown.config;
var $select = _dropdown.$select;
var $target = $(event.target);
var value = $target.attr('data-value');
var hasSelected = $target.hasClass('dropdown-chose');
var selectedName = [];
var selectedProp;
if ($target.hasClass('dropdown-display')) {
return false;
}
if (hasSelected) {
$target.removeClass('dropdown-chose');
_dropdown.selectAmount--;
} else {
if (_dropdown.selectAmount < _config.limitCount) {
$target.addClass('dropdown-chose');
_dropdown.selectAmount++;
} else {
maxItemAlert.call(_dropdown);
return false;
}
}
_dropdown.name = [];
$.each(_config.data, function (key, item) {
if ('' + item.id === '' + value) {
selectedProp = item;
item.selected = hasSelected ? false : true;
}
if (item.selected) {
selectedName.push(item.name);
_dropdown.name.push('<span class="dropdown-selected">' + item.name + '<i class="del" data-id="' + item.id + '"></i></span>');
}
});
$select.find('option[value="' + value + '"]').prop('selected', hasSelected ? false : true);
if (hasSelected && _dropdown.selectAmount < _config.minCount) {
minItemsAlert.call(_dropdown);
}
_dropdown.$choseList.find('.dropdown-selected').remove();
_dropdown.$choseList.prepend(_dropdown.name.join(''));
_dropdown.$el.find('.dropdown-display').attr('title', selectedName.join(','));
_config.choice.call(_dropdown, event, selectedProp);
},
singleChoose: function (event) {
var _dropdown = this;
var _config = _dropdown.config;
var $el = _dropdown.$el;
var $select = _dropdown.$select;
var $target = $(event.target);
var value = $target.attr('data-value');
var hasSelected = $target.hasClass('dropdown-chose');
if ($target.hasClass('dropdown-chose') || $target.hasClass('dropdown-display')) {
return false;
}
_dropdown.name = [];
$el.removeClass('active').find('li').not($target).removeClass('dropdown-chose');
$target.toggleClass('dropdown-chose');
$.each(_config.data, function (key, item) {
// id 有可能是数字也有可能是字符串,强制全等有弊端 2017-03-20 22:19:21
item.selected = false;
if ('' + item.id === '' + value) {
item.selected = hasSelected ? 0 : 1;
if (item.selected) {
_dropdown.name.push('<span class="dropdown-selected">' + item.name + '<i class="del" data-id="' + item.id + '"></i></span>');
}
}
});
$select.find('option[value="' + value + '"]').prop('selected', true);
_dropdown.name.push('<span class="placeholder">' + _dropdown.placeholder + '</span>');
_dropdown.$choseList.html(_dropdown.name.join(''));
_config.choice.call(_dropdown, event);
},
del: function (event) {
var _dropdown = this;
var _config = _dropdown.config;
var $target = $(event.target);
var id = $target.data('id');
// 2017-03-23 15:58:50 测试
// 10000条数据测试删除耗时 ~3ms
$.each(_dropdown.name, function (key, value) {
if (value.indexOf('data-id="' + id + '"') !== -1) {
_dropdown.name.splice(key, 1);
return false;
}
});
$.each(_dropdown.config.data, function (key, item) {
if ('' + item.id == '' + id) {
item.selected = false;
return false;
}
});
_dropdown.selectAmount--;
_dropdown.$el.find('[data-value="' + id + '"]').removeClass('dropdown-chose');
_dropdown.$el.find('[value="' + id + '"]').prop('selected', false).removeAttr('selected');
$target.closest('.dropdown-selected').remove();
_config.choice.call(_dropdown, event);
return false;
},
clearAll: function (event) {
var _dropdown = this;
var _config = _dropdown.config;
event && event.preventDefault();
console.log(this)
this.$choseList.find('.del').each(function (index, el) {
$(el).trigger('click');
});
if (_config.minCount > 0) {
minItemsAlert.call(_dropdown);
}
this.$el.find('.dropdown-display').removeAttr('title');
return false;
}
};
function Dropdown(options, el) {
this.$el = $(el);
this.$select = this.$el.find('select');
this.placeholder = this.$select.attr('placeholder');
this.config = options;
this.name = [];
this.isSingleSelect = !this.$select.prop('multiple');
this.selectAmount = 0;
this.itemLimitAlertTimer = null;
this.isLabelMode = this.config.multipleMode === 'label';
this.init();
}
Dropdown.prototype = {
init: function () {
var _this = this;
var _config = _this.config;
var $el = _this.$el;
_this.$select.hide();
// 判断dropdown是否单选是否token模式
$el.addClass(_this.isSingleSelect ? 'dropdown-single' : _this.isLabelMode ? 'dropdown-multiple-label' : 'dropdown-multiple');
if (_config.data.length === 0) {
_config.data = selectToObject(_this.$select);
}
var processResult = objectToSelect.call(_this, _config.data);
_this.name = processResult[1];
_this.selectAmount = processResult[2];
_this.$select.html(processResult[0]);
_this.renderSelect();
// disabled权重高于readonly
_this.changeStatus(_config.disabled ? 'disabled' : _config.readonly ? 'readonly' : false);
_this.config.init();
},
// 渲染 select 为 dropdown
renderSelect: function (isUpdate, isCover) {
var _this = this;
var $el = _this.$el;
var $select = _this.$select;
var elemLi = selectToDiv($select.prop('outerHTML'));
var template;
if (isUpdate) {
$el.find('ul')[isCover ? 'html' : 'append'](elemLi);
} else {
template = createTemplate.call(_this).replace('{{ul}}', '<ul>' + elemLi + '</ul>');
$el.append(template).find('ul').removeAttr('style class');
}
if (isCover) {
_this.name = [];
_this.$el.find('.dropdown-selected').remove();
_this.$select.val('');
}
_this.$choseList = $el.find('.dropdown-chose-list');
if (!_this.isLabelMode) {
_this.$choseList.html($('<span class="placeholder"></span>').text(_this.placeholder));
}
_this.$choseList.prepend(_this.name ? _this.name.join('') : []);
},
bindEvent: function () {
var _this = this;
var $el = _this.$el;
var openHandle = isSafari ? EVENT_SPACE.click : EVENT_SPACE.focus;
$el.on(EVENT_SPACE.click, function (event) {
event.stopPropagation();
});
$el.on(EVENT_SPACE.click, '.del', $.proxy(action.del, _this));
// show
if (_this.isLabelMode) {
$el.on(EVENT_SPACE.click, '.dropdown-display-label', function () {
$el.find('input').focus();
});
if (_this.config.searchable) {
$el.on(EVENT_SPACE.focus, 'input', $.proxy(action.show, _this));
} else {
$el.on(EVENT_SPACE.click, $.proxy(action.show, _this));
}
$el.on(EVENT_SPACE.keydown, 'input', function (event) {
if (event.keyCode === 8 && this.value === '' && _this.name.length) {
$el.find('.del').eq(-1).trigger('click');
}
});
} else {
$el.on(openHandle, '.dropdown-display', $.proxy(action.show, _this));
$el.on(openHandle, '.dropdown-clear-all', $.proxy(action.clearAll, _this));
}
// 搜索
$el.on(EVENT_SPACE.keyup, 'input', $.proxy(action.search, _this));
// 按下enter键设置token
$el.on(EVENT_SPACE.keyup, function (event) {
var keyCode = event.keyCode;
var KC = KEY_CODE;
if (keyCode === KC.enter) {
$.proxy(_this.isSingleSelect ? action.singleChoose : action.multiChoose, _this, event)();
}
});
// 按下上下键切换token
$el.on(EVENT_SPACE.keydown, $.proxy(action.control, _this));
$el.on(EVENT_SPACE.click, 'li[tabindex]', $.proxy(_this.isSingleSelect ? action.singleChoose : action.multiChoose, _this));
},
unbindEvent: function () {
var _this = this;
var $el = _this.$el;
var openHandle = isSafari ? EVENT_SPACE.click : EVENT_SPACE.focus;
$el.off(EVENT_SPACE.click);
$el.off(EVENT_SPACE.click, '.del');
// show
if (_this.isLabelMode) {
$el.off(EVENT_SPACE.click, '.dropdown-display-label');
$el.off(EVENT_SPACE.focus, 'input');
$el.off(EVENT_SPACE.keydown, 'input');
} else {
$el.off(openHandle, '.dropdown-display');
$el.off(openHandle, '.dropdown-clear-all');
}
// 搜索
$el.off(EVENT_SPACE.keyup, 'input');
// 按下enter键设置token
$el.off(EVENT_SPACE.keyup);
// 按下上下键切换token
$el.off(EVENT_SPACE.keydown);
$el.off(EVENT_SPACE.click, '[tabindex]');
},
changeStatus: function (status) {
var _this = this;
if (status === 'readonly') {
_this.unbindEvent();
} else if (status === 'disabled') {
_this.$select.prop('disabled', true);
_this.unbindEvent();
} else {
_this.$select.prop('disabled', false);
_this.bindEvent();
}
},
update: function (data, isCover) {
var _this = this;
var _config = _this.config;
var $el = _this.$el;
var _isCover = isCover || false;
if (Object.prototype.toString.call(data) !== '[object Array]') {
return;
}
_config.data = _isCover ? data.slice(0) : _config.data.concat(data);
var processResult = objectToSelect.call(_this, _config.data);
_this.name = processResult[1];
_this.selectAmount = processResult[2];
_this.$select.html(processResult[0]);
_this.renderSelect(true, _isCover);
},
destroy: function () {
this.unbindEvent();
this.$el.children().not('select').remove();
this.$el.removeClass('dropdown-single dropdown-multiple-label dropdown-multiple');
this.$select.show();
},
choose: function (values, status) {
var valArr = Object.prototype.toString.call(values) === '[object Array]' ? values : [values];
var _this = this;
var _status = status !== void 0 ? !!status : true
$.each(valArr, function (index, value) {
var $target = _this.$el.find('[data-value="' + value + '"]');
var targetStatus = $target.hasClass('dropdown-chose');
if (targetStatus !== _status) {
$target.trigger(EVENT_SPACE.click, status || true)
}
});
},
reset: function () {
action.clearAll.call(this)
}
};
$(document).on('click.dropdown', function () {
$('.dropdown-single,.dropdown-multiple,.dropdown-multiple-label').removeClass('active');
});
$.fn.dropdown = function (options) {
this.each(function (index, el) {
$(el).data('dropdown', new Dropdown($.extend(true, {}, settings, options), el));
});
return this;
}
})(jQuery);

View File

@@ -0,0 +1 @@
"use strict";function CheckBoxCustom(e){const[t,n]=useState(e.meta.inline_featured_image),{meta:o,updateInlineFeaturedSvg:a}=e;return createElement(wp.components.CheckboxControl,{label:"Render this SVG inline (Advanced)",checked:t,onChange:e=>{n(e),a(e,o)},__nextHasNoMarginBottom:!0})}function wrapPostFeaturedImage(e){return function(t){return createElement(Fragment,{},"",createElement(e,t),createElement(composedCheckBox))}}const{createElement:createElement,Fragment:Fragment,useState:useState}=wp.element,{withSelect:withSelect,withDispatch:withDispatch}=wp.data,{compose:compose}=wp.compose,composedCheckBox=compose([withSelect((e=>{const t=undefined,n=undefined;return{meta:{...e("core/editor").getCurrentPostAttribute("meta"),...e("core/editor").getEditedPostAttribute("meta")}}})),withDispatch((e=>({updateInlineFeaturedSvg(t,n){n={...n,inline_featured_image:t},e("core/editor").editPost({meta:n})}})))])(CheckBoxCustom);wp.hooks.addFilter("editor.PostFeaturedImage","bodhi-svgs-featured-image/render-inline-image-checkbox",wrapPostFeaturedImage);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
jQuery(document).ready((function($){function t(t){const s=t.hasClass(i),r=t.parent().hasClass(i),n=t.closest("."+i).length>0;if(("true"===ForceInlineSVGActive||s||n)&&(!svgSettings.skipNested||s||r||!n)){var a=t.attr("id"),o=t.attr("class"),c=t.attr("src");c.endsWith("svg")&&$.get(c,(function(i){var s=$(i).find("svg"),r=s.attr("id");void 0===a?void 0===r?(a="svg-replaced-"+e,s=s.attr("id",a)):a=r:s=s.attr("id",a),void 0!==o&&(s=s.attr("class",o+" replaced-svg svg-replaced-"+e)),s=s.removeAttr("xmlns:a"),"on"===frontSanitizationEnabled&&""!=s[0].outerHTML&&(s=DOMPurify.sanitize(s[0].outerHTML)),t.replaceWith(s),e++,$(document).trigger("svg.loaded",[a])}),"xml").fail((function(){}))}}let e=0,i;(bodhisvgsInlineSupport=function(){"true"===ForceInlineSVGActive&&jQuery("img").each((function(){void 0!==jQuery(this).attr("src")&&!1!==jQuery(this).attr("src")&&jQuery(this).attr("src").match(/\.(svg)/)&&(jQuery(this).hasClass(cssTarget.ForceInlineSVG)||jQuery(this).addClass(cssTarget.ForceInlineSVG))})),String.prototype.endsWith||(String.prototype.endsWith=function(t,e){var i=this.toString();("number"!=typeof e||!isFinite(e)||Math.floor(e)!==e||e>i.length)&&(e=i.length),e-=t.length;var s=i.lastIndexOf(t,e);return-1!==s&&s===e}),String.prototype.endsWith=function(t){var e=this.length-t.length;return e>=0&&this.lastIndexOf(t)===e},i="true"===ForceInlineSVGActive?"img."!==cssTarget.Bodhi?cssTarget.ForceInlineSVG:"style-svg":"img."!==cssTarget.Bodhi?cssTarget.Bodhi:"style-svg","string"==typeof i&&(i=i.replace("img.",""),$("."+i).each((function(e){void 0!==$(this).attr("src")&&!1!==$(this).attr("src")?t($(this)):$(this).find("img").each((function(e){void 0!==$(this).attr("src")&&!1!==$(this).attr("src")&&t($(this))}))})))})()}));

View File

@@ -0,0 +1 @@
document.addEventListener("DOMContentLoaded",(function(e){function t(e){if("IMG"!==e.nodeName)return;const t=e.classList.contains(i),n=e.parentElement.classList.contains(i),r=null!==e.closest("."+i);if(("true"===ForceInlineSVGActive||t||r)&&(!svgSettings.skipNested||t||n||!r)){var o=e.id,a=e.className,c=e.src;if(c.endsWith("svg")){var l=new XMLHttpRequest;l.onreadystatechange=function(){if(4===l.readyState&&200===l.status){var t=l.responseText;let c;const d=undefined;var n=(new DOMParser).parseFromString(t,"text/html").getElementsByTagName("svg")[0],i=n.id;if(void 0===o||""===o?void 0===i||""===i?(o="svg-replaced-"+s,n.setAttribute("id",o)):o=i:n.setAttribute("id",o),void 0!==a&&""!==a&&n.setAttribute("class",a+" replaced-svg svg-replaced-"+s),n.removeAttribute("xmlns:a"),"on"===frontSanitizationEnabled&&""!==n.outerHTML){var r=DOMPurify.sanitize(n.outerHTML);e.outerHTML=r}else e.replaceWith(n);s++}else 4===l.readyState&&l.status},l.open("GET",c,!0),l.send(null)}}}function n(e){if(e.childNodes.length>0)for(var s=0;s<e.childNodes.length;s++){var i;if("IMG"===e.childNodes[s].nodeName)t(e.childNodes[s]);else n(e.childNodes[s])}}let s=0,i;(bodhisvgsInlineSupport=function(){if("true"===ForceInlineSVGActive)for(var e=document.getElementsByTagName("img"),s=0;s<e.length;s++)void 0!==e[s].src&&e[s].src.match(/\.(svg)/)&&(e[s].classList.contains(cssTarget.ForceInlineSVG)||e[s].classList.add(cssTarget.ForceInlineSVG));String.prototype.endsWith||(String.prototype.endsWith=function(e,t){var n=this.toString();("number"!=typeof t||!isFinite(t)||Math.floor(t)!==t||t>n.length)&&(t=n.length),t-=e.length;var s=n.lastIndexOf(e,t);return-1!==s&&s===t}),String.prototype.endsWith=function(e){var t=this.length-e.length;return t>=0&&this.lastIndexOf(e)===t},i="true"===ForceInlineSVGActive?"img."!==cssTarget.Bodhi?cssTarget.ForceInlineSVG:"style-svg":"img."!==cssTarget.Bodhi?cssTarget.Bodhi:"style-svg","string"==typeof i&&(i=i.replace("img.",""),document.querySelectorAll("."+i).forEach((function(e){"IMG"===e.nodeName?t(e):n(e)})))})()}));

View File

@@ -0,0 +1,168 @@
/* eslint-env browser */
/* global svgSettings, ForceInlineSVGActive, cssTarget, frontSanitizationEnabled, DOMPurify */
document.addEventListener("DOMContentLoaded", function(event) {
let bodhisvgsReplacements = 0;
let target;
// Function to replace the img tag with the SVG
function bodhisvgsReplace(img) {
// Ensure it's an image
if (img.nodeName !== 'IMG') {
return;
}
const hasTargetClass = img.classList.contains(target);
const parentHasTargetClass = img.parentElement.classList.contains(target);
const insideTargetContainer = img.closest('.' + target) !== null;
// First check if we should process at all
if (ForceInlineSVGActive !== 'true' && !hasTargetClass && !insideTargetContainer) {
return;
}
// If skip nested is enabled, only skip if:
// 1. Image doesn't have target class AND
// 2. Image's parent is not the target container but is inside one
if (svgSettings.skipNested && !hasTargetClass && !parentHasTargetClass && insideTargetContainer) {
return;
}
var imgID = img.id;
var imgClass = img.className;
var imgURL = img.src;
// Ensure the URL ends with .svg before proceeding
if (!imgURL.endsWith('svg')) {
return;
}
var xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
var data = xmlHttp.responseText;
// Parse the returned data to extract the SVG
let parser = new DOMParser();
const doc = parser.parseFromString(data, 'text/html');
// Get the SVG tag from the parsed data
var svg = doc.getElementsByTagName('svg')[0];
var svgID = svg.id;
// Add replaced image's ID to the new SVG if necessary
if (typeof imgID === 'undefined' || imgID === '') {
if (typeof svgID === 'undefined' || svgID === '') {
imgID = 'svg-replaced-' + bodhisvgsReplacements;
svg.setAttribute('id', imgID);
} else {
imgID = svgID;
}
} else {
svg.setAttribute('id', imgID);
}
// Add replaced image's classes to the new SVG
if (typeof imgClass !== 'undefined' && imgClass !== '') {
svg.setAttribute('class', imgClass + ' replaced-svg svg-replaced-' + bodhisvgsReplacements);
}
// Remove any invalid XML tags as per http://validator.w3.org
svg.removeAttribute('xmlns:a');
// If sanitization is enabled, sanitize the SVG code
if (frontSanitizationEnabled === 'on' && svg.outerHTML !== "") {
var sanitizedSVG = DOMPurify.sanitize(svg.outerHTML);
img.outerHTML = sanitizedSVG;
} else {
img.replaceWith(svg);
}
bodhisvgsReplacements++;
} else if (xmlHttp.readyState === 4 && xmlHttp.status !== 200) {
// Silently fail
}
};
xmlHttp.open("GET", imgURL, true);
xmlHttp.send(null);
}
// Function to iterate over nodes and replace images
function bodhisvgsIterator(node) {
if (node.childNodes.length > 0) {
for (var i = 0; i < node.childNodes.length; i++) {
if (node.childNodes[i].nodeName === 'IMG') {
var img = node.childNodes[i];
bodhisvgsReplace(img);
} else {
bodhisvgsIterator(node.childNodes[i]);
}
}
}
}
// Wrap in IIFE so that it can be called again later as bodhisvgsInlineSupport();
(bodhisvgsInlineSupport = function() {
// If force inline SVG option is active then add class
if (ForceInlineSVGActive === 'true') {
var allImages = document.getElementsByTagName('img');
for (var i = 0; i < allImages.length; i++) {
if (typeof allImages[i].src !== 'undefined') {
if (allImages[i].src.match(/\.(svg)/)) {
if (!allImages[i].classList.contains(cssTarget.ForceInlineSVG)) {
allImages[i].classList.add(cssTarget.ForceInlineSVG);
}
}
}
}
}
// Polyfill to support all older browsers
if (!String.prototype.endsWith) {
String.prototype.endsWith = function(searchString, position) {
var subjectString = this.toString();
if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
position = subjectString.length;
}
position -= searchString.length;
var lastIndex = subjectString.lastIndexOf(searchString, position);
return lastIndex !== -1 && lastIndex === position;
};
}
// Another snippet to support IE11
String.prototype.endsWith = function(pattern) {
var d = this.length - pattern.length;
return d >= 0 && this.lastIndexOf(pattern) === d;
};
// Set target before we use it
if (ForceInlineSVGActive === 'true') {
target = cssTarget.Bodhi !== 'img.' ? cssTarget.ForceInlineSVG : 'style-svg';
} else {
target = cssTarget.Bodhi !== 'img.' ? cssTarget.Bodhi : 'style-svg';
}
// Ensure target is a string before applying replace method
if (typeof target === 'string') {
target = target.replace("img.", "");
} else {
return;
}
// Replace images with SVGs based on the target class
document.querySelectorAll('.' + target).forEach(function(element) {
if (element.nodeName === 'IMG') {
bodhisvgsReplace(element);
} else {
bodhisvgsIterator(element);
}
});
})(); // Execute immediately
});

View File

@@ -0,0 +1,166 @@
/* eslint-env jquery */
/* global svgSettings, ForceInlineSVGActive, cssTarget, frontSanitizationEnabled, DOMPurify, jQuery */
jQuery(document).ready(function ($) {
let bodhisvgsReplacements = 0;
let target;
// Function to replace the img tag with the SVG
function bodhisvgsReplace(img) {
const hasTargetClass = img.hasClass(target);
const parentHasTargetClass = img.parent().hasClass(target);
const insideTargetContainer = img.closest('.' + target).length > 0;
// First check if we should process at all
if (ForceInlineSVGActive !== 'true' && !hasTargetClass && !insideTargetContainer) {
return;
}
// If skip nested is enabled, only skip if:
// 1. Image doesn't have target class AND
// 2. Image's parent is not the target container but is inside one
if (svgSettings.skipNested && !hasTargetClass && !parentHasTargetClass && insideTargetContainer) {
return;
}
var imgID = img.attr('id');
var imgClass = img.attr('class');
var imgURL = img.attr('src');
// Ensure the URL ends with .svg before proceeding
if (!imgURL.endsWith('svg')) {
return;
}
// Use jQuery's get method to fetch the SVG
$.get(imgURL, function(data) {
// Get the SVG tag, ignore the rest
var $svg = $(data).find('svg');
var svgID = $svg.attr('id');
// Add replaced image's ID to the new SVG if necessary
if (typeof imgID === 'undefined') {
if (typeof svgID === 'undefined') {
imgID = 'svg-replaced-' + bodhisvgsReplacements;
$svg = $svg.attr('id', imgID);
} else {
imgID = svgID;
}
} else {
$svg = $svg.attr('id', imgID);
}
// Add replaced image's classes to the new SVG
if (typeof imgClass !== 'undefined') {
$svg = $svg.attr('class', imgClass + ' replaced-svg svg-replaced-' + bodhisvgsReplacements);
}
// Remove any invalid XML tags as per http://validator.w3.org
$svg = $svg.removeAttr('xmlns:a');
// If sanitization is enabled, sanitize the SVG code
if (frontSanitizationEnabled === 'on' && $svg[0]['outerHTML'] != "") {
$svg = DOMPurify.sanitize($svg[0]['outerHTML']);
}
// Replace image with new SVG
img.replaceWith($svg);
// Increment the replacements counter
bodhisvgsReplacements++;
// Trigger custom event after SVG is loaded
$(document).trigger('svg.loaded', [imgID]);
}, 'xml').fail(function() {
// Silently fail
});
}
// Wrap in IIFE so that it can be called again later as bodhisvgsInlineSupport();
(bodhisvgsInlineSupport = function () {
// If force inline SVG option is active then add class
if (ForceInlineSVGActive === 'true') {
// Find all SVG inside img and add class if it hasn't got it
jQuery('img').each(function () {
// Check if the SRC attribute is present at all
if (typeof jQuery(this).attr('src') !== typeof undefined && jQuery(this).attr('src') !== false) {
// Pick only those with the extension we want
if (jQuery(this).attr('src').match(/\.(svg)/)) {
// Add our class name
if (!jQuery(this).hasClass(cssTarget.ForceInlineSVG)) {
jQuery(this).addClass(cssTarget.ForceInlineSVG);
}
}
}
});
}
// Polyfill to support all older browsers
// delete when not needed in the future
if (!String.prototype.endsWith) {
String.prototype.endsWith = function (searchString, position) {
var subjectString = this.toString();
if (typeof position !== 'number' || !isFinite(position) || Math.floor(position) !== position || position > subjectString.length) {
position = subjectString.length;
}
position -= searchString.length;
var lastIndex = subjectString.lastIndexOf(searchString, position);
return lastIndex !== -1 && lastIndex === position;
};
} // end polyfill
// Another snippet to support IE11
String.prototype.endsWith = function (pattern) {
var d = this.length - pattern.length;
return d >= 0 && this.lastIndexOf(pattern) === d;
};
// End snippet to support IE11
// Set target before we use it
if (ForceInlineSVGActive === 'true') {
target = cssTarget.Bodhi !== 'img.' ? cssTarget.ForceInlineSVG : 'style-svg';
} else {
target = cssTarget.Bodhi !== 'img.' ? cssTarget.Bodhi : 'style-svg';
}
// Ensure target is a string before applying replace method
if (typeof target === 'string') {
target = target.replace("img.", "");
} else {
return;
}
// Replace images with SVGs based on the target class
$('.' + target).each(function (index) {
// If image then send for replacement
if (typeof $(this).attr('src') !== typeof undefined && $(this).attr('src') !== false) {
bodhisvgsReplace($(this));
} else {
// Look for SVG children and send for replacement
$(this).find("img").each(function (i) {
if (typeof $(this).attr('src') !== typeof undefined && $(this).attr('src') !== false) {
bodhisvgsReplace($(this));
}
});
}
});
})(); // Execute immediately
});