mirror of
https://github.com/citizenfx/cfx-server-data.git
synced 2025-12-12 06:14:09 +01:00
add playernames resource
This commit is contained in:
27
resources/[gameplay]/playernames/__resource.lua
Normal file
27
resources/[gameplay]/playernames/__resource.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
-- add scripts
|
||||
client_script 'playernames_api.lua'
|
||||
server_script 'playernames_api.lua'
|
||||
|
||||
client_script 'playernames_cl.lua'
|
||||
server_script 'playernames_sv.lua'
|
||||
|
||||
-- make exports
|
||||
local exportList = {
|
||||
'setComponentColor',
|
||||
'setComponentAlpha',
|
||||
'setComponentVisibility',
|
||||
'setWantedLevel',
|
||||
'setHealthBarColor',
|
||||
'setNameTemplate'
|
||||
}
|
||||
|
||||
exports(exportList)
|
||||
server_exports(exportList)
|
||||
|
||||
-- add files
|
||||
files {
|
||||
'template/template.lua'
|
||||
}
|
||||
|
||||
-- support the latest resource manifest
|
||||
resource_manifest_version '05cfa83c-a124-4cfa-a768-c24a5811d8f9'
|
||||
80
resources/[gameplay]/playernames/playernames_api.lua
Normal file
80
resources/[gameplay]/playernames/playernames_api.lua
Normal file
@@ -0,0 +1,80 @@
|
||||
local ids = {}
|
||||
|
||||
local function getTriggerFunction(key)
|
||||
return function(id, ...)
|
||||
-- if on the client, it's easy
|
||||
if not IsDuplicityVersion() then
|
||||
TriggerEvent('playernames:configure', GetPlayerServerId(id), key, ...)
|
||||
else
|
||||
-- if on the server, save configuration
|
||||
if not ids[id] then
|
||||
ids[id] = {}
|
||||
end
|
||||
|
||||
-- save the setting
|
||||
ids[id][key] = table.pack(...)
|
||||
|
||||
-- broadcast to clients
|
||||
TriggerClientEvent('playernames:configure', -1, id, key, ...)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if IsDuplicityVersion() then
|
||||
function reconfigure(source)
|
||||
for id, data in pairs(ids) do
|
||||
for key, args in pairs(data) do
|
||||
TriggerClientEvent('playernames:configure', source, id, key, table.unpack(args))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
AddEventHandler('playerDropped', function()
|
||||
ids[source] = nil
|
||||
end)
|
||||
end
|
||||
|
||||
setComponentColor = getTriggerFunction('setc')
|
||||
setComponentAlpha = getTriggerFunction('seta')
|
||||
setComponentVisibility = getTriggerFunction('tglc')
|
||||
setWantedLevel = getTriggerFunction('setw')
|
||||
setHealthBarColor = getTriggerFunction('sehc')
|
||||
setNameTemplate = getTriggerFunction('tpl')
|
||||
setName = getTriggerFunction('name')
|
||||
|
||||
if not io then
|
||||
io = { write = nil, open = nil }
|
||||
end
|
||||
|
||||
local template = load(LoadResourceFile(GetCurrentResourceName(), 'template/template.lua'))()
|
||||
|
||||
function formatPlayerNameTag(i, templateStr)
|
||||
--return ('%s <%d>'):format(GetPlayerName(i), GetPlayerServerId(i))
|
||||
local str = ''
|
||||
|
||||
template.print = function(txt)
|
||||
str = str .. txt
|
||||
end
|
||||
|
||||
local context = {
|
||||
name = GetPlayerName(i),
|
||||
i = i,
|
||||
global = _G
|
||||
}
|
||||
|
||||
if IsDuplicityVersion() then
|
||||
context.id = i
|
||||
else
|
||||
context.id = GetPlayerServerId(i)
|
||||
end
|
||||
|
||||
TriggerEvent('playernames:extendContext', i, function(k, v)
|
||||
context[k] = v
|
||||
end)
|
||||
|
||||
template.render(templateStr, context, nil, true)
|
||||
|
||||
template.print = print
|
||||
|
||||
return str
|
||||
end
|
||||
196
resources/[gameplay]/playernames/playernames_cl.lua
Normal file
196
resources/[gameplay]/playernames/playernames_cl.lua
Normal file
@@ -0,0 +1,196 @@
|
||||
local mpGamerTags = {}
|
||||
local mpGamerTagSettings = {}
|
||||
|
||||
local gtComponent = {
|
||||
GAMER_NAME = 0,
|
||||
CREW_TAG = 1,
|
||||
healthArmour = 2,
|
||||
BIG_TEXT = 3,
|
||||
AUDIO_ICON = 4,
|
||||
MP_USING_MENU = 5,
|
||||
MP_PASSIVE_MODE = 6,
|
||||
WANTED_STARS = 7,
|
||||
MP_DRIVER = 8,
|
||||
MP_CO_DRIVER = 9,
|
||||
MP_TAGGED = 10,
|
||||
GAMER_NAME_NEARBY = 11,
|
||||
ARROW = 12,
|
||||
MP_PACKAGES = 13,
|
||||
INV_IF_PED_FOLLOWING = 14,
|
||||
RANK_TEXT = 15,
|
||||
MP_TYPING = 16
|
||||
}
|
||||
|
||||
local function makeSettings()
|
||||
return {
|
||||
alphas = {},
|
||||
colors = {},
|
||||
healthColor = false,
|
||||
toggles = {},
|
||||
wantedLevel = false
|
||||
}
|
||||
end
|
||||
|
||||
local templateStr
|
||||
|
||||
function updatePlayerNames()
|
||||
-- re-run this function the next frame
|
||||
SetTimeout(0, updatePlayerNames)
|
||||
|
||||
-- return if no template string is set
|
||||
if not templateStr then
|
||||
return
|
||||
end
|
||||
|
||||
-- get local coordinates to compare to
|
||||
local localCoords = GetEntityCoords(PlayerPedId())
|
||||
|
||||
-- for each valid player index
|
||||
for i = 0, 255 do
|
||||
-- if the player exists
|
||||
if NetworkIsPlayerActive(i) and i ~= PlayerId() then
|
||||
-- get their ped
|
||||
local ped = GetPlayerPed(i)
|
||||
local pedCoords = GetEntityCoords(ped)
|
||||
|
||||
-- make a new settings list if needed
|
||||
if not mpGamerTagSettings[i] then
|
||||
mpGamerTagSettings[i] = makeSettings()
|
||||
end
|
||||
|
||||
-- check the ped, because changing player models may recreate the ped
|
||||
-- also check gamer tag activity in case the game deleted the gamer tag
|
||||
if not mpGamerTags[i] or mpGamerTags[i].ped ~= ped or not IsMpGamerTagActive(mpGamerTags[i].tag) then
|
||||
local nameTag = formatPlayerNameTag(i, templateStr)
|
||||
|
||||
-- remove any existing tag
|
||||
if mpGamerTags[i] then
|
||||
RemoveMpGamerTag(mpGamerTags[i].tag)
|
||||
end
|
||||
|
||||
-- store the new tag
|
||||
mpGamerTags[i] = {
|
||||
tag = CreateMpGamerTag(GetPlayerPed(i), nameTag, false, false, '', 0),
|
||||
ped = ped
|
||||
}
|
||||
end
|
||||
|
||||
-- store the tag in a local
|
||||
local tag = mpGamerTags[i].tag
|
||||
|
||||
-- should the player be renamed? this is set by events
|
||||
if mpGamerTagSettings[i].rename then
|
||||
SetMpGamerTagName(tag, formatPlayerNameTag(i, templateStr))
|
||||
mpGamerTagSettings[i].rename = nil
|
||||
end
|
||||
|
||||
-- check distance
|
||||
local distance = #(pedCoords - localCoords)
|
||||
|
||||
-- show/hide based on nearbyness/line-of-sight
|
||||
-- nearby checks are primarily to prevent a lot of LOS checks
|
||||
if distance < 250 and HasEntityClearLosToEntity(PlayerPedId(), ped, 17) then
|
||||
SetMpGamerTagVisibility(tag, gtComponent.GAMER_NAME, true)
|
||||
SetMpGamerTagVisibility(tag, gtComponent.healthArmour, IsPlayerTargettingEntity(PlayerId(), ped))
|
||||
SetMpGamerTagVisibility(tag, gtComponent.AUDIO_ICON, NetworkIsPlayerTalking(i))
|
||||
|
||||
SetMpGamerTagAlpha(tag, gtComponent.AUDIO_ICON, 255)
|
||||
SetMpGamerTagAlpha(tag, gtComponent.healthArmour, 255)
|
||||
|
||||
-- override settings
|
||||
local settings = mpGamerTagSettings[i]
|
||||
|
||||
for k, v in pairs(settings.toggles) do
|
||||
SetMpGamerTagVisibility(tag, gtComponent[k], v)
|
||||
end
|
||||
|
||||
for k, v in pairs(settings.alphas) do
|
||||
SetMpGamerTagAlpha(tag, gtComponent[k], v)
|
||||
end
|
||||
|
||||
for k, v in pairs(settings.colors) do
|
||||
SetMpGamerTagColour(tag, gtComponent[k], v)
|
||||
end
|
||||
|
||||
if settings.wantedLevel then
|
||||
SetMpGamerTagWantedLevel(tag, settings.wantedLevel)
|
||||
end
|
||||
|
||||
if settings.healthColor then
|
||||
SetMpGamerTagHealthBarColour(tag, settings.healthColor)
|
||||
end
|
||||
else
|
||||
SetMpGamerTagVisibility(tag, gtComponent.GAMER_NAME, false)
|
||||
SetMpGamerTagVisibility(tag, gtComponent.healthArmour, false)
|
||||
SetMpGamerTagVisibility(tag, gtComponent.AUDIO_ICON, false)
|
||||
end
|
||||
elseif mpGamerTags[i] then
|
||||
RemoveMpGamerTag(mpGamerTags[i].tag)
|
||||
|
||||
mpGamerTags[i] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getSettings(id)
|
||||
local i = GetPlayerFromServerId(tonumber(id))
|
||||
|
||||
if not mpGamerTagSettings[i] then
|
||||
mpGamerTagSettings[i] = makeSettings()
|
||||
end
|
||||
|
||||
return mpGamerTagSettings[i]
|
||||
end
|
||||
|
||||
RegisterNetEvent('playernames:configure')
|
||||
|
||||
AddEventHandler('playernames:configure', function(id, key, ...)
|
||||
local args = table.pack(...)
|
||||
|
||||
if key == 'tglc' then
|
||||
getSettings(id).toggles[args[1]] = args[2]
|
||||
elseif key == 'seta' then
|
||||
getSettings(id).alphas[args[1]] = args[2]
|
||||
elseif key == 'setc' then
|
||||
getSettings(id).colors[args[1]] = args[2]
|
||||
elseif key == 'setw' then
|
||||
getSettings(id).wantedLevel = args[1]
|
||||
elseif key == 'sehc' then
|
||||
getSettings(id).healthColor = args[1]
|
||||
elseif key == 'rnme' then
|
||||
getSettings(id).rename = true
|
||||
elseif key == 'name' then
|
||||
print(id, 'id')
|
||||
print(getSettings(id))
|
||||
|
||||
getSettings(id).serverName = args[1]
|
||||
getSettings(id).rename = true
|
||||
elseif key == 'tpl' then
|
||||
for _, v in pairs(mpGamerTagSettings) do
|
||||
v.rename = true
|
||||
end
|
||||
|
||||
templateStr = args[1]
|
||||
end
|
||||
end)
|
||||
|
||||
AddEventHandler('playernames:extendContext', function(i, cb)
|
||||
print(getSettings(GetPlayerServerId(i)))
|
||||
|
||||
cb('serverName', getSettings(GetPlayerServerId(i)).serverName)
|
||||
end)
|
||||
|
||||
AddEventHandler('onResourceStop', function(name)
|
||||
if name == GetCurrentResourceName() then
|
||||
for _, v in pairs(mpGamerTags) do
|
||||
RemoveMpGamerTag(v.tag)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
SetTimeout(0, function()
|
||||
TriggerServerEvent('playernames:init')
|
||||
end)
|
||||
|
||||
-- run this function every frame
|
||||
SetTimeout(0, updatePlayerNames)
|
||||
36
resources/[gameplay]/playernames/playernames_sv.lua
Normal file
36
resources/[gameplay]/playernames/playernames_sv.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
local curTemplate
|
||||
local curTags = {}
|
||||
|
||||
local function detectUpdates()
|
||||
SetTimeout(500, detectUpdates)
|
||||
|
||||
local template = GetConvar('playerNames_template', '[{{id}}] {{name}}')
|
||||
|
||||
if curTemplate ~= template then
|
||||
setNameTemplate(-1, template)
|
||||
|
||||
curTemplate = template
|
||||
end
|
||||
|
||||
template = GetConvar('playerNames_svTemplate', '[{{id}}] {{name}}')
|
||||
|
||||
for _, v in ipairs(GetPlayers()) do
|
||||
local newTag = formatPlayerNameTag(v, template)
|
||||
|
||||
if newTag ~= curTags[v] then
|
||||
setName(v, newTag)
|
||||
|
||||
curTags[v] = newTag
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
RegisterNetEvent('playernames:init')
|
||||
AddEventHandler('playernames:init', function()
|
||||
reconfigure(source)
|
||||
end)
|
||||
|
||||
SetTimeout(500, detectUpdates)
|
||||
detectUpdates()
|
||||
27
resources/[gameplay]/playernames/template/LICENSE
Normal file
27
resources/[gameplay]/playernames/template/LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright (c) 2014 - 2017 Aapo Talvensaari
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the {organization} nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
478
resources/[gameplay]/playernames/template/template.lua
Normal file
478
resources/[gameplay]/playernames/template/template.lua
Normal file
@@ -0,0 +1,478 @@
|
||||
local setmetatable = setmetatable
|
||||
local loadstring = loadstring
|
||||
local loadchunk
|
||||
local tostring = tostring
|
||||
local setfenv = setfenv
|
||||
local require = require
|
||||
local capture
|
||||
local concat = table.concat
|
||||
local assert = assert
|
||||
local prefix
|
||||
local write = io.write
|
||||
local pcall = pcall
|
||||
local phase
|
||||
local open = io.open
|
||||
local load = load
|
||||
local type = type
|
||||
local dump = string.dump
|
||||
local find = string.find
|
||||
local gsub = string.gsub
|
||||
local byte = string.byte
|
||||
local null
|
||||
local sub = string.sub
|
||||
local ngx = ngx
|
||||
local jit = jit
|
||||
local var
|
||||
|
||||
local _VERSION = _VERSION
|
||||
local _ENV = _ENV
|
||||
local _G = _G
|
||||
|
||||
local HTML_ENTITIES = {
|
||||
["&"] = "&",
|
||||
["<"] = "<",
|
||||
[">"] = ">",
|
||||
['"'] = """,
|
||||
["'"] = "'",
|
||||
["/"] = "/"
|
||||
}
|
||||
|
||||
local CODE_ENTITIES = {
|
||||
["{"] = "{",
|
||||
["}"] = "}",
|
||||
["&"] = "&",
|
||||
["<"] = "<",
|
||||
[">"] = ">",
|
||||
['"'] = """,
|
||||
["'"] = "'",
|
||||
["/"] = "/"
|
||||
}
|
||||
|
||||
local VAR_PHASES
|
||||
|
||||
local ok, newtab = pcall(require, "table.new")
|
||||
if not ok then newtab = function() return {} end end
|
||||
|
||||
local caching = true
|
||||
local template = newtab(0, 12)
|
||||
|
||||
template._VERSION = "1.9"
|
||||
template.cache = {}
|
||||
|
||||
local function enabled(val)
|
||||
if val == nil then return true end
|
||||
return val == true or (val == "1" or val == "true" or val == "on")
|
||||
end
|
||||
|
||||
local function trim(s)
|
||||
return gsub(gsub(s, "^%s+", ""), "%s+$", "")
|
||||
end
|
||||
|
||||
local function rpos(view, s)
|
||||
while s > 0 do
|
||||
local c = sub(view, s, s)
|
||||
if c == " " or c == "\t" or c == "\0" or c == "\x0B" then
|
||||
s = s - 1
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
local function escaped(view, s)
|
||||
if s > 1 and sub(view, s - 1, s - 1) == "\\" then
|
||||
if s > 2 and sub(view, s - 2, s - 2) == "\\" then
|
||||
return false, 1
|
||||
else
|
||||
return true, 1
|
||||
end
|
||||
end
|
||||
return false, 0
|
||||
end
|
||||
|
||||
local function readfile(path)
|
||||
local file = open(path, "rb")
|
||||
if not file then return nil end
|
||||
local content = file:read "*a"
|
||||
file:close()
|
||||
return content
|
||||
end
|
||||
|
||||
local function loadlua(path)
|
||||
return readfile(path) or path
|
||||
end
|
||||
|
||||
local function loadngx(path)
|
||||
local vars = VAR_PHASES[phase()]
|
||||
local file, location = path, vars and var.template_location
|
||||
if sub(file, 1) == "/" then file = sub(file, 2) end
|
||||
if location and location ~= "" then
|
||||
if sub(location, -1) == "/" then location = sub(location, 1, -2) end
|
||||
local res = capture(concat{ location, '/', file})
|
||||
if res.status == 200 then return res.body end
|
||||
end
|
||||
local root = vars and (var.template_root or var.document_root) or prefix
|
||||
if sub(root, -1) == "/" then root = sub(root, 1, -2) end
|
||||
return readfile(concat{ root, "/", file }) or path
|
||||
end
|
||||
|
||||
do
|
||||
if ngx then
|
||||
VAR_PHASES = {
|
||||
set = true,
|
||||
rewrite = true,
|
||||
access = true,
|
||||
content = true,
|
||||
header_filter = true,
|
||||
body_filter = true,
|
||||
log = true
|
||||
}
|
||||
template.print = ngx.print or write
|
||||
template.load = loadngx
|
||||
prefix, var, capture, null, phase = ngx.config.prefix(), ngx.var, ngx.location.capture, ngx.null, ngx.get_phase
|
||||
if VAR_PHASES[phase()] then
|
||||
caching = enabled(var.template_cache)
|
||||
end
|
||||
else
|
||||
template.print = write
|
||||
template.load = loadlua
|
||||
end
|
||||
if _VERSION == "Lua 5.1" then
|
||||
local context = { __index = function(t, k)
|
||||
return t.context[k] or t.template[k] or _G[k]
|
||||
end }
|
||||
if jit then
|
||||
loadchunk = function(view)
|
||||
return assert(load(view, nil, nil, setmetatable({ template = template }, context)))
|
||||
end
|
||||
else
|
||||
loadchunk = function(view)
|
||||
local func = assert(loadstring(view))
|
||||
setfenv(func, setmetatable({ template = template }, context))
|
||||
return func
|
||||
end
|
||||
end
|
||||
else
|
||||
local context = { __index = function(t, k)
|
||||
return t.context[k] or t.template[k] or _ENV[k]
|
||||
end }
|
||||
loadchunk = function(view)
|
||||
return assert(load(view, nil, nil, setmetatable({ template = template }, context)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function template.caching(enable)
|
||||
if enable ~= nil then caching = enable == true end
|
||||
return caching
|
||||
end
|
||||
|
||||
function template.output(s)
|
||||
if s == nil or s == null then return "" end
|
||||
if type(s) == "function" then return template.output(s()) end
|
||||
return tostring(s)
|
||||
end
|
||||
|
||||
function template.escape(s, c)
|
||||
if type(s) == "string" then
|
||||
if c then return gsub(s, "[}{\">/<'&]", CODE_ENTITIES) end
|
||||
return gsub(s, "[\">/<'&]", HTML_ENTITIES)
|
||||
end
|
||||
return template.output(s)
|
||||
end
|
||||
|
||||
function template.new(view, layout)
|
||||
assert(view, "view was not provided for template.new(view, layout).")
|
||||
local render, compile = template.render, template.compile
|
||||
if layout then
|
||||
if type(layout) == "table" then
|
||||
return setmetatable({ render = function(self, context)
|
||||
local context = context or self
|
||||
context.blocks = context.blocks or {}
|
||||
context.view = compile(view)(context)
|
||||
layout.blocks = context.blocks or {}
|
||||
layout.view = context.view or ""
|
||||
return layout:render()
|
||||
end }, { __tostring = function(self)
|
||||
local context = self
|
||||
context.blocks = context.blocks or {}
|
||||
context.view = compile(view)(context)
|
||||
layout.blocks = context.blocks or {}
|
||||
layout.view = context.view
|
||||
return tostring(layout)
|
||||
end })
|
||||
else
|
||||
return setmetatable({ render = function(self, context)
|
||||
local context = context or self
|
||||
context.blocks = context.blocks or {}
|
||||
context.view = compile(view)(context)
|
||||
return render(layout, context)
|
||||
end }, { __tostring = function(self)
|
||||
local context = self
|
||||
context.blocks = context.blocks or {}
|
||||
context.view = compile(view)(context)
|
||||
return compile(layout)(context)
|
||||
end })
|
||||
end
|
||||
end
|
||||
return setmetatable({ render = function(self, context)
|
||||
return render(view, context or self)
|
||||
end }, { __tostring = function(self)
|
||||
return compile(view)(self)
|
||||
end })
|
||||
end
|
||||
|
||||
function template.precompile(view, path, strip)
|
||||
local chunk = dump(template.compile(view), strip ~= false)
|
||||
if path then
|
||||
local file = open(path, "wb")
|
||||
file:write(chunk)
|
||||
file:close()
|
||||
end
|
||||
return chunk
|
||||
end
|
||||
|
||||
function template.compile(view, key, plain)
|
||||
assert(view, "view was not provided for template.compile(view, key, plain).")
|
||||
if key == "no-cache" then
|
||||
return loadchunk(template.parse(view, plain)), false
|
||||
end
|
||||
key = key or view
|
||||
local cache = template.cache
|
||||
if cache[key] then return cache[key], true end
|
||||
local func = loadchunk(template.parse(view, plain))
|
||||
if caching then cache[key] = func end
|
||||
return func, false
|
||||
end
|
||||
|
||||
function template.parse(view, plain)
|
||||
assert(view, "view was not provided for template.parse(view, plain).")
|
||||
if not plain then
|
||||
view = template.load(view)
|
||||
if byte(view, 1, 1) == 27 then return view end
|
||||
end
|
||||
local j = 2
|
||||
local c = {[[
|
||||
context=... or {}
|
||||
local function include(v, c) return template.compile(v)(c or context) end
|
||||
local ___,blocks,layout={},blocks or {}
|
||||
]] }
|
||||
local i, s = 1, find(view, "{", 1, true)
|
||||
while s do
|
||||
local t, p = sub(view, s + 1, s + 1), s + 2
|
||||
if t == "{" then
|
||||
local e = find(view, "}}", p, true)
|
||||
if e then
|
||||
local z, w = escaped(view, s)
|
||||
if i < s - w then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, s - 1 - w)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
if z then
|
||||
i = s
|
||||
else
|
||||
c[j] = "___[#___+1]=template.escape("
|
||||
c[j+1] = trim(sub(view, p, e - 1))
|
||||
c[j+2] = ")\n"
|
||||
j=j+3
|
||||
s, i = e + 1, e + 2
|
||||
end
|
||||
end
|
||||
elseif t == "*" then
|
||||
local e = find(view, "*}", p, true)
|
||||
if e then
|
||||
local z, w = escaped(view, s)
|
||||
if i < s - w then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, s - 1 - w)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
if z then
|
||||
i = s
|
||||
else
|
||||
c[j] = "___[#___+1]=template.output("
|
||||
c[j+1] = trim(sub(view, p, e - 1))
|
||||
c[j+2] = ")\n"
|
||||
j=j+3
|
||||
s, i = e + 1, e + 2
|
||||
end
|
||||
end
|
||||
elseif t == "%" then
|
||||
local e = find(view, "%}", p, true)
|
||||
if e then
|
||||
local z, w = escaped(view, s)
|
||||
if z then
|
||||
if i < s - w then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, s - 1 - w)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
i = s
|
||||
else
|
||||
local n = e + 2
|
||||
if sub(view, n, n) == "\n" then
|
||||
n = n + 1
|
||||
end
|
||||
local r = rpos(view, s - 1)
|
||||
if i <= r then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, r)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
c[j] = trim(sub(view, p, e - 1))
|
||||
c[j+1] = "\n"
|
||||
j=j+2
|
||||
s, i = n - 1, n
|
||||
end
|
||||
end
|
||||
elseif t == "(" then
|
||||
local e = find(view, ")}", p, true)
|
||||
if e then
|
||||
local z, w = escaped(view, s)
|
||||
if i < s - w then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, s - 1 - w)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
if z then
|
||||
i = s
|
||||
else
|
||||
local f = sub(view, p, e - 1)
|
||||
local x = find(f, ",", 2, true)
|
||||
if x then
|
||||
c[j] = "___[#___+1]=include([=["
|
||||
c[j+1] = trim(sub(f, 1, x - 1))
|
||||
c[j+2] = "]=],"
|
||||
c[j+3] = trim(sub(f, x + 1))
|
||||
c[j+4] = ")\n"
|
||||
j=j+5
|
||||
else
|
||||
c[j] = "___[#___+1]=include([=["
|
||||
c[j+1] = trim(f)
|
||||
c[j+2] = "]=])\n"
|
||||
j=j+3
|
||||
end
|
||||
s, i = e + 1, e + 2
|
||||
end
|
||||
end
|
||||
elseif t == "[" then
|
||||
local e = find(view, "]}", p, true)
|
||||
if e then
|
||||
local z, w = escaped(view, s)
|
||||
if i < s - w then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, s - 1 - w)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
if z then
|
||||
i = s
|
||||
else
|
||||
c[j] = "___[#___+1]=include("
|
||||
c[j+1] = trim(sub(view, p, e - 1))
|
||||
c[j+2] = ")\n"
|
||||
j=j+3
|
||||
s, i = e + 1, e + 2
|
||||
end
|
||||
end
|
||||
elseif t == "-" then
|
||||
local e = find(view, "-}", p, true)
|
||||
if e then
|
||||
local x, y = find(view, sub(view, s, e + 1), e + 2, true)
|
||||
if x then
|
||||
local z, w = escaped(view, s)
|
||||
if z then
|
||||
if i < s - w then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, s - 1 - w)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
i = s
|
||||
else
|
||||
y = y + 1
|
||||
x = x - 1
|
||||
if sub(view, y, y) == "\n" then
|
||||
y = y + 1
|
||||
end
|
||||
local b = trim(sub(view, p, e - 1))
|
||||
if b == "verbatim" or b == "raw" then
|
||||
if i < s - w then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, s - 1 - w)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
c[j] = "___[#___+1]=[=["
|
||||
c[j+1] = sub(view, e + 2, x)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
else
|
||||
if sub(view, x, x) == "\n" then
|
||||
x = x - 1
|
||||
end
|
||||
local r = rpos(view, s - 1)
|
||||
if i <= r then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, r)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
c[j] = 'blocks["'
|
||||
c[j+1] = b
|
||||
c[j+2] = '"]=include[=['
|
||||
c[j+3] = sub(view, e + 2, x)
|
||||
c[j+4] = "]=]\n"
|
||||
j=j+5
|
||||
end
|
||||
s, i = y - 1, y
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif t == "#" then
|
||||
local e = find(view, "#}", p, true)
|
||||
if e then
|
||||
local z, w = escaped(view, s)
|
||||
if i < s - w then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = sub(view, i, s - 1 - w)
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
if z then
|
||||
i = s
|
||||
else
|
||||
e = e + 2
|
||||
if sub(view, e, e) == "\n" then
|
||||
e = e + 1
|
||||
end
|
||||
s, i = e - 1, e
|
||||
end
|
||||
end
|
||||
end
|
||||
s = find(view, "{", s + 1, true)
|
||||
end
|
||||
s = sub(view, i)
|
||||
if s and s ~= "" then
|
||||
c[j] = "___[#___+1]=[=[\n"
|
||||
c[j+1] = s
|
||||
c[j+2] = "]=]\n"
|
||||
j=j+3
|
||||
end
|
||||
c[j] = "return layout and include(layout,setmetatable({view=table.concat(___),blocks=blocks},{__index=context})) or table.concat(___)"
|
||||
return concat(c)
|
||||
end
|
||||
|
||||
function template.render(view, context, key, plain)
|
||||
assert(view, "view was not provided for template.render(view, context, key, plain).")
|
||||
return template.print(template.compile(view, key, plain)(context))
|
||||
end
|
||||
|
||||
return template
|
||||
Reference in New Issue
Block a user