ASP Classic blog framework - BrainOrdure
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

850 строки
27KB

  1. <%
  2. Function QuoteValue(val)
  3. if IsWrappedInSingleQuotes(val) then
  4. QuoteValue = val
  5. Exit Function
  6. end if
  7. Select Case VarType(val)
  8. Case vbString
  9. QuoteValue = "'" & Replace(val, "'", "''") & "'"
  10. Case vbDate
  11. if conn.Provider = "Microsoft.Jet.OLEDB.4.0" or conn.Provider = "Microsoft.ACE.OLEDB.12.0" then
  12. QuoteValue = "#" & FormatDateTime(val, 0) & "#"
  13. else
  14. ' SQL Server
  15. QuoteValue = "'" & FormatDateTime(val, 0) & "'"
  16. end if
  17. Case vbNull, vbEmpty
  18. QuoteValue = "Null"
  19. Case vbBoolean
  20. ' Return boolean values without quotes
  21. QuoteValue = "'" & CStr(val) & "'"
  22. Case Else
  23. If IsNumeric(val) Then
  24. QuoteValue = CLng(val)
  25. Else
  26. QuoteValue = CStr(val)
  27. End If
  28. End Select
  29. End Function
  30. Public Function GetAppSetting(key)
  31. Dim cacheKey, xml, nodes, node, i
  32. cacheKey = "AppSetting_" & key
  33. ' Check Application cache first for performance
  34. If Not IsEmpty(Application(cacheKey)) Then
  35. GetAppSetting = Application(cacheKey)
  36. Exit Function
  37. End If
  38. ' Load from web.config only if not cached
  39. Set xml = Server.CreateObject("Microsoft.XMLDOM")
  40. xml.Load(Server.MapPath("web.config"))
  41. Set nodes = xml.selectNodes("//appSettings/add")
  42. For i = 0 To nodes.Length - 1
  43. Set node = nodes.Item(i)
  44. If node.getAttribute("key") = key Then
  45. GetAppSetting = node.getAttribute("value")
  46. ' Cache the value for subsequent requests
  47. Application.Lock
  48. Application(cacheKey) = GetAppSetting
  49. Application.Unlock
  50. Exit Function
  51. End If
  52. Next
  53. GetAppSetting = "nothing"
  54. End Function
  55. Public Function GetEnvironmentValue(name)
  56. Dim shell, env, value
  57. value = ""
  58. On Error Resume Next
  59. Set shell = Server.CreateObject("WScript.Shell")
  60. Set env = shell.Environment("PROCESS")
  61. If Err.Number = 0 Then
  62. value = env(name)
  63. If Err.Number <> 0 Then
  64. Err.Clear
  65. value = ""
  66. End If
  67. Else
  68. Err.Clear
  69. End If
  70. On Error GoTo 0
  71. GetEnvironmentValue = Trim(CStr(value))
  72. End Function
  73. Public Function GetSecureSetting(key, envName)
  74. Dim value, envValue
  75. value = Trim(CStr(GetAppSetting(key)))
  76. If Len(value) > 0 And LCase(value) <> "nothing" Then
  77. GetSecureSetting = value
  78. Exit Function
  79. End If
  80. envValue = Trim(CStr(GetEnvironmentValue(envName)))
  81. If Len(envValue) > 0 Then
  82. On Error Resume Next
  83. UpdateAppSetting key, envValue
  84. Err.Clear
  85. On Error GoTo 0
  86. GetSecureSetting = envValue
  87. Exit Function
  88. End If
  89. GetSecureSetting = ""
  90. End Function
  91. Public Function GetGenerationPromptTemplate()
  92. Dim prompt
  93. prompt = Trim(CStr(GetAppSetting("AbacusGenerationPrompt")))
  94. If Len(prompt) = 0 Or LCase(prompt) = "nothing" Then
  95. prompt = "You write clear, engaging blog post content for a classic ASP blog. Return only valid JSON with two keys: summary and body. Summary must be 1 to 2 sentences. Body must be 3 to 5 short paragraphs separated by blank lines. Do not use markdown fences, bullets, or code blocks." & vbCrLf & vbCrLf & _
  96. "Create blog content for this post title: {TITLE}" & vbCrLf & _
  97. "Existing summary: {SUMMARY}" & vbCrLf & _
  98. "Existing body: {BODY}" & vbCrLf & _
  99. "Keep the title unchanged. Make the content readable and helpful for a general audience."
  100. End If
  101. GetGenerationPromptTemplate = prompt
  102. End Function
  103. Public Function BuildGenerationPrompt(ByRef post)
  104. Dim template
  105. template = GetGenerationPromptTemplate()
  106. template = Replace(template, "{TITLE}", SafePromptText(post.Title))
  107. template = Replace(template, "{SUMMARY}", SafePromptText(post.Summary))
  108. template = Replace(template, "{BODY}", SafePromptText(post.Body))
  109. BuildGenerationPrompt = template
  110. End Function
  111. Public Function SafePromptText(ByVal value)
  112. If IsNull(value) Or IsEmpty(value) Then
  113. SafePromptText = ""
  114. Else
  115. SafePromptText = CStr(value)
  116. End If
  117. End Function
  118. Public Function UpdateAppSetting(key, value)
  119. Dim xml, nodes, node, appSettings, found
  120. Set xml = Server.CreateObject("Microsoft.XMLDOM")
  121. xml.async = False
  122. xml.preserveWhiteSpace = True
  123. xml.Load Server.MapPath("web.config")
  124. If xml.parseError.errorCode <> 0 Then
  125. Err.Raise 1, "UpdateAppSetting", "Unable to load web.config: " & xml.parseError.reason
  126. End If
  127. Set nodes = xml.selectNodes("//appSettings/add[@key='" & key & "']")
  128. found = False
  129. If Not (nodes Is Nothing) Then
  130. If nodes.Length > 0 Then
  131. Set node = nodes.Item(0)
  132. node.setAttribute "value", value
  133. found = True
  134. End If
  135. End If
  136. If Not found Then
  137. Set appSettings = xml.selectSingleNode("//appSettings")
  138. If appSettings Is Nothing Then
  139. Err.Raise 1, "UpdateAppSetting", "<appSettings> section not found in web.config."
  140. End If
  141. Set node = xml.createElement("add")
  142. node.setAttribute "key", key
  143. node.setAttribute "value", value
  144. appSettings.appendChild node
  145. End If
  146. xml.Save Server.MapPath("web.config")
  147. Application.Contents.Remove("AppSetting_" & key)
  148. UpdateAppSetting = True
  149. End Function
  150. Public Sub ShowServerVariables
  151. Dim varName, htmlTable
  152. htmlTable = "<table border='1' cellspacing='0' cellpadding='5'>"
  153. htmlTable = htmlTable & "<thead><tr><th>Variable Name</th><th>Value</th></tr></thead><tbody>"
  154. ' Loop through all server variables
  155. For Each varName In Request.ServerVariables
  156. htmlTable = htmlTable & "<tr>"
  157. htmlTable = htmlTable & "<td>" & Server.HTMLEncode(varName) & "</td>"
  158. htmlTable = htmlTable & "<td>" & Server.HTMLEncode(Request.ServerVariables(varName)) & "</td>"
  159. htmlTable = htmlTable & "</tr>"
  160. Next
  161. htmlTable = htmlTable & "</tbody></table>"
  162. ' Output the HTML table
  163. Response.Write(htmlTable)
  164. End Sub
  165. '------------------------------------------------------------------------------
  166. ' Utility: IIf Function for VBScript
  167. ' Usage: result = IIf(condition, trueValue, falseValue)
  168. '------------------------------------------------------------------------------
  169. Function IIf(condition, trueValue, falseValue)
  170. On Error Resume Next
  171. If CBool(condition) Then
  172. IIf = trueValue
  173. Else
  174. IIf = falseValue
  175. End If
  176. If Err.Number <> 0 Then
  177. ' Optional: handle or log error in conversion/evaluation
  178. Err.Clear
  179. End If
  180. On Error GoTo 0
  181. End Function
  182. '-----------------------------
  183. ' Utility: Generic Error Reporter
  184. '-----------------------------
  185. Public Sub ErrorCheck(context)
  186. If Err.Number <> 0 Then
  187. Dim errHtml
  188. errHtml = "<div style='padding:10px; border:2px solid red; background:#fdd; font-family:Verdana; font-size:12px;'>"
  189. errHtml = errHtml & "<strong>Error occurred" & IIf(Not IsEmpty(context) And context <> "", ": " & context, "") & "</strong><br />"
  190. errHtml = errHtml & "<em>Time:</em> " & Now() & "<br />"
  191. errHtml = errHtml & "<em>Number:</em> " & Err.Number & "<br />"
  192. errHtml = errHtml & "<em>Description:</em> " & Server.HTMLEncode(Err.Description) & "<br />"
  193. If Len(Err.Source) > 0 Then
  194. errHtml = errHtml & "<em>Source:</em> " & Server.HTMLEncode(Err.Source) & "<br />"
  195. End If
  196. errHtml = errHtml & "</div>"
  197. Response.Write errHtml
  198. Err.Clear
  199. End If
  200. End Sub
  201. '------------------------------------------------------------------------------
  202. ' Utility: TrimQueryParams
  203. ' Removes everything from the first "?" or "&" onward.
  204. ' Usage:
  205. ' CleanPath = TrimQueryParams(rawPath)
  206. '------------------------------------------------------------------------------
  207. Function TrimQueryParams(rawPath)
  208. Dim posQ, posA, cutPos
  209. ' find the first occurrences of "?" and "&"
  210. posQ = InStr(rawPath, "?")
  211. posA = InStr(rawPath, "&")
  212. ' determine the earliest cut position (>0)
  213. If posQ > 0 And posA > 0 Then
  214. cutPos = IIf(posQ < posA, posQ, posA)
  215. ElseIf posQ > 0 Then
  216. cutPos = posQ
  217. ElseIf posA > 0 Then
  218. cutPos = posA
  219. Else
  220. cutPos = 0
  221. End If
  222. ' if found, return up to just before that char
  223. If cutPos > 0 Then
  224. TrimQueryParams = Left(rawPath, cutPos - 1)
  225. Else
  226. TrimQueryParams = rawPath
  227. End If
  228. End Function
  229. Function DecodeUrlPath(ByVal rawPath)
  230. Dim current, previous
  231. current = Trim(CStr(rawPath))
  232. On Error Resume Next
  233. Do
  234. previous = current
  235. current = Server.URLDecode(current)
  236. If Err.Number <> 0 Then
  237. Err.Clear
  238. current = previous
  239. Exit Do
  240. End If
  241. Loop While current <> previous
  242. On Error GoTo 0
  243. current = Replace(current, "%252D", "-")
  244. current = Replace(current, "%252d", "-")
  245. current = Replace(current, "%2D", "-")
  246. current = Replace(current, "%2d", "-")
  247. current = Replace(current, "%25", "%")
  248. DecodeUrlPath = current
  249. End Function
  250. Sub Destroy(o)
  251. if isobject(o) then
  252. if not o is nothing then
  253. on error resume next
  254. o.close
  255. on error goto 0
  256. set o = nothing
  257. end if
  258. end if
  259. End Sub
  260. 'prepends indents
  261. Private Sub puti(v)
  262. put Spaces(m_indent) & v
  263. End Sub
  264. Sub put(v)
  265. Select Case typename(v)
  266. Case "LinkedList_Class" : response.write join(v.TO_Array, ", ")
  267. Case "DynamicArray_Class" : response.write JoinList(v)
  268. Case "Variant()" : response.write join(v, ", ")
  269. Case else : response.write v
  270. End Select
  271. End Sub
  272. Sub put_
  273. put "<br>"
  274. End Sub
  275. Sub putl(v)
  276. put v
  277. put_
  278. End Sub
  279. '---------------------------------------------------------------------------------------------------------------------
  280. 'Wrapper for Server.HTMLEncode() -- makes it easier on the eyes when reading the HTML code
  281. Function H(s)
  282. If Not IsEmpty(s) and Not IsNull(s) then
  283. H = Server.HTMLEncode(s)
  284. Else
  285. H = ""
  286. End If
  287. End Function
  288. Function RenderPostBody(ByVal body)
  289. Dim raw
  290. If IsNull(body) Or IsEmpty(body) Then
  291. RenderPostBody = ""
  292. Exit Function
  293. End If
  294. raw = CStr(body)
  295. If IsHtmlPostBody(raw) Then
  296. RenderPostBody = raw
  297. Else
  298. raw = Server.HTMLEncode(raw)
  299. raw = Replace(raw, vbCrLf, "<br>")
  300. raw = Replace(raw, vbCr, "<br>")
  301. raw = Replace(raw, vbLf, "<br>")
  302. RenderPostBody = raw
  303. End If
  304. End Function
  305. Function IsHtmlPostBody(ByVal text)
  306. Dim lowerText
  307. lowerText = LCase(CStr(text))
  308. IsHtmlPostBody = _
  309. (InStr(lowerText, "<p") > 0) Or _
  310. (InStr(lowerText, "<div") > 0) Or _
  311. (InStr(lowerText, "<br") > 0) Or _
  312. (InStr(lowerText, "<strong") > 0) Or _
  313. (InStr(lowerText, "<em") > 0) Or _
  314. (InStr(lowerText, "<ul") > 0) Or _
  315. (InStr(lowerText, "<ol") > 0) Or _
  316. (InStr(lowerText, "<li") > 0) Or _
  317. (InStr(lowerText, "<a ") > 0) Or _
  318. (InStr(lowerText, "<img") > 0) Or _
  319. (InStr(lowerText, "<blockquote") > 0) Or _
  320. (InStr(lowerText, "<h1") > 0) Or _
  321. (InStr(lowerText, "<h2") > 0) Or _
  322. (InStr(lowerText, "<h3") > 0) Or _
  323. (InStr(lowerText, "<h4") > 0) Or _
  324. (InStr(lowerText, "<h5") > 0) Or _
  325. (InStr(lowerText, "<h6") > 0) Or _
  326. (InStr(lowerText, "<code") > 0) Or _
  327. (InStr(lowerText, "<pre") > 0)
  328. End Function
  329. Function AiImageUrl(ByVal prompt)
  330. AiImageUrl = "https://gen.pollinations.ai/image/" & Server.URLEncode(Trim(CStr(prompt)))
  331. End Function
  332. '------------------------------------------------------------------------------
  333. ' Canonical application URL helpers
  334. ' - Categories use numeric IDs
  335. ' - Posts use slug permalinks for public links and numeric IDs for admin actions
  336. '------------------------------------------------------------------------------
  337. Function CategoryUrl(ByVal categoryId)
  338. CategoryUrl = "/categories/" & Server.URLEncode(CStr(categoryId))
  339. End Function
  340. Function CategoriesUrl()
  341. CategoriesUrl = "/categories"
  342. End Function
  343. Function CategoryNewUrl()
  344. CategoryNewUrl = "/categories/new"
  345. End Function
  346. Function CategoryEditUrl(ByVal categoryId)
  347. CategoryEditUrl = CategoryUrl(categoryId) & "/edit"
  348. End Function
  349. Function CategoryDeleteUrl(ByVal categoryId)
  350. CategoryDeleteUrl = CategoryUrl(categoryId) & "/delete"
  351. End Function
  352. Function PostUrl(ByVal slug)
  353. PostUrl = "/posts/" & Server.URLEncode(NormalizeSlug(slug))
  354. End Function
  355. Function PostPath(ByVal slug)
  356. PostPath = "/posts/" & NormalizeSlug(slug)
  357. End Function
  358. Function PostsUrl()
  359. PostsUrl = "/posts"
  360. End Function
  361. Function PostNewUrl()
  362. PostNewUrl = "/posts/new"
  363. End Function
  364. Function PostEditUrl(ByVal postId)
  365. PostEditUrl = "/posts/" & Server.URLEncode(CStr(postId)) & "/edit"
  366. End Function
  367. Function PostUpdateUrl(ByVal postId)
  368. PostUpdateUrl = "/posts/" & Server.URLEncode(CStr(postId))
  369. End Function
  370. Function PostDeleteUrl(ByVal postId)
  371. PostDeleteUrl = "/posts/" & Server.URLEncode(CStr(postId)) & "/delete"
  372. End Function
  373. Function AdminPostPublishUrl(ByVal postId)
  374. AdminPostPublishUrl = "/admin/posts/" & Server.URLEncode(CStr(postId)) & "/publish"
  375. End Function
  376. Function AdminPostUnpublishUrl(ByVal postId)
  377. AdminPostUnpublishUrl = "/admin/posts/" & Server.URLEncode(CStr(postId)) & "/unpublish"
  378. End Function
  379. Function AdminPostAIUrl(ByVal postId)
  380. AdminPostAIUrl = "/admin/posts/" & Server.URLEncode(CStr(postId)) & "/ai"
  381. End Function
  382. Function AdminCommentsUrl()
  383. AdminCommentsUrl = "/admin/comments"
  384. End Function
  385. Function AdminCommentApproveUrl(ByVal commentId)
  386. AdminCommentApproveUrl = "/admin/comments/" & Server.URLEncode(CStr(commentId)) & "/approve"
  387. End Function
  388. Function AdminCommentUnapproveUrl(ByVal commentId)
  389. AdminCommentUnapproveUrl = "/admin/comments/" & Server.URLEncode(CStr(commentId)) & "/unapprove"
  390. End Function
  391. Function AdminCommentDeleteUrl(ByVal commentId)
  392. AdminCommentDeleteUrl = "/admin/comments/" & Server.URLEncode(CStr(commentId)) & "/delete"
  393. End Function
  394. Function AdminAIPromptUrl()
  395. AdminAIPromptUrl = "/admin/ai-prompt"
  396. End Function
  397. Function AdminAIPromptUpdateUrl()
  398. AdminAIPromptUpdateUrl = "/admin/ai-prompt"
  399. End Function
  400. Function AdminUrl()
  401. AdminUrl = "/admin"
  402. End Function
  403. Function CommentsUrl()
  404. CommentsUrl = "/comments"
  405. End Function
  406. Function NormalizeSlug(ByVal slug)
  407. Dim current, previous
  408. current = Trim(CStr(slug))
  409. If Len(current) = 0 Then
  410. NormalizeSlug = ""
  411. Exit Function
  412. End If
  413. On Error Resume Next
  414. Do
  415. previous = current
  416. current = Server.URLDecode(current)
  417. If Err.Number <> 0 Then
  418. Err.Clear
  419. current = previous
  420. Exit Do
  421. End If
  422. Loop While current <> previous
  423. On Error GoTo 0
  424. current = Replace(current, "%252D", "-")
  425. current = Replace(current, "%252d", "-")
  426. current = Replace(current, "%2D", "-")
  427. current = Replace(current, "%2d", "-")
  428. current = Replace(current, "%25", "%")
  429. NormalizeSlug = current
  430. End Function
  431. '=======================================================================================================================
  432. ' Adapted from Tolerable library
  433. '=======================================================================================================================
  434. ' This subroutine allows us to ignore the difference
  435. ' between object and primitive assignments. This is
  436. ' essential for many parts of the engine.
  437. Public Sub Assign(ByRef var, ByVal val)
  438. If IsObject(val) Then
  439. Set var = val
  440. Else
  441. var = val
  442. End If
  443. End Sub
  444. ' This is similar to the ? : operator of other languages.
  445. ' Unfortunately, both the if_true and if_false "branches"
  446. ' will be evalauted before the condition is even checked. So,
  447. ' you'll only want to use this for simple expressions.
  448. Public Function Choice(ByVal cond, ByVal if_true, ByVal if_false)
  449. If cond Then
  450. Assign Choice, if_true
  451. Else
  452. Assign Choice, if_false
  453. End If
  454. End Function
  455. ' Allows single-quotes to be used in place of double-quotes.
  456. ' Basically, this is a cheap trick that can make it easier
  457. ' to specify Lambdas.
  458. Public Function Q(ByVal input)
  459. Q = Replace(input, "'", """")
  460. End Function
  461. Function SurroundString(inputVar)
  462. If VarType(inputVar) = vbString Then
  463. SurroundString = """" & inputVar & """"
  464. Else
  465. SurroundString = inputVar
  466. End If
  467. End Function
  468. Function SurroundStringInArray(arr)
  469. Dim i
  470. For i = LBound(arr) To UBound(arr)
  471. If IsString(arr(i)) Then
  472. arr(i) = """" & arr(i) & """"
  473. End If
  474. Next
  475. SurroundStringInArray = arr
  476. End Function
  477. '-----------------------------------------------------------------------------------------------------------------------
  478. 'Boolean type checkers
  479. 'Don't forget IsArray is built-in!
  480. Function IsString(value)
  481. IsString = Choice(typename(value) = "String", true, false)
  482. End Function
  483. Function IsDict(value)
  484. IsDict = Choice(typename(value) = "Dictionary", true, false)
  485. End Function
  486. Function IsRecordset(value)
  487. IsRecordset = Choice(typename(value) = "Recordset", true, false)
  488. End Function
  489. Function IsLinkedList(value)
  490. IsLinkedList = Choice(typename(value) = "LinkedList_Class", true, false)
  491. End Function
  492. Function IsArray(value)
  493. IsArray = Choice(typename(value) = "Variant()", true, false)
  494. End Function
  495. '--------------------------------------------------------------------
  496. ' Returns True when the named key is present in Session.Contents
  497. ' • Handles scalars (String, Integer, etc.), objects, Empty, and Null
  498. '--------------------------------------------------------------------
  499. Function SessionHasKey(keyName)
  500. 'Loop over the existing keys—Session.Contents is like a dictionary
  501. Dim k
  502. For Each k In Session.Contents
  503. If StrComp(k, keyName, vbTextCompare) = 0 Then
  504. SessionHasKey = True
  505. Exit Function
  506. End If
  507. Next
  508. SessionHasKey = False 'not found
  509. End Function
  510. Function RenderObjectsAsTable(arr,boolUseTabulator)
  511. Dim html, propNames, i, j, obj, val, pkName, isPk
  512. If IsEmpty(arr) Or Not IsArray(arr) Then
  513. RenderObjectsAsTable = "<!-- no data -->"
  514. Exit Function
  515. End If
  516. Set obj = arr(0)
  517. On Error Resume Next
  518. propNames = obj.Properties
  519. pkName = obj.PrimaryKey
  520. On Error GoTo 0
  521. If IsEmpty(propNames) Or Len(pkName) = 0 Then
  522. RenderObjectsAsTable = "<!-- missing properties or primary key -->"
  523. Exit Function
  524. End If
  525. html = "<div class='table-wrapper'>" & vbCrLf
  526. html = html & "<table class='pobo-table' id='pobo-table'>" & vbCrLf
  527. html = html & " <thead><tr>" & vbCrLf
  528. For i = 0 To UBound(propNames)
  529. html = html & " <th>" & Server.HTMLEncode(propNames(i)) & "</th>" & vbCrLf
  530. Next
  531. html = html & " </tr></thead>" & vbCrLf
  532. html = html & " <tbody>" & vbCrLf
  533. For j = 0 To UBound(arr)
  534. Set obj = arr(j)
  535. html = html & " <tr>" & vbCrLf
  536. For i = 0 To UBound(propNames)
  537. val = GetDynamicProperty(obj, propNames(i))
  538. isPk = (StrComp(propNames(i), pkName, vbTextCompare) = 0)
  539. If IsNull(val) Or IsEmpty(val) Then
  540. val = "&nbsp;"
  541. ElseIf IsDate(val) Then
  542. val = FormatDateTime(val, vbShortDate)
  543. ElseIf VarType(val) = vbBoolean Then
  544. val = IIf(val, "True", "False")
  545. Else
  546. val = CStr(val)
  547. Dim maxLen : maxLen = CInt(GetAppSetting("TableCellMaxLength"))
  548. If maxLen <= 0 Then maxLen = 90
  549. If Len(val) > maxLen Then
  550. val = Left(val, maxLen - 3) & "..."
  551. End If
  552. val = Server.HTMLEncode(val)
  553. End If
  554. If isPk and boolUseTabulator = False Then
  555. val = "<a href=""" & obj.Tablename & "/edit/" & GetDynamicProperty(obj, pkName) & """ class=""table-link"">" & val & "</a>"
  556. End If
  557. html = html & " <td>" & val & "</td>" & vbCrLf
  558. Next
  559. html = html & " </tr>" & vbCrLf
  560. Next
  561. html = html & " </tbody>" & vbCrLf & "</table>" & vbCrLf & "</div>"
  562. RenderObjectsAsTable = html
  563. End Function
  564. Function RenderFormFromObject(obj)
  565. Dim html, propNames, i, name, val, inputType
  566. Dim pkName, tableName, checkedAttr
  567. On Error Resume Next
  568. propNames = obj.Properties
  569. pkName = obj.PrimaryKey
  570. tableName = obj.TableName
  571. On Error GoTo 0
  572. If IsEmpty(propNames) Or Len(pkName) = 0 Then
  573. RenderFormFromObject = "<!-- Invalid object -->"
  574. Exit Function
  575. End If
  576. html = "<form method='post' action='/" & tableName & "/save' class='article-content'>" & vbCrLf
  577. For i = 0 To UBound(propNames)
  578. name = propNames(i)
  579. val = GetDynamicProperty(obj, name)
  580. ' Handle nulls
  581. If IsNull(val) Then val = ""
  582. ' Primary key → hidden input
  583. If StrComp(name, pkName, vbTextCompare) = 0 Then
  584. html = html & " <input type='hidden' name='" & name & "' value='" & Server.HTMLEncode(val) & "' />" & vbCrLf
  585. 'Continue For
  586. End If
  587. html = html & " <div class='form-group'>" & vbCrLf
  588. html = html & " <label for='" & name & "'>" & name & "</label>" & vbCrLf
  589. Select Case True
  590. Case VarType(val) = vbBoolean
  591. checkedAttr = ""
  592. If val = True Then checkedAttr = " checked"
  593. html = html & " <input type='checkbox' class='form-check-input' name='" & name & "' id='" & name & "' value='true'" & checkedAttr & " />" & vbCrLf
  594. Case IsDate(val)
  595. html = html & " <input type='date' class='form-control' name='" & name & "' id='" & name & "' value='" & FormatDateForInput(val) & "' />" & vbCrLf
  596. Case IsNumeric(val)
  597. html = html & " <input type='number' class='form-control' name='" & name & "' id='" & name & "' value='" & val & "' />" & vbCrLf
  598. Case Len(val) > CInt(GetAppSetting("FormTextareaThreshold"))
  599. html = html & " <textarea class='form-control' name='" & name & "' id='" & name & "' rows='6'>" & Server.HTMLEncode(val) & "</textarea>" & vbCrLf
  600. Case Else
  601. html = html & " <input type='text' class='form-control' name='" & name & "' id='" & name & "' value='" & Server.HTMLEncode(val) & "' />" & vbCrLf
  602. End Select
  603. html = html & " </div>" & vbCrLf
  604. Next
  605. html = html & " <button type='submit' class='btn btn-primary btn-lg'>Save</button>" & vbCrLf
  606. html = html & "</form>" & vbCrLf
  607. RenderFormFromObject = html
  608. End Function
  609. Function GetDynamicProperty(obj, propName)
  610. On Error Resume Next
  611. Dim result
  612. Execute "result = obj." & propName
  613. If Err.Number <> 0 Then
  614. result = ""
  615. Err.Clear
  616. End If
  617. GetDynamicProperty = result
  618. On Error GoTo 0
  619. End Function
  620. Function FormatDateForInput(val)
  621. If IsDate(val) Then
  622. Dim yyyy, mm, dd
  623. yyyy = Year(val)
  624. mm = Right("0" & Month(val), 2)
  625. dd = Right("0" & Day(val), 2)
  626. FormatDateForInput = yyyy & "-" & mm & "-" & dd
  627. Else
  628. FormatDateForInput = ""
  629. End If
  630. End Function
  631. '-------------------------------------------------------------
  632. ' Returns obj.<propName> for any public VBScript class property
  633. '-------------------------------------------------------------
  634. Function GetObjProp(o, pName)
  635. Dim tmp
  636. ' Build a tiny statement like: tmp = o.UserID
  637. Execute "tmp = o." & pName
  638. GetObjProp = tmp
  639. End Function
  640. Function GenerateSlug(title)
  641. Dim slug
  642. slug = LCase(title) ' Convert to lowercase
  643. slug = Replace(slug, "&", "and") ' Replace ampersands
  644. slug = Replace(slug, "'", "") ' Remove apostrophes
  645. slug = Replace(slug, """", "") ' Remove quotes
  646. slug = Replace(slug, "–", "-") ' Replace en dash
  647. slug = Replace(slug, "—", "-") ' Replace em dash
  648. slug = Replace(slug, "/", "-") ' Replace slashes
  649. slug = Replace(slug, "\", "-") ' Replace backslashes
  650. ' Remove all non-alphanumeric and non-hyphen/space characters
  651. Dim i, ch, clean
  652. clean = ""
  653. For i = 1 To Len(slug)
  654. ch = Mid(slug, i, 1)
  655. If (ch >= "a" And ch <= "z") Or (ch >= "0" And ch <= "9") Or ch = " " Or ch = "-" Then
  656. clean = clean & ch
  657. End If
  658. Next
  659. ' Replace multiple spaces or hyphens with single hyphen
  660. Do While InStr(clean, " ") > 0
  661. clean = Replace(clean, " ", " ")
  662. Loop
  663. clean = Replace(clean, " ", "-")
  664. Do While InStr(clean, "--") > 0
  665. clean = Replace(clean, "--", "-")
  666. Loop
  667. ' Trim leading/trailing hyphens
  668. Do While Left(clean, 1) = "-"
  669. clean = Mid(clean, 2)
  670. Loop
  671. Do While Right(clean, 1) = "-"
  672. clean = Left(clean, Len(clean) - 1)
  673. Loop
  674. GenerateSlug = clean
  675. End Function
  676. Function GetRawJsonFromRequest()
  677. Dim stream, rawJson
  678. Set stream = Server.CreateObject("ADODB.Stream")
  679. stream.Type = 1 ' adTypeBinary
  680. stream.Open
  681. stream.Write Request.BinaryRead(Request.TotalBytes)
  682. stream.Position = 0
  683. stream.Type = 2 ' adTypeText
  684. stream.Charset = "utf-8"
  685. rawJson = stream.ReadText
  686. stream.Close
  687. Set stream = Nothing
  688. GetRawJsonFromRequest = rawJson
  689. End Function
  690. Function Active(controllerName)
  691. On Error Resume Next
  692. If Replace(Lcase(router.Resolve(Request.ServerVariables("REQUEST_METHOD"), TrimQueryParams(Request.ServerVariables("HTTP_X_ORIGINAL_URL")))(0)),"controller","") = LCase(controllerName) Then
  693. Active = "active"
  694. Else
  695. Active = ""
  696. End If
  697. On Error GoTo 0
  698. End Function
  699. '====================================================================
  700. ' FormatDateForSql
  701. ' Converts a VBScript Date to a SQL Server-compatible string
  702. ' Output: 'YYYY-MM-DD HH:MM:SS'
  703. '====================================================================
  704. Function FormatDateForSql(vbDate)
  705. If IsNull(vbDate) Or vbDate = "" Then
  706. FormatDateForSql = "NULL"
  707. Exit Function
  708. End If
  709. ' Ensure vbDate is a valid date
  710. If Not IsDate(vbDate) Then
  711. Err.Raise vbObjectError + 1000, "FormatDateForSql", "Invalid date: " & vbDate
  712. End If
  713. Dim yyyy, mm, dd, hh, nn, ss
  714. yyyy = Year(vbDate)
  715. mm = Right("0" & Month(vbDate), 2)
  716. dd = Right("0" & Day(vbDate), 2)
  717. hh = Right("0" & Hour(vbDate), 2)
  718. nn = Right("0" & Minute(vbDate), 2)
  719. ss = Right("0" & Second(vbDate), 2)
  720. ' Construct SQL Server datetime literal
  721. FormatDateForSql = "'" & yyyy & "-" & mm & "-" & dd & " " & hh & ":" & nn & ":" & ss & "'"
  722. End Function
  723. %>

Powered by TurnKey Linux.