多级列表首字母大写(JS,JQUERY)
Uppercase first letters in multi-level lists (JS, JQUERY)
我正在尝试为我们使用的 CKEditor 做一些自定义大写工具。但即使没有 CKEditor,这似乎也是一个有趣的案例。
现在我想要一些好的解决方案,只选择 LEVEL 1 元素并在不触及子级别 HTML 结构的情况下将所有包含的 TEXT 大写,然后在不触及的情况下将 LEVEL 2 大写1级。
我已经尝试了许多具有许多指向组合的排除方法。
我们不能使用 类 和 id's.
似乎当我们使用大写函数时,我们从它返回的字符串(内容文本),当我们将它们插入代码时,正在弄乱 HTML 结构。
当前目标:不破坏嵌套结构,将它们全部连接起来并将它们移动到父元素。
当前进度:
- 我们只能大写 LEVEL 1 元素 - 但有副作用:
加入子级别并将它们添加到 LEVEL 1 父元素。
- 我们只能将嵌套的 LEVEL 2 元素大写。
- 我们可以将 LEVEL 1 和 LEVEL 2 元素一起大写 - 但是
副作用:加入子级别并将它们添加到级别 1 父级
元素.
我有一些想法,但也许我需要重新审视这个问题。
现在似乎是提出重要问题的时候了:
是否只需要更具体的方式来选择元素,更好的方式来替换文本,或者它是否适合完全不同和更复杂的方法?
我已经用当前版本的代码和示例数据准备了一个测试环境 - 现在有两个活动函数来显示对 LEVEL 1 和 LEVEL 2 元素的操作:
https://codepen.io/adalbertus/pen/jxOGYV
HTML:
<p>FIRST LIST after header- we want it to change:</p>
<h2>Some header to target proper lists</h2>
<ul>
<li>text 1 - Level 1</li>
<li>text 2 - Level 1
<ul>
<li>text 1 - Level 2</li>
<li>text 2 - Level 2</li>
</ul>
</li>
<li>text 3 - Level 1</li>
<li>text 4 - Level 1</li>
<p>SECOND LIST after header - we don't want it to change:</p>
<ul>
<li>text 1 - Level 1</li>
<li>text 2 - Level 1
<ul>
<li>text 1 - Level 2</li>
<li>text 2 - Level 2</li>
</ul>
</li>
<li>text 3 - Level 1</li>
<li>text 4 - Level 1</li>
JS:
$("#capitalize").click(function (){
function capitalizeFirstLetter(lists){
return lists.charAt(0).toUpperCase() + lists.slice(1);}
//Condition to target only lists directly after Headers is not necessary, but let say it will be there.
//So this is the reason to exist such variables like below - to easily change this in the future:
var h2Andh3TagsToTargetLiElements = $("body").find("h2,h3");
var listsToCapitalize = $("body").find("ul");
var listsAfterHeaders = $(h2Andh3TagsToTargetLiElements).next(listsToCapitalize).find("li");
var nestedListsToCapitalize = $("body").find("ul > li > ul , ul > li > ol");
var nestedListsAfterHeaders =$(h2Andh3TagsToTargetLiElements).next(nestedListsToCapitalize).contents().find("li");
if (listsAfterHeaders.length) {
//Operation just for nested lists - just for tests
$(nestedListsAfterHeaders).each(function () {
var nested = $(this).text();
var nestedtocap = capitalizeFirstLetter(nested);
$(this).text(nestedtocap);
});
$(listsAfterHeaders).each(function () {
var totxt = $(this).text();
var tocap = capitalizeFirstLetter(totxt);
$(this).text(tocap);
});
}
});
如果我正确理解了你的问题,这可以更简单地完成。
$("#capitalize").click(function() {
function capitalizeFirstLetter(lists) {
return lists.charAt(0).toUpperCase() + lists.slice(1);
}
$("body > ul > li").each(function(idx, el) {
$(el).html($(el).html().charAt(0).toUpperCase() + $(el).html().slice(1));
});
});
基本上,只有 select 个遵循 body > ul > li
层次结构的项目。
我不知道我的理解是否正确,但您正在寻找对嵌套元素的一些控制。这是一个没有 jquery 或可能有帮助的 querySelectors 的普通 js 解决方案:
//assuming that we have an ul variable where li descendants always
have a text node as the first child:
var ul = document.createElement("ul");
ul.innerHTML = `<li>text 1 - Level 1</li>
<li>text 2 - Level 1
<ul>
<li>text 1 - Level 2</li>
<li>text 2 - Level 2</li>
</ul>
</li>
<li>text 3 - Level 1</li>
<li>text 4 - Level 1</li>`;
/*create a function to capitalize the first letter,
I'm using regex incase you want to do different manipulations other than
capitalizing.Below, Node is a ul element, gets the immediate
li elements and performs replace*/
function capitalize(node){
Array.prototype.slice.call(node.children)
.filter(function(d,i){return d.tagName === "LI" })
.forEach(function(d,i){
d.firstChild.textContent
= d.firstChild.textContent
.replace(/^[A-Z]/gi,function(m,o,s){return m.toUpperCase();})})
}
要获得 'levels',这里有一个函数 returns 一个包含该级别的 ul 节点的数组:
function getLevels(level,parent){
var nodes = [parent],
children = undefined;
for (var i = 0;i<level;++i){
nodes = nodes.map(function(d,i){
return d
&& d.nodeType
&& (children = Array.prototype.slice.call(d.children))
.filter(function(d,i){return d.tagName === "UL"})
}).reduce(function(ac,d,i){
return ac.concat(d);
},[])
if(!nodes.length && i !== level - 1){
nodes = children;
}
}
return nodes;
}
例如,对于 ul 变量:
getLevels(0,ul);//return the parent itself [ul]
getLevels(1,ul);//return empty [] since all immediate children are li
getLevels(2,ul);//return [ul] containing ul inside the second li
现在,要将第 2 级 ul 的 li 标签大写:
getLevels(2,ul).forEach(function(d,i){capitalize(d)})
你最终得到:
<li>text 1 - Level 1</li>
<li>text 2 - Level 1
<ul>
<li>Text 1 - Level 2</li>
<li>Text 2 - Level 2</li>
</ul>
</li>
<li>text 3 - Level 1</li>
<li>text 4 - Level 1</li>
我是临时写的,所以边缘情况下的错误检查可能需要一两次编辑。
我正在尝试为我们使用的 CKEditor 做一些自定义大写工具。但即使没有 CKEditor,这似乎也是一个有趣的案例。
现在我想要一些好的解决方案,只选择 LEVEL 1 元素并在不触及子级别 HTML 结构的情况下将所有包含的 TEXT 大写,然后在不触及的情况下将 LEVEL 2 大写1级。 我已经尝试了许多具有许多指向组合的排除方法。 我们不能使用 类 和 id's.
似乎当我们使用大写函数时,我们从它返回的字符串(内容文本),当我们将它们插入代码时,正在弄乱 HTML 结构。
当前目标:不破坏嵌套结构,将它们全部连接起来并将它们移动到父元素。
当前进度:
- 我们只能大写 LEVEL 1 元素 - 但有副作用: 加入子级别并将它们添加到 LEVEL 1 父元素。
- 我们只能将嵌套的 LEVEL 2 元素大写。
- 我们可以将 LEVEL 1 和 LEVEL 2 元素一起大写 - 但是
副作用:加入子级别并将它们添加到级别 1 父级 元素.
我有一些想法,但也许我需要重新审视这个问题。
现在似乎是提出重要问题的时候了: 是否只需要更具体的方式来选择元素,更好的方式来替换文本,或者它是否适合完全不同和更复杂的方法?
我已经用当前版本的代码和示例数据准备了一个测试环境 - 现在有两个活动函数来显示对 LEVEL 1 和 LEVEL 2 元素的操作:
https://codepen.io/adalbertus/pen/jxOGYV
HTML:
<p>FIRST LIST after header- we want it to change:</p>
<h2>Some header to target proper lists</h2>
<ul>
<li>text 1 - Level 1</li>
<li>text 2 - Level 1
<ul>
<li>text 1 - Level 2</li>
<li>text 2 - Level 2</li>
</ul>
</li>
<li>text 3 - Level 1</li>
<li>text 4 - Level 1</li>
<p>SECOND LIST after header - we don't want it to change:</p>
<ul>
<li>text 1 - Level 1</li>
<li>text 2 - Level 1
<ul>
<li>text 1 - Level 2</li>
<li>text 2 - Level 2</li>
</ul>
</li>
<li>text 3 - Level 1</li>
<li>text 4 - Level 1</li>
JS:
$("#capitalize").click(function (){
function capitalizeFirstLetter(lists){
return lists.charAt(0).toUpperCase() + lists.slice(1);}
//Condition to target only lists directly after Headers is not necessary, but let say it will be there.
//So this is the reason to exist such variables like below - to easily change this in the future:
var h2Andh3TagsToTargetLiElements = $("body").find("h2,h3");
var listsToCapitalize = $("body").find("ul");
var listsAfterHeaders = $(h2Andh3TagsToTargetLiElements).next(listsToCapitalize).find("li");
var nestedListsToCapitalize = $("body").find("ul > li > ul , ul > li > ol");
var nestedListsAfterHeaders =$(h2Andh3TagsToTargetLiElements).next(nestedListsToCapitalize).contents().find("li");
if (listsAfterHeaders.length) {
//Operation just for nested lists - just for tests
$(nestedListsAfterHeaders).each(function () {
var nested = $(this).text();
var nestedtocap = capitalizeFirstLetter(nested);
$(this).text(nestedtocap);
});
$(listsAfterHeaders).each(function () {
var totxt = $(this).text();
var tocap = capitalizeFirstLetter(totxt);
$(this).text(tocap);
});
}
});
如果我正确理解了你的问题,这可以更简单地完成。
$("#capitalize").click(function() {
function capitalizeFirstLetter(lists) {
return lists.charAt(0).toUpperCase() + lists.slice(1);
}
$("body > ul > li").each(function(idx, el) {
$(el).html($(el).html().charAt(0).toUpperCase() + $(el).html().slice(1));
});
});
基本上,只有 select 个遵循 body > ul > li
层次结构的项目。
我不知道我的理解是否正确,但您正在寻找对嵌套元素的一些控制。这是一个没有 jquery 或可能有帮助的 querySelectors 的普通 js 解决方案:
//assuming that we have an ul variable where li descendants always
have a text node as the first child:
var ul = document.createElement("ul");
ul.innerHTML = `<li>text 1 - Level 1</li>
<li>text 2 - Level 1
<ul>
<li>text 1 - Level 2</li>
<li>text 2 - Level 2</li>
</ul>
</li>
<li>text 3 - Level 1</li>
<li>text 4 - Level 1</li>`;
/*create a function to capitalize the first letter,
I'm using regex incase you want to do different manipulations other than
capitalizing.Below, Node is a ul element, gets the immediate
li elements and performs replace*/
function capitalize(node){
Array.prototype.slice.call(node.children)
.filter(function(d,i){return d.tagName === "LI" })
.forEach(function(d,i){
d.firstChild.textContent
= d.firstChild.textContent
.replace(/^[A-Z]/gi,function(m,o,s){return m.toUpperCase();})})
}
要获得 'levels',这里有一个函数 returns 一个包含该级别的 ul 节点的数组:
function getLevels(level,parent){
var nodes = [parent],
children = undefined;
for (var i = 0;i<level;++i){
nodes = nodes.map(function(d,i){
return d
&& d.nodeType
&& (children = Array.prototype.slice.call(d.children))
.filter(function(d,i){return d.tagName === "UL"})
}).reduce(function(ac,d,i){
return ac.concat(d);
},[])
if(!nodes.length && i !== level - 1){
nodes = children;
}
}
return nodes;
}
例如,对于 ul 变量:
getLevels(0,ul);//return the parent itself [ul]
getLevels(1,ul);//return empty [] since all immediate children are li
getLevels(2,ul);//return [ul] containing ul inside the second li
现在,要将第 2 级 ul 的 li 标签大写:
getLevels(2,ul).forEach(function(d,i){capitalize(d)})
你最终得到:
<li>text 1 - Level 1</li>
<li>text 2 - Level 1
<ul>
<li>Text 1 - Level 2</li>
<li>Text 2 - Level 2</li>
</ul>
</li>
<li>text 3 - Level 1</li>
<li>text 4 - Level 1</li>
我是临时写的,所以边缘情况下的错误检查可能需要一两次编辑。