跳转到内容

模块:Citation/CS1/COinS

本页使用了标题或全文手工转换
来自维基百科
imported>Antigng2022年4月27日 (三) 00:37的版本 (已保护“Module:Citation/CS1/COinS”:​高风险模块([编辑=仅允许管理员](无限期)[移动=仅允许管理员](无限期)))
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)
-{H|zh-cn:账号; zh-tw:帳號;}--{H|账户=>zh-cn:账号; 账户=>zh-tw:帳號;}--{H|賬戶=>zh-cn:账号; 賬戶=>zh-tw:帳號;}--{H|賬號=>zh-cn:账号; 賬號=>zh-tw:帳號;}--{H|帐户=>zh-cn:账号; 帐户=>zh-tw:帳號;}--{H|帳戶=>zh-cn:账号;}--{H|帐号=>zh-cn:账号; 帐号=>zh-tw:帳號;}--{H|zh-cn:全域账号; zh-tw:全域帳號;}--{H|zh-cn:大量账号创建者; zh-tw:大量帳號建立者; zh-hk:大量帳號建立者;}--{H|zh-cn:高级; zh-tw:進階;}--{H|zh-cn:规范控制; zh-tw:權威控制;}--{H|zh-cn:封禁; zh-tw:封鎖; zh-hk:封鎖;}--{H|zh-cn:全域封禁; zh-tw:全域封鎖; zh-hk:全域封鎖;}--{H|zh-cn:更改; zh-tw:變更;}--{H|zh-cn:字符; zh-tw:字元;}--{H|zh-cn:著作权; zh-tw:著作權; zh-hk:版權; zh-mo:著作權;}--{H|版权=>zh-tw:著作權; 版权=>zh-mo:著作權;}--{H|版权信息=>zh-cn:著作权信息; 版权信息=>zh-sg:著作权信息; 版权信息=>zh-my:著作权信息; 版权信息=>zh-tw:著作權資訊; 版权信息=>zh-mo:著作權資訊;}--{H|zh-cn:创建; zh-tw:建立;}--{H|創建=>zh-tw:建立; 創建=>zh-hk:建立; 創建=>zh-mo:建立;}--{H|zh-cn:自定义; zh-tw:自訂;}--{H|自定義=>zh-hk:自訂; 自定義=>zh-tw:自訂;}--{H|自定=>zh-hk:自訂; 自定=>zh-tw:自訂;}--{H|zh-cn:默认; zh-tw:預設;}--{H|默認=>zh-tw:預設;}--{H|zh-hans: 扩展名; zh-hant: 副檔名;}--{H|文件扩展名 => zh-tw: 副檔名; 文件扩展名 => zh-hk: 副檔名; 文件扩展名 => zh-mo: 副檔名; }--{H|zh-hans: 扩展; zh-hant: 擴充功能;}--{H|扩充功能 => zh-cn: 扩展; 扩充功能 => zh-my: 扩展; 扩充功能 => zh-sg: 扩展;}--{H|擴充套件 => zh-cn: 扩展; 擴充套件 => zh-my: 扩展; 擴充套件 => zh-sg: 扩展;}--{H|擴展 => zh-tw: 擴充功能; 擴展 => zh-hk: 擴充功能; 擴展 => zh-mo: 擴充功能; }--{H|zh-cn:文件; zh-tw:檔案;}--{H|档案=>zh-cn:文件; 档案=>zh-sg:文件; 档案=>zh-my:文件;}--{H|zh-cn:文件名; zh-tw:檔案名稱;}--{H|zh-hans:机器用户; zh-tw:機器使用者; zh-hk:機械用戶;}--{H|zh-cn:脚注; zh-tw:註腳;}--{H|zh-cn:帮助:; zh-tw:說明:;}--{H|zh-cn:帮助讨论:; zh-tw:說明討論:;}--{H|zh-cn:导入; zh-tw:匯入;}--{H|汇入=>zh-cn:导入; 汇入=>zh-sg:导入; 汇入=>zh-my:导入;}--{H|導入=>zh-tw:匯入; 導入=>zh-hk:匯入; 導入=>zh-mo:匯入;}--{H|zh-cn:信息; zh-tw:資訊;}--{H|zh-hans:界面; zh-hant:介面;}--{H|zh-cn:界面管理员; zh-tw:介面管理員;}--{H|zh-cn:IP封禁豁免; zh-tw:IP封鎖豁免;}--{H|IP封禁例外=>zh-hans:IP封禁豁免; IP封禁例外=>zh-hant:IP封鎖豁免;}--{H|IP封鎖例外=>zh-hans:IP封禁豁免; IP封禁例外=>zh-hant:IP封鎖豁免;}--{H|zh-hans:换行符;zh-hant:換行字元;}--{H|zh:換行符;zh-hans:换行符;zh-hant:換行字元;}--{H|zh:换行字元;zh-hans:换行符;zh-hant:換行字元;}--{H|zh-cn:链接; zh-tw:連結;}--{H|连结=>zh-cn:链接; 连结=>zh-sg:链接; 连结=>zh-my:链接;}--{H|鏈接=>zh-tw:連結; 鏈接=>zh-hk:連結; 鏈接=>zh-mo:連結;}--{H|鏈結=>zh-tw:連結; 鏈結=>zh-hk:連結; 鏈結=>zh-mo:連結;}--{H|内链=>zh-tw:內部連結; 内链=>zh-hk:內部連結; 内链=>zh-mo:內部連結;}--{H|內鏈=>zh-tw:內部連結; 內鏈=>zh-hk:內部連結; 內鏈=>zh-mo:內部連結;}--{H|外链=>zh-tw:外部連結; 外链=>zh-hk:外部連結; 外链=>zh-mo:外部連結;}--{H|外鏈=>zh-tw:外部連結; 外鏈=>zh-hk:外部連結; 外鏈=>zh-mo:外部連結;}--{H|红链=>zh-tw:紅色連結; 红链=>zh-hk:紅色連結; 红链=>zh-mo:紅色連結;}--{H|紅鏈=>zh-tw:紅色連結; 紅鏈=>zh-hk:紅色連結; 紅鏈=>zh-mo:紅色連結;}--{H|绿链=>zh-tw:綠色連結; 绿链=>zh-hk:綠色連結; 绿链=>zh-mo:綠色連結;}--{H|綠鏈=>zh-tw:綠色連結; 綠鏈=>zh-hk:綠色連結; 綠鏈=>zh-mo:綠色連結;}--{H|蓝链=>zh-tw:藍色連結; 蓝链=>zh-hk:藍色連結; 蓝链=>zh-mo:藍色連結;}--{H|藍鏈=>zh-tw:藍色連結; 藍鏈=>zh-hk:藍色連結; 藍鏈=>zh-mo:藍色連結;}--{H|zh-cn:链入; zh-tw:連入;}--{H|鏈入=>zh-tw:連入;}--{H|zh-hans:日志详情; zh-hant:日誌明細;}--{H|zh-hans:登录; zh-hant:登入;}--{H|zh-hant:登出; zh-hans:退出;}--{H|退出登录 => zh-tw:登出; 退出登录 => zh-hk:登出; 退出登录 => zh-mo:登出; }--{H|zh-cn:模块; zh-tw:模組;}--{H|模组=>zh-cn:模块; 模组=>zh-sg:模块; 模组=>zh-my:模块;}--{H|zh-hans:模块文档; zh-hant:模組文件;}--{H|zh-hans:命名空间; zh-hant:命名空間;}--{H|名字空间=>zh-cn:命名空间; 名字空间=>zh-hk:命名空間; 名字空间=>zh-mo:命名空間; 名字空间=>zh-tw:命名空間; 名字空间=>zh-sg:命名空间; 名字空间=>zh-my:命名空间;}--{H|名字空間=>zh-cn:命名空间; 名字空間=>zh-hk:命名空間; 名字空間=>zh-mo:命名空間; 名字空間=>zh-tw:命名空間; 名字空間=>zh-sg:命名空间; 名字空間=>zh-my:命名空间;}--{H|zh-hans:布告板; zh-hant:布告板;}--{H|布告板=>zh-hk:佈告板; 布告板=>zh-mo:佈告板}--{H|佈告板=>zh-tw:布告板; 佈告板=>zh-hans:布告板}--{H|zh-cn:解析器函数; zh-hk:解析器函數; zh-tw:解析器函數;}--{H|zh-cn:参数设置; zh-tw:偏好設定; zh-hk:參數設置;}--{H|zh-hans:项目; zh-hant:專案; zh-tw:專案;}--{H|专案=>zh-cn:项目; 专案=>zh-sg:项目; 专案=>zh-my:项目; 专案=>zh-tw:專案;}--{H|計劃=>zh-cn:项目; 計劃=>zh-sg:项目; 計劃=>zh-my:项目; 計劃=>zh-tw:專案; 計劃=>zh-hk:專案; 計劃=>zh-mo:專案;}--{H|zh-hans:项目页面; zh-hant:專案頁面; zh-tw:專案頁面;}--{H|項目頁面=>zh-tw:計畫頁面; 項目頁面=>zh-hk:專案頁面; 項目=>zh-mo:專案頁面;}--{H|zh-hans:最近更改; zh-hant:近期變更;}--{H|zh-cn:重定向; zh-tw:重新導向;}--{H|zh-cn:重定向页; zh-tw:重新導向頁面;}--{H|重定向页面=>zh-tw:重新導向頁面; 重定向页面=>zh-hk:重新導向頁面; 重定向页面=>zh-mo:重新導向頁面;}--{H|zh-cn:举报; zh-tw:檢舉;}--{H|zh-cn:示例; zh-tw:範例;}--{H|皮肤=>zh-tw:外觀; 皮肤=>zh-hk:外觀; 皮肤=>zh-mo:外觀;}--{H|zh-hans:原始码; zh-hant:原始碼; zh-cn:源代码;}--{H|源代碼=>zh-hk:原始碼; 源代碼=>zh-mo:原始碼; 源代碼=>zh-tw:原始碼; 源代碼=>zh-sg:原始码; 源代碼=>zh-my:原始码;}--{H|源码=>zh-hk:原始碼; 源码=>zh-mo:原始碼; 源码=>zh-tw:原始碼; 源码=>zh-sg:原始码; 源码=>zh-my:原始码;}--{H|源碼=>zh-hk:原始碼; 源碼=>zh-mo:原始碼; 源碼=>zh-tw:原始碼; 源碼=>zh-sg:原始码; 源碼=>zh-my:原始码;}--{H|zh-cn:字符串; zh-tw:字串;}--{H|zh-hans:模板数据; zh-hant:模板資料; zh-tw:模板資料;}--{H|zh-hans:模板文档; zh-hant:模板文件;}--{H|zh-cn:通过; zh-tw:透過;}--{H|zh-cn:撤销; zh-tw:復原;}--{H|撤消=>zh-tw:復原; 撤消=>zh-hk:復原; 撤消=>zh-mo:復原;}--{H|zh-hans:用户; zh-hant:使用者; zh-tw:使用者; zh-hk:用戶;}--{H|zh-cn:用户组; zh-tw:使用者群組; zh-hk:用戶組;}--{H|用户名字空間=>zh-hk:用戶命名空間; 用户名字空間=>zh-mo:用戶命名空間; 用户名字空間=>zh-tw:使用者命名空間;}--{H|用戶名字空间=>zh-hk:用戶命名空間; 用戶名字空间=>zh-mo:用戶命名空間; 用戶名字空间=>zh-tw:使用者命名空間;}--{H|用戶名字空間=>zh-hk:用戶命名空間; 用戶名字空間=>zh-mo:用戶命名空間; 用戶名字空間=>zh-tw:使用者命名空間;}--{H|zh-cn:用户页; zh-tw:使用者頁面; zh-hk:用戶頁;}--{H|用户頁=>zh-tw:使用者頁面;}--{H|用戶页=>zh-tw:使用者頁面;}--{H|用户页面=>zh-tw:使用者頁面;}--{H|使用者頁=>zh-tw:使用者頁面;}--{H|使用者頁面=>zh-tw:使用者頁面;}--{H|用户权限 => zh-tw:使用者權限;用戶權限 => zh-tw:使用者權限;}--{H|用户权 => zh-tw:使用者權限;用戶權 => zh-tw:使用者權限;}--{H|zh-cn:用户框; zh-tw:使用者方塊; zh-hk:用戶框;}--{H|zh-hans:用户名; zh-hant:用戶名; zh-tw:使用者名稱;}--{H|用户名称=>zh-cn:用户名; 用户名称=>zh-my:用户名; 用户名称=>zh-sg:用户名; 用户名称=>zh-tw:使用者名稱;}--{H|用戶名稱=>zh-cn:用户名; 用戶名稱=>zh-my:用户名; 用戶名稱=>zh-sg:用户名; 用戶名稱=>zh-tw:使用者名稱;}--{H|zh-cn:查看; zh-tw:檢視;}--{H|zh-cn:可视化; zh-tw:視覺化;}--{H|zh-cn:监视列表; zh-tw:監視清單;}--{H|计算机=>zh-sg:电脑; 计算机=>zh-my:电脑; 计算机=>zh-tw:電腦; 计算机=>zh-hk:電腦; 计算机=>zh-mo:電腦;}--{H|計算機=>zh-sg:电脑; 計算機=>zh-my:电脑;}--{H|电子计算机=>zh-sg:电脑; 电子计算机=>zh-my:电脑; 电子计算机=>zh-tw:電腦; 电子计算机=>zh-hk:電腦; 电子计算机=>zh-mo:電腦;}--{H|zh-cn:链接; zh-tw:連結;}--{H|连结=>zh-cn:链接; 连结=>zh-sg:链接; 连结=>zh-my:链接;}--{H|zh-cn:链入; zh-tw:連入;}--{H|zh-cn:程序;zh-hk:程序;zh-tw:程式;}--{H|zh-cn:语法高亮; zh-tw:語法突顯;}--{H|語法凸顯=>zh-cn:语法高亮; 語法凸顯=>zh-sg:语法高亮; 語法凸顯=>zh-my:语法高亮;}--{H|语法高亮度=>zh-tw:語法突顯; 语法高亮度=>zh-hk:語法突顯; 语法高亮度=>zh-mo:語法突顯;}--{H|語法高亮度=>zh-tw:語法突顯; 語法高亮度=>zh-hk:語法突顯; 語法高亮度=>zh-mo:語法突顯;}--{H|zh-cn:可视化; zh-tw:視覺化;}--{H|紀錄=>zh-cn:记录}--{H|zh-cn:署名; zh-hk:署名; zh-tw:姓名標示; zh-sg:署名;}--{H|zh-hans:著作权; zh-hant:著作權; zh-hk:版權;}--{H|版权=>zh-cn:著作权; 版权=>zh-sg:著作权; 版权=>zh-my:著作权; 版权=>zh-tw:著作權; 版权=>zh-mo:著作權;}--{H|zh-hans:著作权信息;zh-hant:著作權資訊;zh-hk:版權資訊;}--{H|版权信息=>zh-cn:著作权信息; 版权信息=>zh-sg:著作权信息; 版权信息=>zh-my:著作权信息; 版权信息=>zh-tw:著作權資訊; 版权信息=>zh-mo:著作權資訊;}--{H|zh-cn:知识共享;zh-tw:創用CC;zh-hk:共享創意;}--{H|知识共享CC => zh-tw: 創用CC; 共享創意CC => zh-tw: 創用CC;}--{H|zh-cn:知识共享公共许可协议;zh-tw:創用CC公眾授權條款;zh-hk:共享創意公眾特許條款;}--{H|創用 CC 公眾授權條款=>zh-cn:知识共享公共许可协议;創用 CC 公眾授權條款=>zh-tw:創用 CC 公眾授權條款;創用 CC 公眾授權條款=>zh-hk:共享創意公眾特許條款;創用 CC 公眾授權條款=>zh-mo:共享創意公眾特許條款;}--{H|創用CC 公眾授權條款=>zh-cn:知识共享公共许可协议;創用CC 公眾授權條款=>zh-tw:創用CC 公眾授權條款;創用CC 公眾授權條款=>zh-hk:共享創意公眾特許條款;創用CC 公眾授權條款=>zh-mo:共享創意公眾特許條款;}--{H|創作共用公眾授權條款=>zh-cn:知识共享公共许可协议;創用共用公眾授權條款=>zh-tw:創用CC 公眾授權條款;創用共用公眾授權條款=>zh-hk:共享創意公眾特許條款;創用共用公眾授權條款=>zh-mo:共享創意公眾特許條款;}--{H|zh-cn:自由软件许可协议;zh-tw:自由軟體授權;zh-hk:自由軟體授權;}--{H|zh-cn:信息; zh-tw:資訊}--{H|授權=>zh-cn:授权; 授權=>zh-hk:授權; 授權=>zh-tw:授權;}--{H|授权=>zh-cn:授权; 授權=>zh-hk:授權; 授權=>zh-tw:授權;}--{H|特許=>zh-cn:許可; 特許=>zh-hk:特許; 特許=>zh-tw:授權;}--{H|許可=>zh-cn:许可; 許可=>zh-tw:授權; 許可=>zh-hk:特許;}--{H|许可=>zh-cn:许可; 许可=>zh-tw:授權; 许可=>zh-hk:特許;}--{H|zh-cn:许可条款; zh-tw:授權條款; zh-hk:特許條款;}--{H|授权条款=>zh-cn:许可证;授权条款=>zh-hk:特許條款;授权条款=>zh-mo:特許條款;}--{H|许可证=>zh-tw:授權條款;许可证=>zh-hk:特許條款;许可证=>zh-mo:特許條款;}--{H|許可證=>zh-tw:授權條款;許可證=>zh-hk:特許條款;許可證=>zh-mo:特許條款;}--{H|zh-cn:本地化; zh-tw:在地化; zh-hk:本地化; zh-sg:本地化;}--{H|zh-cn:禁止演绎; zh-hk:禁止衍生; zh-tw:禁止改作; zh-cn:禁止演绎;}--{H|zh-cn:发布; zh-tw:釋出;}--{H|zh-cn:相同方式共享; zh-hk:相同方式共享; zh-tw:相同方式分享; zh-sg:相同方式共享;}--{H|zh-hans:维护报告;zh-hant:維護報表}--{H|zh:未连接至项的页面;zh-hans:未连接至项的页面;zh-hant:頁面未連結至任何項目}--{H|未链接页面=>zh:未连接至项的页面;未链接页面=>zh-hans:未连接至项的页面;未链接页面=>zh-hant:頁面未連結至任何項目}--{H|zh-hans:页面列表;zh-hant:頁面清單}--{H|所有带前缀的页面=>zh:前缀索引;所有带前缀的页面=>zh-hans:前缀索引;所有带前缀的页面=>zh-hant:前缀索引}--{H|按詞頭查詢頁面=>zh:前缀索引;按詞頭查詢頁面=>zh-hans:前缀索引;按詞頭查詢頁面=>zh-hant:前缀索引}--{H|zh-cn:搜索; zh-tw:搜尋;}--{H|zh:全域用户账户重命名申请;zh-hans:全域用户账户重命名申请;zh-hant:全域使用者帳號重新命名請求}--{H|全域重命名申请=>zh:全域用户账户重命名申请;全域重命名申请=>zh-hans:全域用户账户重命名申请;全域重命名申请=>zh-hant:全域使用者帳號重新命名請求}--{H|zh:创建账户;zh-hans:创建账户;zh-hant:建立帳號}--{H|zh:登录;zh-hans:登录;zh-hant:登入}--{H|zh:统一登录状态;zh-hans:统一登录状态;zh-hant:帳號整合狀態}--{H|合并账户=>zh:统一登录状态;合并账户=>zh-hans:统一登录状态;合并账户=>zh-hant:帳號整合狀態}--{H|zh-hans:电子邮箱;zh-hant:電子郵件;}--{H|zh-hans:电邮联系;zh-hant:電郵聯絡用戶;zh-tw:電郵聯絡使用者;}--{H|zh-hans:参数设置;zh-hant:偏好設定;}--{H|偏好设定=>zh-hans:参数设置;偏好设定=>zh-cn:参数设置;偏好设定=>zh-my:参数设置;偏好设定=>zh-sg:参数设置;}--{H|參數設置=>zh-hant:偏好設定;參數設置=>zh-tw:偏好設定;參數設置=>zh-hk:偏好設定;參數設置=>zh-mo:偏好設定;}--{H|zh-hans:设置;zh-hant:設定;}--{H|设定=>zh-hans:设置;设定=>zh-cn:设置;设定=>zh-my:设置;设定=>zh-sg:设置;}--{H|設置=>zh-hant:設定;設置=>zh-tw:設定;設置=>zh-hk:設定;設置=>zh-mo:設定;}--{H|zh-hans:最近更改;zh-hant:近期變更;}--{H|近期变更=>zh-cn:最近更改;近期变更=>zh-my:最近更改;近期变更=>zh-sg:最近更改;}--{H|zh-hans:链入页面;zh-hant:連結至此的頁面;}--{H|链接至此的页面=>zh-cn:链入页面;链接至此的页面=>zh-my:链入页面;链接至此的页面=>zh-sg:链入页面;}--{H|连结至此的页面=>zh-cn:链入页面;连结至此的页面=>zh-my:链入页面;连结至此的页面=>zh-sg:链入页面;}--{H|鏈入頁面=>zh-tw:連結至此的頁面;鏈入頁面=>zh-hk:連結至此的頁面;鏈入頁面=>zh-mo:連結至此的頁面;}--{H|連入頁面=>zh-tw:連結至此的頁面;連入頁面=>zh-hk:連結至此的頁面;連入頁面=>zh-mo:連結至此的頁面;}--{H|zh-cn:档案馆; zh-tw:檔案館;}--{H|档案馆=>zh-cn:档案馆; 档案馆=>zh-sg:档案馆; 档案馆=>zh-my:档案馆;}--{H|zh-hans:方程式;zh-hant:方程式}--{H|zh-cn:全域禁制; zh-tw:全域禁制;}--{H|zh-cn:日志项目; zh-tw:日誌項目;}--{H|zh-hant:通過;zh-tw:通過;zh-hk:通過;zh-mo:通過;zh-hans:通过;zh-cn:通过;zh-sg:通过;zh-my:通过;}--{H|透過=>zh-hant:透過;zh-hans:通过;}--{H|使用者名稱稱=>zh-tw:使用者名稱;}--{H|使用者名稱命名空間 => zh-tw:使用者命名空間;}--{H|使用者權限限 => zh-tw:使用者權限;}--{H|用户名单 => zh-tw:使用者名單; 用戶名單 => zh-tw:使用者名單;}--{H|用户名單 => zh-tw:使用者名單; 用户名單 => zh-tw:使用者名單;}--{H|zh-hans:或许可以;zh-hant:或許可以}--{H|zh-hans:也许可以;zh-hant:也許可以}-


{{#lst:Module:Citation/CS1/doc|header}} 此页面包含渲染CS1与CS2模板的元数据所用的各种函数

{{#lst:Module:Citation/CS1/doc|module_components_table}}




--[[--------------------------< F O R W A R D   D E C L A R A T I O N S >--------------------------------------
]]

local is_set, in_array, remove_wiki_link, strip_apostrophe_markup;				-- functions in Module:Citation/CS1/Utilities and Module:Citation/CS1/Links

local cfg;																		-- table of configuration tables that are defined in Module:Citation/CS1/Configuration


--[[--------------------------< M A K E _ C O I N S _ T I T L E >----------------------------------------------

Makes a title for COinS from Title and / or ScriptTitle (or any other name-script pairs)

Apostrophe markup (bold, italics) is stripped from each value so that the COinS metadata isn't corrupted with strings
of %27%27...

]]

local function make_coins_title (title, script)
	if is_set (title) then
		title = strip_apostrophe_markup (title);								-- strip any apostrophe markup
	else
		title = '';																-- if not set, make sure title is an empty string
	end
	if is_set (script) then
		script = script:gsub ('^%l%l%s*:%s*', '');								-- remove language prefix if present (script value may now be empty string)
		script = strip_apostrophe_markup (script);								-- strip any apostrophe markup
	else
		script = '';																-- if not set, make sure script is an empty string
	end
	if is_set (title) and is_set (script) then
		script = ' ' .. script;													-- add a space before we concatenate
	end
	return title .. script;														-- return the concatenation
end


--[[--------------------------< E S C A P E _ L U A _ M A G I C _ C H A R S >----------------------------------

Returns a string where all of Lua's magic characters have been escaped.  This is important because functions like
string.gsub() treat their pattern and replace strings as patterns, not literal strings.
]]

local function escape_lua_magic_chars (argument)
	argument = argument:gsub("%%", "%%%%");										-- replace % with %%
	argument = argument:gsub("([%^%$%(%)%.%[%]%*%+%-%?])", "%%%1");				-- replace all other Lua magic pattern characters
	return argument;
end


--[[--------------------------< G E T _ C O I N S _ P A G E S >------------------------------------------------

Extract page numbers from external wikilinks in any of the |page=, |pages=, or |at= parameters for use in COinS.

]]

local function get_coins_pages (pages)
	local pattern;
	if not is_set (pages) then return pages; end								-- if no page numbers then we're done
	
	while true do
		pattern = pages:match("%[(%w*:?//[^ ]+%s+)[%w%d].*%]");					-- pattern is the opening bracket, the URL and following space(s): "[url "
		if nil == pattern then break; end										-- no more URLs
		pattern = escape_lua_magic_chars (pattern);								-- pattern is not a literal string; escape Lua's magic pattern characters
		pages = pages:gsub(pattern, "");										-- remove as many instances of pattern as possible
	end
	pages = pages:gsub("[%[%]]", "");											-- remove the brackets
	pages = pages:gsub("–", "-" );							-- replace endashes with hyphens
	pages = pages:gsub("&%w+;", "-" );						-- and replace HTML entities (&ndash; etc.) with hyphens; do we need to replace numerical entities like &#32; and the like?
	return pages;
end


--[=[-------------------------< C O I N S _ R E P L A C E _ M A T H _ S T R I P M A R K E R >------------------

There are three options for math markup rendering that depend on the editor's math preference settings.  These
settings are at [[Special:Preferences#mw-prefsection-rendering]] and are
	PNG images
	TeX source
	MathML with SVG or PNG fallback

All three are heavy with HTML and CSS which doesn't belong in the metadata.

Without this function, the metadata saved in the raw wikitext contained the rendering determined by the settings
of the last editor to save the page.

This function gets the rendered form of an equation according to the editor's preference before the page is saved.  It
then searches the rendering for the text equivalent of the rendered equation and replaces the rendering with that so
that the page is saved without extraneous HTML/CSS markup and with a reasonably readable text form of the equation.

When a replacement is made, this function returns true and the value with replacement; otherwise false and the initial
value.  To replace multipe equations it is necessary to call this function from within a loop.

]=]

local function coins_replace_math_stripmarker (value)
	local stripmarker = cfg.stripmarkers['math'];
	local rendering = value:match (stripmarker);								-- is there a math stripmarker

	if not rendering then														-- when value doesn't have a math stripmarker, abandon this test
		return false, value;
	end
	
	rendering = mw.text.unstripNoWiki (rendering);								-- convert stripmarker into rendered value (or nil? ''? when math render error)
	
	if rendering:match ('alt="[^"]+"') then										-- if PNG math option
		rendering = rendering:match ('alt="([^"]+)"');							-- extract just the math text
	elseif rendering:match ('$%s+.+%s+%$') then									-- if TeX math option; $ is legit character that is escapes as \$
		rendering = rendering:match ('$%s+(.+)%s+%$')							-- extract just the math text
	elseif rendering:match ('<annotation[^>]+>.+</annotation>') then			-- if MathML math option
		rendering = rendering:match ('<annotation[^>]+>(.+)</annotation>')		-- extract just the math text
	else
		return false, value;													-- had math stripmarker but not one of the three defined forms
	end
	
	return true, value:gsub (stripmarker, rendering, 1);
end


--[[--------------------------< C O I N S _ C L E A N U P >----------------------------------------------------

Cleanup parameter values for the metadata by removing or replacing invisible characters and certain HTML entities.

2015-12-10: there is a bug in mw.text.unstripNoWiki ().  It replaces math stripmarkers with the appropriate content
when it shouldn't.  See https://phabricator.wikimedia.org/T121085 and Wikipedia_talk:Lua#stripmarkers_and_mw.text.unstripNoWiki.28.29

TODO: move the replacement patterns and replacement values into a table in /Configuration similar to the invisible
characters table?

]]

local function coins_cleanup (value)
	local replaced = true;														-- default state to get the do loop running

	while replaced do															-- loop until all math stripmarkers replaced
		replaced, value = coins_replace_math_stripmarker (value);				-- replace math stripmarker with text representation of the equation
	end

	value = value:gsub (cfg.stripmarkers['math'], "MATH RENDER ERROR");						-- one or more couldn't be replaced; insert vague error message
	
	value = mw.text.unstripNoWiki (value);										-- replace nowiki stripmarkers with their content
	value = value:gsub ('<span class="nowrap" style="padding%-left:0%.1em;">&#39;(s?)</span>', "'%1");	-- replace {{'}} or {{'s}} with simple apostrophe or apostrophe-s
	value = value:gsub ('&nbsp;', ' ');											-- replace &nbsp; entity with plain space
	value = value:gsub ('\226\128\138', ' ');									-- replace hair space with plain space
	if not mw.ustring.find (value, cfg.indic_script) then						-- don't remove zero-width joiner characters from indic script
		value = value:gsub ('&zwj;', '');											-- remove &zwj; entities
		value = mw.ustring.gsub (value, '[\226\128\141\226\128\139\194\173]', '');	-- remove zero-width joiner, zero-width space, soft hyphen
	end
	value = value:gsub ('[\009\010\013 ]+', ' ');									-- replace horizontal tab, line feed, carriage return with plain space
	return value;
end


--[[--------------------------< C O I N S >--------------------------------------------------------------------

COinS metadata (see <http://ocoins.info/>) allows automated tools to parse the citation information.

]]

local function COinS (data, class)
	if 'table' ~= type (data) or nil == next (data) then
		return '';
	end

	for k, v in pairs (data) do													-- spin through all of the metadata parameter values
		if 'ID_list' ~= k and 'Authors' ~= k then								-- except the ID_list and Author tables (author nowiki stripmarker done when Author table processed)
			data[k] = coins_cleanup (v);
		end
	end

	local ctx_ver = "Z39.88-2004";
	
	-- treat table strictly as an array with only set values.
	local OCinSoutput = setmetatable ({}, {
		__newindex = function(self, key, value)
			if is_set (value) then
				rawset (self, #self+1, table.concat {key, '=', mw.uri.encode (remove_wiki_link (value))});
			end
		end
	});
	
	if in_array (class, {'arxiv', 'biorxiv', 'citeseerx', 'ssrn', 'journal', 'news', 'magazine'}) or (in_array (class, {'conference', 'interview', 'map', 'press release', 'web'}) and is_set(data.Periodical)) or
		('citation' == class and is_set(data.Periodical) and not is_set (data.Encyclopedia)) then
			OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal";			-- journal metadata identifier
			if in_array (class, {'arxiv', 'biorxiv', 'citeseerx', 'ssrn'}) then	-- set genre according to the type of citation template we are rendering
				OCinSoutput["rft.genre"] = "preprint";							-- cite arxiv, cite biorxiv, cite citeseerx, cite ssrn
			elseif 'conference' == class then
				OCinSoutput["rft.genre"] = "conference";						-- cite conference (when Periodical set)
			elseif 'web' == class then
				OCinSoutput["rft.genre"] = "unknown";							-- cite web (when Periodical set)
			else
				OCinSoutput["rft.genre"] = "article";							-- journal and other 'periodical' articles
			end
			OCinSoutput["rft.jtitle"] = data.Periodical;						-- journal only
			if is_set (data.Map) then
				OCinSoutput["rft.atitle"] = data.Map;							-- for a map in a periodical
			else
				OCinSoutput["rft.atitle"] = make_coins_title (data.Title, data.ScriptTitle);
																				-- all other 'periodical' article titles
			end
																				-- these used onlu for periodicals
			OCinSoutput["rft.ssn"] = data.Season;								-- keywords: winter, spring, summer, fall
			OCinSoutput["rft.chron"] = data.Chron;								-- free-form date components
			OCinSoutput["rft.volume"] = data.Volume;							-- does not apply to books
			OCinSoutput["rft.issue"] = data.Issue;
			OCinSoutput["rft.pages"] = get_coins_pages (data.Pages);			-- also used in book metadata

	elseif 'thesis' ~= class then												-- all others except cite thesis are treated as 'book' metadata; genre distinguishes
		OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book";					-- book metadata identifier
		if 'report' == class or 'techreport' == class then						-- cite report and cite techreport
			OCinSoutput["rft.genre"] = "report";
		elseif 'conference' == class then										-- cite conference when Periodical not set
			OCinSoutput["rft.genre"] = "conference";
		elseif in_array (class, {'book', 'citation', 'encyclopaedia', 'interview', 'map'}) then
			if is_set (data.Chapter) or is_set (data.ScriptChapter) then
				OCinSoutput["rft.genre"] = "bookitem";
				OCinSoutput["rft.atitle"] = make_coins_title (data.Chapter, data.ScriptChapter);
																				-- book chapter, encyclopedia article, interview in a book, or map title
			else
				if 'map' == class or 'interview' == class then
					OCinSoutput["rft.genre"] = 'unknown';						-- standalone map or interview
				else
					OCinSoutput["rft.genre"] = 'book';							-- book and encyclopedia
				end
			end
		else	--{'AV media', 'AV media notes', 'episode', 'interview', 'mailinglist', 'map', 'newsgroup', 'podcast', 'press release', 'serial', 'sign', 'speech', 'web'}
			OCinSoutput["rft.genre"] = "unknown";
		end
		OCinSoutput["rft.btitle"] = make_coins_title (data.Title, data.ScriptTitle);
																				-- book only
		OCinSoutput["rft.place"] = data.PublicationPlace;						-- book only
		OCinSoutput["rft.series"] = data.Series;								-- book only
		OCinSoutput["rft.pages"] = get_coins_pages (data.Pages);				-- book, journal
		OCinSoutput["rft.edition"] = data.Edition;								-- book only
		OCinSoutput["rft.pub"] = data.PublisherName;							-- book and dissertation
		
	else																		-- cite thesis
		OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:dissertation";			-- dissertation metadata identifier
		OCinSoutput["rft.title"] = make_coins_title (data.Title, data.ScriptTitle);
																				-- dissertation (also patent but that is not yet supported)
		OCinSoutput["rft.degree"] = data.Degree;								-- dissertation only
		OCinSoutput['rft.inst'] = data.PublisherName;							-- book and dissertation
	end
																				-- and now common parameters (as much as possible)
	OCinSoutput["rft.date"] = data.Date;										-- book, journal, dissertation
	
	for k, v in pairs (data.ID_list) do											-- what to do about these? For now assume that they are common to all?
		if k == 'ISBN' then v = v:gsub ("[^-0-9X]", ""); end
		local id = cfg.id_handlers[k].COinS;
		if string.sub (id or "", 1, 4) == 'info' then							-- for ids that are in the info:registry
			OCinSoutput["rft_id"] = table.concat {id, "/", v};
		elseif string.sub (id or "", 1, 3) == 'rft' then						-- for isbn, issn, eissn, etc that have defined COinS keywords
			OCinSoutput[id] = v;
		elseif id then															-- when cfg.id_handlers[k].COinS is not nil
			OCinSoutput["rft_id"] = table.concat {cfg.id_handlers[k].prefix, v};-- others; provide a url
		end
	end

	local last, first;
	for k, v in ipairs (data.Authors) do
		last, first = coins_cleanup (v.last), coins_cleanup (v.first or '');	-- replace any nowiki strip markers, non-printing or invisible characers
		if k == 1 then															-- for the first author name only
			if is_set (last)  and is_set (first) then							-- set these COinS values if |first= and |last= specify the first author name
				OCinSoutput["rft.aulast"] = last;								-- book, journal, dissertation
				OCinSoutput["rft.aufirst"] = first;								-- book, journal, dissertation
			elseif is_set(last) then 
				OCinSoutput["rft.au"] = last;									-- book, journal, dissertation -- otherwise use this form for the first name
			end
		else																	-- for all other authors
			if is_set(last) and is_set(first) then
				OCinSoutput["rft.au"] = table.concat {last, ", ", first};		-- book, journal, dissertation
			elseif is_set(last) then
				OCinSoutput["rft.au"] = last;									-- book, journal, dissertation
			end
		end
	end

	OCinSoutput.rft_id = data.URL;
	OCinSoutput.rfr_id = table.concat {"info:sid/", mw.site.server:match( "[^/]*$" ), ":", data.RawPage};
	OCinSoutput = setmetatable (OCinSoutput, nil);
	
	-- sort with version string always first, and combine.
	table.sort (OCinSoutput);
	table.insert (OCinSoutput, 1, "ctx_ver=" .. ctx_ver);						-- such as "Z39.88-2004"
	return table.concat (OCinSoutput, "&");
end


--[[--------------------------< S E T _ S E L E C T E D _ M O D U L E S >--------------------------------------

Sets local cfg table and imported functions table to same (live or sandbox) as that used by the other modules.

]]

local function set_selected_modules (cfg_table_ptr, utilities_page_ptr, links_page_ptr)
	cfg = cfg_table_ptr;

	is_set = utilities_page_ptr.is_set;											-- import functions from selected Module:Citation/CS1/Utilities module
	in_array = utilities_page_ptr.in_array;
	strip_apostrophe_markup = utilities_page_ptr.strip_apostrophe_markup;
	
	remove_wiki_link = links_page_ptr.remove_wiki_link;
end


--[[--------------------------< E X P O R T E D   F U N C T I O N S >------------------------------------------
]]

return {
	COinS = COinS,
	
	set_selected_modules = set_selected_modules,
	}