truncate.lua -- html truncate for luvit lang.
-- | |
-- Created by: Cyril. | |
-- Created at: 15/6/25 上午12:40 | |
-- Email: houshoushuai@gmail.com | |
-- | |
local string = require("string") | |
local find = string.find | |
_G.indexOf = function(t, x) | |
if type(t) == 'string' then | |
return find(t, x, true) | |
end | |
for k, v in pairs(t) do | |
if v == x then | |
return k | |
end | |
end | |
return nil | |
end | |
_G.lastIndexOf = function(t, x) | |
local idx | |
if type(t) == "string" then | |
local i=t:match(".*"..x.."()") | |
if i==nil then return nil else return i-1 end | |
end | |
for k, v in pairs(t) do | |
if v == x then | |
idx = k | |
end | |
end | |
return idx | |
end | |
_G.pop = function(t) | |
return table.remove(t) | |
end | |
_G.truncate = function(html, option) | |
option = option or {} | |
local tolerance = option.tolerance | |
local image | |
if type(option.image) == 'boolean' then | |
image = option.image | |
else | |
image = true | |
end | |
local maxInt = option.max or 250 | |
local ellipsis = option.ellipsis or "... ..." | |
local shouldAddEllipsis = false | |
local tagPartten = "<(%/?)([A-Za-z0-9]+)[^%>]*>" | |
local escapeTags = {"area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"} | |
local startTagArray = {} | |
html = html:gsub(tagPartten, function(a, b) | |
if b == "script" then | |
return "" | |
end | |
if not(image) then | |
if b == "img" or b == "figure" then | |
return "" | |
end | |
end | |
end) | |
local htmlLen = #html | |
local i = 0 | |
local bareHtmlLen = 0 | |
while i <= htmlLen and maxInt - bareHtmlLen > 0 do | |
local afterfix = html:sub(i+1, htmlLen) or "" | |
local start, stop = afterfix:find(tagPartten) | |
if not(start or stop) then | |
bareHtmlLen = maxInt | |
break | |
end | |
local bareHtml = (afterfix:sub(0, start-1) or ""):gsub(tagPartten, function()return "" end) | |
local _, utfCount = string.gsub(bareHtml, "[^\128-\193]", "") | |
if maxInt < bareHtmlLen + utfCount then | |
string.gsub(bareHtml, "([%z\1-\127\194-\244][\128-\191]*)", function(a) | |
if bareHtmlLen < maxInt then | |
bareHtmlLen = bareHtmlLen + 1 | |
if #a == 3 then | |
i = i+3 | |
else | |
i = i+1 | |
end | |
end | |
end) | |
shouldAddEllipsis = true | |
else | |
i = stop + i | |
bareHtmlLen = bareHtmlLen + utfCount | |
end | |
end | |
html = html:sub(0, i) | |
local bare = (html or ""):gsub(tagPartten, function(a, b) | |
if a == "/" then -- End Tag | |
if indexOf(escapeTags, b) then | |
else | |
if startTagArray[#startTagArray] == b then | |
_G.pop(startTagArray) | |
else | |
if tolerance then | |
-- fault-tolerance | |
local lastIndex = lastIndexOf(startTagArray, b) | |
if #startTagArray - lastIndex <= 1 then | |
_G.pop(startTagArray) | |
end | |
end | |
end | |
end | |
else -- Start Tag | |
if indexOf(escapeTags, b) then | |
else | |
table.insert(startTagArray, b) | |
end | |
end | |
return "" | |
end) | |
-- fix end tag | |
local endTagString = "" | |
for _, v in pairs(startTagArray) do | |
endTagString = "</".. v .. ">" .. endTagString | |
end | |
if #startTagArray and shouldAddEllipsis then | |
html = html .. " " ..ellipsis | |
end | |
html = html .. endTagString | |
return html | |
end | |
-- usage truncate("<p>Hello world <a href="#">link... ...</p></a>", {image = true, ellipsis = "<br/> Read More"}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment