果獲取“當(dāng)前”域名
host = window.location.host;
url=document.domain;
url = window.location.href;
取得完整url路徑: 用以下代碼可以完整研證結(jié)果:
<table width=100% cellpadding=0 cellspacing=0 border=0 >
<script>
thisURL = document.URL;
thisHREF = document.location.href;
thisSLoc = self.location.href;
thisDLoc = document.location;
strwrite = "<tr><td valign=top>thisURL: </td><td>[" + thisURL + "]</td></tr>"
strwrite += "<tr><td valign=top>thisHREF: </td><td>[" + thisHREF + "]</td></tr>"
strwrite += "<tr><td valign=top>thisSLoc: </td><td>[" + thisSLoc + "]</td></tr>"
strwrite += "<tr><td valign=top>thisDLoc: </td><td>[" + thisDLoc + "]</td></tr>"
document.write( strwrite );
</script>
thisDLoc = document.location; <BR>
thisURL = document.URL; <BR>
thisHREF = document.location.href; <BR>
thisSLoc = self.location.href;<BR>
<script>
thisTLoc = top.location.href;
thisPLoc = parent.document.location;
thisTHost = top.location.hostname;
thisHost = location.hostname;
strwrite = "<tr><td valign=top>thisTLoc: </td><td>[" + thisTLoc + "]</td></tr>"
strwrite += "<tr><td valign=top>thisPLoc: </td><td>[" + thisPLoc + "]</td></tr>"
strwrite += "<tr><td valign=top>thisTHost: </td><td>[" + thisTHost + "]</td></tr>"
strwrite += "<tr><td valign=top>thisHost: </td><td>[" + thisHost + "]</td></tr>"
document.write( strwrite );
</script>
thisTLoc = top.location.href; <BR>
thisPLoc = parent.document.location; <BR>
thisTHost = top.location.hostname; <BR>
thisHost = location.hostname;<BR>
<script>
tmpHPage = thisHREF.split( "/" );
thisHPage = tmpHPage[ tmpHPage.length-1 ];
tmpUPage = thisURL.split( "/" );
thisUPage = tmpUPage[ tmpUPage.length-1 ];
strwrite = "<tr><td valign=top>thisHPage: </td><td>[" + thisHPage + "]</td></tr>"
strwrite += "<tr><td valign=top>thisUPage: </td><td>[" + thisUPage + "]</td></tr>"
document.write( strwrite );
</script><tr><td>
運(yùn)行如下: thisDLoc = document.location;
thisURL = document.URL;
thisHREF = document.location.href;
thisSLoc = self.location.href;
thisTLoc = top.location.href;
thisPLoc = parent.document.location;
thisTHost = top.location.hostname;
thisHost = location.hostname;
thisURL: [
thisHREF: [
thisSLoc: [
thisDLoc: [
thisTLoc: [
thisPLoc: [
thisTHost: [925bb.taobao.com]
thisHost: [925bb.taobao.com]
thisHPage: [js%E8%8E%B7%E5%8F%96url.html]
thisUPage: [js%E8%8E%B7%E5%8F%96url.html]
為開發(fā)人員,我們依賴于靜態(tài)分析工具來檢查、lint(分析)和轉(zhuǎn)換我們的代碼。我們使用這些工具來幫助我們提高生產(chǎn)效率并生成更好的代碼。然而,當(dāng)我們使用markdown編寫內(nèi)容時(shí),可用的工具就很少。
在本文中,我們將介紹如何開發(fā)一個(gè)Markdown擴(kuò)展來解決在使用Markdown管理Django站點(diǎn)中的內(nèi)容時(shí)遇到的挑戰(zhàn)。
你認(rèn)為他們有l(wèi)inter嗎?
照片來自Pexels,由mali maeder拍攝
像每個(gè)網(wǎng)站一樣,我們?cè)谥黜摗AQ部分和“關(guān)于”頁面等地方都有不同類型的(大部分)靜態(tài)內(nèi)容。很長(zhǎng)一段時(shí)間以來,我們都是在Django模板中直接管理這些內(nèi)容的。
當(dāng)我們最終決定是時(shí)候?qū)⑦@些內(nèi)容從模板轉(zhuǎn)移到數(shù)據(jù)庫中時(shí),我們認(rèn)為最好使用Markdown。從Markdown生成HTML更安全,它提供了一定程度的控制和一致性,并且對(duì)于非技術(shù)用戶來說更容易處理。隨著我們轉(zhuǎn)移過程的進(jìn)展,我們注意到我們遺漏了一些東西:
當(dāng)URL更改時(shí),鏈接到內(nèi)部頁面的鏈接可能會(huì)中斷。在Django模板和視圖中,我們使用了reverseand {% url %},但是這在普通的Markdown中是不可用的。
絕對(duì)內(nèi)部連接不能在不同環(huán)境之間進(jìn)行復(fù)制。這可以使用相對(duì)鏈接來解決,不過目前沒有開箱即用的增強(qiáng)這一點(diǎn)的方法。
無效鏈接會(huì)損害用戶體驗(yàn),并導(dǎo)致用戶質(zhì)疑整個(gè)內(nèi)容的可靠性。這并不是Markdown獨(dú)有的東西,只不過HTML模板是由對(duì)URL有一定了解的開發(fā)人員維護(hù)的。另一方面,Markdown文檔是為非技術(shù)寫作人員設(shè)計(jì)的。
當(dāng)我研究這個(gè)問題時(shí),我搜索了Python linters、Markdown預(yù)處理器和擴(kuò)展來幫助生成更好的Markdown。結(jié)果都不是很好。一個(gè)引人注目的方法是使用Django模板來生成Markdown文檔。
使用Django模板,你可以使用諸如url之類的模板標(biāo)記來反向查詢URL名稱,并配合使用條件、變量、日期格式和所有其他Django模板特性。這種方法本質(zhì)上是使用Django模板作為Markdown文檔的預(yù)處理程序。
我個(gè)人認(rèn)為這可能不是非技術(shù)作家的最佳解決方案。另外,我擔(dān)心提供對(duì)Django模板標(biāo)記的訪問可能是危險(xiǎn)的。
對(duì)這個(gè)問題有了更好的理解之后,我們準(zhǔn)備在Python中更深入地研究Markdown。
要在Python中開始使用Markdown,我們先安裝markdown包:
接著,創(chuàng)建一個(gè)Markdown對(duì)象并使用其函數(shù)將一些Markdown轉(zhuǎn)換成HTML:
你現(xiàn)在可以在你的模板中使用這個(gè)HTML代碼片段。
基本的Markdown處理器提供了生成HTML內(nèi)容的基本要素。對(duì)于更“新奇”的選項(xiàng),Python markdown包包含了一些內(nèi)置擴(kuò)展。一個(gè)流行的擴(kuò)展是“extra”擴(kuò)展,除了其他東西之外,它增加了對(duì)隔離代碼塊的支持:
為了使用我們獨(dú)特的Django功能擴(kuò)展Markdown,我們將開發(fā)自己的擴(kuò)展。
如果你查看源代碼,你將看到要將markdown轉(zhuǎn)換為HTML, Markdown會(huì)使用多種不同的處理器。一種類型的處理器是內(nèi)聯(lián)處理器。內(nèi)聯(lián)處理器會(huì)匹配特定的內(nèi)聯(lián)模式,如鏈接、反引號(hào)、粗體文本和帶下劃線的文本,并將它們轉(zhuǎn)換為HTML。
我們的Markdown擴(kuò)展的主要目的是驗(yàn)證和轉(zhuǎn)換鏈接。因此,我們最感興趣的內(nèi)聯(lián)處理器是LinkInlineProcessor。這個(gè)處理器以[Haki的網(wǎng)站](https://hakibenito.com)的形式獲取markdown ,解析它并返回一個(gè)包含鏈接和文本的元組。
為了擴(kuò)展該功能,我們擴(kuò)展了LinkInlineProcessor并創(chuàng)建了一個(gè)Markdown.Extension, 我們用它來處理鏈接:
我們來將這段代碼分解一下::
DjangoUrlExtension擴(kuò)展注冊(cè)了一個(gè)名為DjangoLinkInlineProcessor的內(nèi)聯(lián)鏈接處理器。這個(gè)處理器將取代任何其他現(xiàn)有的鏈接處理器。
內(nèi)聯(lián)處理器DjangoLinkInlineProcessor擴(kuò)展了內(nèi)置的LinkInlineProcessor,并在它處理的每個(gè)鏈接上調(diào)用clean_link函數(shù)。
clean_link函數(shù)接收一個(gè)鏈接和一個(gè)域名,并返回一個(gè)轉(zhuǎn)換后的鏈接。這就是我們要插入我們的實(shí)現(xiàn)的地方。
如何獲得網(wǎng)站域名
要識(shí)別到你自己網(wǎng)站的鏈接,你必須知道你的網(wǎng)站的域名。如果你正在使用Django的sites框架,那么你可以使用它來獲取當(dāng)前域名。
我沒有把它包含在我的實(shí)現(xiàn)中,因?yàn)槲覀儧]有使用sites框架。相反,我們?cè)贒jango設(shè)置中設(shè)置了一個(gè)變量。
獲取當(dāng)前域名的另一種方法是使用HttpRequest對(duì)象。如果內(nèi)容只在你自己的站點(diǎn)中被編輯,你可以嘗試從請(qǐng)求對(duì)象中插入站點(diǎn)域名。這可能需要對(duì)你的實(shí)現(xiàn)進(jìn)行一些更改。
要使用該擴(kuò)展,請(qǐng)?jiān)诔跏蓟粋€(gè)新的Markdown實(shí)例時(shí)添加它:
太好了,這個(gè)擴(kuò)展已經(jīng)被使用了,我們準(zhǔn)備進(jìn)入有趣的部分了!
既然我們得到了在所有鏈接上調(diào)用clean_link的擴(kuò)展,那我們可以來實(shí)現(xiàn)我們的驗(yàn)證和轉(zhuǎn)換邏輯。
要開始工作,我們將從一個(gè)簡(jiǎn)單的驗(yàn)證開始。mailto鏈接對(duì)于使用預(yù)定義的收件人地址、主題甚至消息正文打開用戶的電子郵件客戶端非常有用。
一個(gè)常見的mailto鏈接是這樣的:
這個(gè)鏈接將打開你的電子郵件客戶端,并設(shè)置成撰寫一封主題行為“我需要幫助!”的新電子郵件給“support@service.com”。
mailto鏈接不一定非要包含電子郵件地址。如果你看一看這篇文章底部的“分享”按鈕,你會(huì)發(fā)現(xiàn)像這樣的一個(gè)mailto鏈接:
這個(gè)mailto鏈接沒有包含收件人,僅包含了主題行和消息正文。
既然我們已經(jīng)很好地理解了mailto鏈接是什么樣子的,我們就可以向clean_link函數(shù)添加第一個(gè)驗(yàn)證:
為了驗(yàn)證mailto鏈接,我們向clean_link中添加了以下代碼:
檢查鏈接是否以mailto:開頭,以識(shí)別相關(guān)鏈接。
使用正則表達(dá)式將鏈接分割到它的組件。
從mailto鏈接中刪除實(shí)際的電子郵件地址,并使用Django的EmailValidator驗(yàn)證它。
注意,我們還添加了一種名為InvalidMarkdown的新異常類型。我們定義了自己的自定義異常類型,以將它與markdown本身所引發(fā)的其他錯(cuò)誤區(qū)分開來。
自定義錯(cuò)誤類
我曾經(jīng)寫過關(guān)于自定義錯(cuò)誤類的文章,為什么它們是有用的,以及你什么時(shí)候應(yīng)該使用它們。
在我們繼續(xù)之前,讓我們添加一些測(cè)試,看看它的實(shí)際效果:
太棒了!按預(yù)期的運(yùn)行了。
既然我們已經(jīng)了解了mailto鏈接,我們也可以處理其他類型的鏈接:
外部鏈接
我們的Django應(yīng)用程序外部的鏈接。
必須包含一個(gè)頁面跳轉(zhuǎn)協(xié)議(scheme):http或https。
理想情況下,我們還希望確保這些鏈接沒有被破壞,但我們現(xiàn)在不會(huì)這樣做。
內(nèi)部鏈接
到我們的Django應(yīng)用程序中的頁面的鏈接。
鏈接必須是相對(duì)的:這將允許我們?cè)诓煌h(huán)境之間移動(dòng)內(nèi)容。
使用Django的URL名稱而不是一個(gè)URL路徑:這將允許我們安全地來回移動(dòng)視圖,而不必?fù)?dān)心markdown內(nèi)容中的失效鏈接。
鏈接可能包含查詢參數(shù)(?)和片段(#)。
SEO
從SEO的角度來看,公共URL不應(yīng)該改變。當(dāng)他們這樣做的時(shí)候,你應(yīng)該使用重定向正確地處理它,否則你可能會(huì)受到搜索引擎的懲罰。
有了這個(gè)需求列表,我們就可以開始工作了。
解析URL名稱
要鏈接到內(nèi)部頁面,我們希望編寫者提供一個(gè)URL名稱,而不是URL路徑。例如,假設(shè)我們有這個(gè)視圖:
這個(gè)頁面的URL路徑是https://example.com/, URL名稱是home。我們想要在我們的markdown鏈接中使用這個(gè)URL名稱home,就像這樣:
這將渲染到:
我們還想支持查詢參數(shù)和散列:
這將渲染到以下HTML:
在使用URL名稱時(shí),如果我們更改了URL路徑,內(nèi)容中的鏈接將不會(huì)被破壞。要檢查作者提供的href是否是一個(gè)有效的url_name,我們可以嘗試reverse它:
URL名稱“home”指向URL路徑“/”。當(dāng)沒有匹配項(xiàng)時(shí),將會(huì)引發(fā)一個(gè)異常:
在我們繼續(xù)之前,當(dāng)URL名稱包含查詢參數(shù)或散列時(shí),會(huì)發(fā)生什么:
這是有意義的,因?yàn)椴樵儏?shù)和散列不是URL名稱的一部分。
要使用reverse并支持查詢參數(shù)和散列,我們首先需要清除值。然后,檢查它是一個(gè)有效的URL名稱,并返回包含查詢參數(shù)和散列的URL路徑,如果提供了的話:
這個(gè)代碼段使用一個(gè)正則表達(dá)式來以?或#的出現(xiàn)對(duì)href進(jìn)行分割,并返回各部分。
請(qǐng)確保它可以工作:
太了不起了!作者們現(xiàn)在可以在Markdown中使用URL名稱了。它們還可以包括要添加到該URL的查詢參數(shù)和片段。
處理外部鏈接
要正確處理外部鏈接,我們需要檢查兩件事:
1.外部鏈接總是提供一個(gè)跳轉(zhuǎn)協(xié)議,http:或者h(yuǎn)ttps:。
2.阻止到我們自己網(wǎng)站的絕對(duì)鏈接。內(nèi)部鏈接應(yīng)該使用URL名稱。
到目前為止,我們已經(jīng)處理了URL名稱和mailto鏈接。如果我們通過了這兩個(gè)檢查,這意味著href是一個(gè)URL。讓我們從檢查鏈接是否是鏈接到我們自己的網(wǎng)站開始:
函數(shù)urlparse會(huì)返回一個(gè)命名元組,該元組包含URL的不同部分。如果netloc屬性等于site_domain,那么該鏈接就確實(shí)是一個(gè)內(nèi)部鏈接。
如果URL實(shí)際上是內(nèi)部的,我們就需要終止。但是,請(qǐng)記住,作者們不一定是技術(shù)人員,因此我們希望幫助他們,并提供一個(gè)有用的錯(cuò)誤消息。我們要求該內(nèi)部鏈接使用URL名稱而不是URL路徑,所以最好讓作者們知道他們提供的路徑的URL名稱。
要獲得一個(gè)URL路徑的URL名稱,Django為我們提供了一個(gè)名為resolve的函數(shù):
當(dāng)找到匹配項(xiàng)時(shí),resolve會(huì)返回一個(gè)ResolverMatch對(duì)象,其中包含URL名稱和其他信息。當(dāng)沒有找到匹配項(xiàng)時(shí),它就會(huì)引發(fā)一個(gè)錯(cuò)誤:
這實(shí)際上就是Django在底層所做的工作,用來確定在一個(gè)新請(qǐng)求到來時(shí)執(zhí)行哪個(gè)視圖函數(shù)。
為了給作者們提供更好的錯(cuò)誤信息,我們可以使用來自ResolverMatch對(duì)象的URL名稱:
當(dāng)我們識(shí)別出內(nèi)部鏈接時(shí),我們要處理兩種情況:
我們沒有識(shí)別出這個(gè)URL:這個(gè)URL很可能是不正確的。請(qǐng)作者檢查該URL是否有錯(cuò)誤。
我們識(shí)別出了這個(gè)URL: 這個(gè)URL是正確的,所以就告訴作者應(yīng)該使用什么URL名稱。
我們來實(shí)際地看一下它:
漂亮!外部鏈接被接受,內(nèi)部鏈接被拒絕,并帶有一個(gè)有用的消息。
要求跳轉(zhuǎn)協(xié)議
我們要做的最后一件事是確保外部鏈接包含一個(gè)跳轉(zhuǎn)協(xié)議,要么是http:,要么是https:。讓我們將這最后一部分添加到函數(shù)clean_link:
使用解析后的URL,我們可以很容易地檢查跳轉(zhuǎn)協(xié)議。讓我們確保它正在工作:
我們向這個(gè)函數(shù)提供了一個(gè)沒有跳轉(zhuǎn)協(xié)議的鏈接,但是它運(yùn)行失敗了,并顯示了一條有用的消息。太酷了!
這是clean_link函數(shù)的全部代碼:
要了解所有這些特性的一個(gè)實(shí)際用例是什么樣子的,請(qǐng)看下面的內(nèi)容:
這將產(chǎn)生以下HTML:
不錯(cuò)!
我們現(xiàn)在有一個(gè)很不錯(cuò)的擴(kuò)展,它可以驗(yàn)證和轉(zhuǎn)換Markdown文檔中的鏈接!現(xiàn)在,在不同環(huán)境之間移動(dòng)文檔和保持內(nèi)容整潔要容易多了,最重要的是,可以保持正確和最新!
源碼
你可以在這個(gè)gist中找到全部源代碼。(地址:https://gist.github.com/hakib/73fccc340e855bb65f42197e298c0c7d )
本文中所描述的功能對(duì)我們很有用,但是你可能需要根據(jù)自己的需求對(duì)它進(jìn)行調(diào)整。
如果你需要一些想法,那么除了這個(gè)擴(kuò)展之外,我們還創(chuàng)建了一個(gè)markdown Preprocessor,它允許作者們?cè)趍arkdown中使用常量。例如,我們定義了一個(gè)名為SUPPORT_EMAIL的常量,我們像這樣使用它:
該預(yù)處理程序?qū)⒂梦覀兌x的文本替換字符串$SUPPORT_EMAIL,然后才渲染Markdown。
英文原文:https://hakibenita.com/django-markdown
譯者:Nothing
JavaScript 提供了許多方法來檢索和更改顯示在瀏覽器地址欄中的當(dāng)前 URL,所有這些方法都使用Location對(duì)象,它是對(duì)象的一個(gè)?屬性Window。
您可以創(chuàng)建一個(gè)具有當(dāng)前URL的新對(duì)象,如下所示:
let loc = window.location;
let url = loc.href;
location屬性
Location 接口不繼承任何屬性,但是實(shí)現(xiàn)了那些來自 URLUtils 的屬性。
Location.href包含整個(gè)URL的一個(gè)DOMStringLocation.protocol包含URL對(duì)應(yīng)協(xié)議的一個(gè)DOMString,最后有一個(gè)":"。
Location.host包含了域名的一個(gè)DOMString,可能在該串最后帶有一個(gè)":"并跟上URL的端口號(hào)。
Location.hostname包含URL域名的一個(gè)DOMString。
Location.port包含端口號(hào)的一個(gè)DOMString。
Location.pathname包含URL中路徑部分的一個(gè)DOMString,開頭有一個(gè)“/"。Location.search 包含URL參數(shù)的一個(gè)DOMString,開頭有一個(gè)“?”。
Location.hash包含塊標(biāo)識(shí)符的DOMString,開頭有一個(gè)“#”。
Location.username包含URL中域名前的用戶名的一個(gè)DOMString。
Location.password包含URL域名前的密碼的一個(gè) DOMString。
Location.origin只讀包含頁面來源的域名的標(biāo)準(zhǔn)形式DOMString。
Location沒有繼承任何方法,但實(shí)現(xiàn)了來自URLUtils的方法。
Location.assign()加載給定URL的內(nèi)容資源到這個(gè)Location對(duì)象所關(guān)聯(lián)的對(duì)象上。
Location.reload()重新加載來自當(dāng)前 URL的資源。他有一個(gè)特殊的可選參數(shù),類型為 Boolean,該參數(shù)為true時(shí)會(huì)導(dǎo)致該方法引發(fā)的刷新一定會(huì)從服務(wù)器上加載數(shù)據(jù)。如果是 false或沒有制定這個(gè)參數(shù),瀏覽器可能從緩存當(dāng)中加載頁面。
Location.replace()用給定的URL替換掉當(dāng)前的資源。與 assign() 方法不同的是用 replace()替換的新頁面不會(huì)被保存在會(huì)話的歷史 History中,這意味著用戶將不能用后退按鈕轉(zhuǎn)到該頁面。
Location.toString()返回一個(gè)DOMString,包含整個(gè)URL。 它和讀取URLUtils.href的效果相同。但是用它是不能夠修改Location的值的。
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。