Consolidated ASP Classic MVC framework from best components
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

571 lines
19KB

  1. <%
  2. Dim m_indent
  3. Function QuoteValue(val)
  4. Dim conn
  5. if IsWrappedInSingleQuotes(val) then
  6. QuoteValue = val
  7. Exit Function
  8. end if
  9. Select Case VarType(val)
  10. Case vbString
  11. QuoteValue = "'" & Replace(val, "'", "''") & "'"
  12. Case vbDate
  13. if conn.Provider = "Microsoft.Jet.OLEDB.4.0" or conn.Provider = "Microsoft.ACE.OLEDB.12.0" then
  14. QuoteValue = "#" & FormatDateTime(val, 0) & "#"
  15. else
  16. ' SQL Server
  17. QuoteValue = "'" & FormatDateTime(val, 0) & "'"
  18. end if
  19. Case vbNull, vbEmpty
  20. QuoteValue = "Null"
  21. Case vbBoolean
  22. ' Return boolean values without quotes
  23. QuoteValue = "'" & CStr(val) & "'"
  24. Case Else
  25. If IsNumeric(val) Then
  26. QuoteValue = CLng(val)
  27. Else
  28. QuoteValue = CStr(val)
  29. End If
  30. End Select
  31. End Function
  32. Public Function GetAppSetting(key)
  33. Dim cacheKey, xml, nodes, node, i
  34. cacheKey = "AppSetting_" & key
  35. ' Check Application cache first for performance
  36. If Not IsEmpty(Application(cacheKey)) Then
  37. GetAppSetting = Application(cacheKey)
  38. Exit Function
  39. End If
  40. ' Load from web.config only if not cached
  41. Set xml = Server.CreateObject("Microsoft.XMLDOM")
  42. xml.Load(Server.MapPath("web.config"))
  43. Set nodes = xml.selectNodes("//appSettings/add")
  44. For i = 0 To nodes.Length - 1
  45. Set node = nodes.Item(i)
  46. If node.getAttribute("key") = key Then
  47. GetAppSetting = node.getAttribute("value")
  48. ' Cache the value for subsequent requests
  49. Application.Lock
  50. Application(cacheKey) = GetAppSetting
  51. Application.Unlock
  52. Exit Function
  53. End If
  54. Next
  55. GetAppSetting = "nothing"
  56. End Function
  57. Public Sub ShowServerVariables
  58. Dim varName, htmlTable
  59. htmlTable = "<table border='1' cellspacing='0' cellpadding='5'>"
  60. htmlTable = htmlTable & "<thead><tr><th>Variable Name</th><th>Value</th></tr></thead><tbody>"
  61. ' Loop through all server variables
  62. For Each varName In Request.ServerVariables
  63. htmlTable = htmlTable & "<tr>"
  64. htmlTable = htmlTable & "<td>" & Server.HTMLEncode(varName) & "</td>"
  65. htmlTable = htmlTable & "<td>" & Server.HTMLEncode(Request.ServerVariables(varName)) & "</td>"
  66. htmlTable = htmlTable & "</tr>"
  67. Next
  68. htmlTable = htmlTable & "</tbody></table>"
  69. ' Output the HTML table
  70. Response.Write(htmlTable)
  71. End Sub
  72. '------------------------------------------------------------------------------
  73. ' Utility: IIf Function for VBScript
  74. ' Usage: result = IIf(condition, trueValue, falseValue)
  75. '------------------------------------------------------------------------------
  76. Function IIf(condition, trueValue, falseValue)
  77. On Error Resume Next
  78. If CBool(condition) Then
  79. IIf = trueValue
  80. Else
  81. IIf = falseValue
  82. End If
  83. If Err.Number <> 0 Then
  84. ' Optional: handle or log error in conversion/evaluation
  85. Err.Clear
  86. End If
  87. On Error GoTo 0
  88. End Function
  89. '-----------------------------
  90. ' Utility: MVC Dispatch Error Renderer
  91. '
  92. ' Renders the error box for a failed MVC.Resolve()/ExecuteAction() call.
  93. ' errInfo is the Dictionary from MVC.LastError: Type = "Security" (format/
  94. ' whitelist failures - message is safe to show in any environment) or
  95. ' Type = "Action" (a controller action raised an error - full detail only
  96. ' in development). Consolidates what were four duplicated inline HTML
  97. ' blocks in the pre-WSC mvc.asp into one place, matching AGENTS.md's
  98. ' "Shared Utilities" rule against duplicate near-identical helpers.
  99. '-----------------------------
  100. Public Sub RenderMvcError(errInfo)
  101. Dim isDevelopment
  102. isDevelopment = (LCase(GetAppSetting("Environment")) = "development")
  103. Response.Write "<div style='padding:15px; margin:10px; border:2px solid #dc3545; background:#f8d7da; color:#721c24; border-radius:4px;'>"
  104. If errInfo("Type") = "Security" Then
  105. Response.Write "<strong>Security Error:</strong> " & Server.HTMLEncode(errInfo("Message"))
  106. ElseIf isDevelopment Then
  107. Response.Write "<strong>Controller Action Error</strong><br>"
  108. Response.Write "Action: <code>" & Server.HTMLEncode(errInfo("ActionName")) & "</code><br>"
  109. Response.Write "Error: " & Server.HTMLEncode(errInfo("Description")) & "<br>"
  110. Response.Write "Error Number: " & errInfo("Number")
  111. Else
  112. Response.Write "<strong>An error occurred</strong><br>"
  113. Response.Write "Please contact the system administrator if the problem persists."
  114. End If
  115. Response.Write "</div>"
  116. End Sub
  117. '-----------------------------
  118. ' Utility: Generic Error Reporter
  119. '-----------------------------
  120. Public Sub ErrorCheck(context)
  121. If Err.Number <> 0 Then
  122. Dim errHtml
  123. errHtml = "<div style='padding:10px; border:2px solid red; background:#fdd; font-family:Verdana; font-size:12px;'>"
  124. errHtml = errHtml & "<strong>Error occurred" & IIf(Not IsEmpty(context) And context <> "", ": " & context, "") & "</strong><br />"
  125. errHtml = errHtml & "<em>Time:</em> " & Now() & "<br />"
  126. errHtml = errHtml & "<em>Number:</em> " & Err.Number & "<br />"
  127. errHtml = errHtml & "<em>Description:</em> " & Server.HTMLEncode(Err.Description) & "<br />"
  128. If Len(Err.Source) > 0 Then
  129. errHtml = errHtml & "<em>Source:</em> " & Server.HTMLEncode(Err.Source) & "<br />"
  130. End If
  131. errHtml = errHtml & "</div>"
  132. Response.Write errHtml
  133. Err.Clear
  134. End If
  135. End Sub
  136. '------------------------------------------------------------------------------
  137. ' Utility: TrimQueryParams
  138. ' Removes everything from the first "?" or "&" onward.
  139. ' Usage:
  140. ' CleanPath = TrimQueryParams(rawPath)
  141. '------------------------------------------------------------------------------
  142. Function TrimQueryParams(rawPath)
  143. Dim posQ, posA, cutPos
  144. ' find the first occurrences of "?" and "&"
  145. posQ = InStr(rawPath, "?")
  146. posA = InStr(rawPath, "&")
  147. ' determine the earliest cut position (>0)
  148. If posQ > 0 And posA > 0 Then
  149. cutPos = IIf(posQ < posA, posQ, posA)
  150. ElseIf posQ > 0 Then
  151. cutPos = posQ
  152. ElseIf posA > 0 Then
  153. cutPos = posA
  154. Else
  155. cutPos = 0
  156. End If
  157. ' if found, return up to just before that char
  158. If cutPos > 0 Then
  159. TrimQueryParams = Left(rawPath, cutPos - 1)
  160. Else
  161. TrimQueryParams = rawPath
  162. End If
  163. End Function
  164. Sub Destroy(o)
  165. if isobject(o) then
  166. if not o is nothing then
  167. on error resume next
  168. o.close
  169. on error goto 0
  170. set o = nothing
  171. end if
  172. end if
  173. End Sub
  174. 'prepends indents
  175. Private Sub puti(v)
  176. put Spaces(m_indent) & v
  177. End Sub
  178. Sub put(v)
  179. Select Case typename(v)
  180. Case "LinkedList_Class" : response.write join(v.TO_Array, ", ")
  181. Case "DynamicArray_Class" : response.write JoinList(v)
  182. Case "Variant()" : response.write join(v, ", ")
  183. Case else : response.write v
  184. End Select
  185. End Sub
  186. Sub put_
  187. put "<br>"
  188. End Sub
  189. Sub putl(v)
  190. put v
  191. put_
  192. End Sub
  193. '---------------------------------------------------------------------------------------------------------------------
  194. 'Wrapper for Server.HTMLEncode() -- makes it easier on the eyes when reading the HTML code
  195. Function H(s)
  196. If Not IsEmpty(s) and Not IsNull(s) then
  197. H = Server.HTMLEncode(s)
  198. Else
  199. H = ""
  200. End If
  201. End Function
  202. '=======================================================================================================================
  203. ' Adapted from Tolerable library
  204. '=======================================================================================================================
  205. ' This subroutine allows us to ignore the difference
  206. ' between object and primitive assignments. This is
  207. ' essential for many parts of the engine.
  208. Public Sub Assign(ByRef var, ByVal val)
  209. If IsObject(val) Then
  210. Set var = val
  211. Else
  212. var = val
  213. End If
  214. End Sub
  215. ' This is similar to the ? : operator of other languages.
  216. ' Unfortunately, both the if_true and if_false "branches"
  217. ' will be evalauted before the condition is even checked. So,
  218. ' you'll only want to use this for simple expressions.
  219. Public Function Choice(ByVal cond, ByVal if_true, ByVal if_false)
  220. If cond Then
  221. Assign Choice, if_true
  222. Else
  223. Assign Choice, if_false
  224. End If
  225. End Function
  226. ' Allows single-quotes to be used in place of double-quotes.
  227. ' Basically, this is a cheap trick that can make it easier
  228. ' to specify Lambdas.
  229. Public Function Q(ByVal input)
  230. Q = Replace(input, "'", """")
  231. End Function
  232. Function SurroundString(inputVar)
  233. If VarType(inputVar) = vbString Then
  234. SurroundString = """" & inputVar & """"
  235. Else
  236. SurroundString = inputVar
  237. End If
  238. End Function
  239. Function SurroundStringInArray(arr)
  240. Dim i
  241. For i = LBound(arr) To UBound(arr)
  242. If IsString(arr(i)) Then
  243. arr(i) = """" & arr(i) & """"
  244. End If
  245. Next
  246. SurroundStringInArray = arr
  247. End Function
  248. '-----------------------------------------------------------------------------------------------------------------------
  249. 'Boolean type checkers
  250. 'Don't forget IsArray is built-in!
  251. Function IsString(value)
  252. IsString = Choice(typename(value) = "String", true, false)
  253. End Function
  254. Function IsDict(value)
  255. IsDict = Choice(typename(value) = "Dictionary", true, false)
  256. End Function
  257. Function IsRecordset(value)
  258. IsRecordset = Choice(typename(value) = "Recordset", true, false)
  259. End Function
  260. Function IsLinkedList(value)
  261. IsLinkedList = Choice(typename(value) = "LinkedList_Class", true, false)
  262. End Function
  263. Function IsArray(value)
  264. IsArray = Choice(typename(value) = "Variant()", true, false)
  265. End Function
  266. '--------------------------------------------------------------------
  267. ' Returns True when the named key is present in Session.Contents
  268. ' • Handles scalars (String, Integer, etc.), objects, Empty, and Null
  269. '--------------------------------------------------------------------
  270. Function SessionHasKey(keyName)
  271. 'Loop over the existing keys—Session.Contents is like a dictionary
  272. Dim k
  273. For Each k In Session.Contents
  274. If StrComp(k, keyName, vbTextCompare) = 0 Then
  275. SessionHasKey = True
  276. Exit Function
  277. End If
  278. Next
  279. SessionHasKey = False 'not found
  280. End Function
  281. Function RenderObjectsAsTable(arr,boolUseTabulator)
  282. Dim html, propNames, i, j, obj, val, pkName, isPk
  283. If IsEmpty(arr) Or Not IsArray(arr) Then
  284. RenderObjectsAsTable = "<!-- no data -->"
  285. Exit Function
  286. End If
  287. Set obj = arr(0)
  288. On Error Resume Next
  289. propNames = obj.Properties
  290. pkName = obj.PrimaryKey
  291. On Error GoTo 0
  292. If IsEmpty(propNames) Or Len(pkName) = 0 Then
  293. RenderObjectsAsTable = "<!-- missing properties or primary key -->"
  294. Exit Function
  295. End If
  296. html = "<div class='table-wrapper'>" & vbCrLf
  297. html = html & "<table class='pobo-table' id='pobo-table'>" & vbCrLf
  298. html = html & " <thead><tr>" & vbCrLf
  299. For i = 0 To UBound(propNames)
  300. html = html & " <th>" & Server.HTMLEncode(propNames(i)) & "</th>" & vbCrLf
  301. Next
  302. html = html & " </tr></thead>" & vbCrLf
  303. html = html & " <tbody>" & vbCrLf
  304. For j = 0 To UBound(arr)
  305. Set obj = arr(j)
  306. html = html & " <tr>" & vbCrLf
  307. For i = 0 To UBound(propNames)
  308. val = GetDynamicProperty(obj, propNames(i))
  309. isPk = (StrComp(propNames(i), pkName, vbTextCompare) = 0)
  310. If IsNull(val) Or IsEmpty(val) Then
  311. val = "&nbsp;"
  312. ElseIf IsDate(val) Then
  313. val = FormatDateTime(val, vbShortDate)
  314. ElseIf VarType(val) = vbBoolean Then
  315. val = IIf(val, "True", "False")
  316. Else
  317. val = CStr(val)
  318. Dim maxLen : maxLen = CInt(GetAppSetting("TableCellMaxLength"))
  319. If maxLen <= 0 Then maxLen = 90
  320. If Len(val) > maxLen Then
  321. val = Left(val, maxLen - 3) & "..."
  322. End If
  323. val = Server.HTMLEncode(val)
  324. End If
  325. If isPk and boolUseTabulator = False Then
  326. val = "<a href=""" & obj.Tablename & "/edit/" & GetDynamicProperty(obj, pkName) & """ class=""table-link"">" & val & "</a>"
  327. End If
  328. html = html & " <td>" & val & "</td>" & vbCrLf
  329. Next
  330. html = html & " </tr>" & vbCrLf
  331. Next
  332. html = html & " </tbody>" & vbCrLf & "</table>" & vbCrLf & "</div>"
  333. RenderObjectsAsTable = html
  334. End Function
  335. Function RenderFormFromObject(obj)
  336. Dim html, propNames, i, name, val, inputType
  337. Dim pkName, tableName, checkedAttr
  338. On Error Resume Next
  339. propNames = obj.Properties
  340. pkName = obj.PrimaryKey
  341. tableName = obj.TableName
  342. On Error GoTo 0
  343. If IsEmpty(propNames) Or Len(pkName) = 0 Then
  344. RenderFormFromObject = "<!-- Invalid object -->"
  345. Exit Function
  346. End If
  347. html = "<form method='post' action='/" & tableName & "/save' class='article-content'>" & vbCrLf
  348. For i = 0 To UBound(propNames)
  349. name = propNames(i)
  350. val = GetDynamicProperty(obj, name)
  351. ' Handle nulls
  352. If IsNull(val) Then val = ""
  353. ' Primary key → hidden input
  354. If StrComp(name, pkName, vbTextCompare) = 0 Then
  355. html = html & " <input type='hidden' name='" & name & "' value='" & Server.HTMLEncode(val) & "' />" & vbCrLf
  356. 'Continue For
  357. End If
  358. html = html & " <div class='form-group'>" & vbCrLf
  359. html = html & " <label for='" & name & "'>" & name & "</label>" & vbCrLf
  360. Select Case True
  361. Case VarType(val) = vbBoolean
  362. checkedAttr = ""
  363. If val = True Then checkedAttr = " checked"
  364. html = html & " <input type='checkbox' class='form-check-input' name='" & name & "' id='" & name & "' value='true'" & checkedAttr & " />" & vbCrLf
  365. Case IsDate(val)
  366. html = html & " <input type='date' class='form-control' name='" & name & "' id='" & name & "' value='" & FormatDateForInput(val) & "' />" & vbCrLf
  367. Case IsNumeric(val)
  368. html = html & " <input type='number' class='form-control' name='" & name & "' id='" & name & "' value='" & val & "' />" & vbCrLf
  369. Case Len(val) > CInt(GetAppSetting("FormTextareaThreshold"))
  370. html = html & " <textarea class='form-control' name='" & name & "' id='" & name & "' rows='6'>" & Server.HTMLEncode(val) & "</textarea>" & vbCrLf
  371. Case Else
  372. html = html & " <input type='text' class='form-control' name='" & name & "' id='" & name & "' value='" & Server.HTMLEncode(val) & "' />" & vbCrLf
  373. End Select
  374. html = html & " </div>" & vbCrLf
  375. Next
  376. html = html & " <button type='submit' class='btn btn-primary btn-lg'>Save</button>" & vbCrLf
  377. html = html & "</form>" & vbCrLf
  378. RenderFormFromObject = html
  379. End Function
  380. Function GetDynamicProperty(obj, propName)
  381. On Error Resume Next
  382. Dim result
  383. Execute "result = obj." & propName
  384. If Err.Number <> 0 Then
  385. result = ""
  386. Err.Clear
  387. End If
  388. GetDynamicProperty = result
  389. On Error GoTo 0
  390. End Function
  391. Function FormatDateForInput(val)
  392. If IsDate(val) Then
  393. Dim yyyy, mm, dd
  394. yyyy = Year(val)
  395. mm = Right("0" & Month(val), 2)
  396. dd = Right("0" & Day(val), 2)
  397. FormatDateForInput = yyyy & "-" & mm & "-" & dd
  398. Else
  399. FormatDateForInput = ""
  400. End If
  401. End Function
  402. '-------------------------------------------------------------
  403. ' Returns obj.<propName> for any public VBScript class property
  404. '-------------------------------------------------------------
  405. Function GetObjProp(o, pName)
  406. Dim tmp
  407. ' Build a tiny statement like: tmp = o.UserID
  408. Execute "tmp = o." & pName
  409. GetObjProp = tmp
  410. End Function
  411. Function GenerateSlug(title)
  412. Dim slug
  413. slug = LCase(title) ' Convert to lowercase
  414. slug = Replace(slug, "&", "and") ' Replace ampersands
  415. slug = Replace(slug, "'", "") ' Remove apostrophes
  416. slug = Replace(slug, """", "") ' Remove quotes
  417. slug = Replace(slug, "–", "-") ' Replace en dash
  418. slug = Replace(slug, "—", "-") ' Replace em dash
  419. slug = Replace(slug, "/", "-") ' Replace slashes
  420. slug = Replace(slug, "\", "-") ' Replace backslashes
  421. ' Remove all non-alphanumeric and non-hyphen/space characters
  422. Dim i, ch, clean
  423. clean = ""
  424. For i = 1 To Len(slug)
  425. ch = Mid(slug, i, 1)
  426. If (ch >= "a" And ch <= "z") Or (ch >= "0" And ch <= "9") Or ch = " " Or ch = "-" Then
  427. clean = clean & ch
  428. End If
  429. Next
  430. ' Replace multiple spaces or hyphens with single hyphen
  431. Do While InStr(clean, " ") > 0
  432. clean = Replace(clean, " ", " ")
  433. Loop
  434. clean = Replace(clean, " ", "-")
  435. Do While InStr(clean, "--") > 0
  436. clean = Replace(clean, "--", "-")
  437. Loop
  438. ' Trim leading/trailing hyphens
  439. Do While Left(clean, 1) = "-"
  440. clean = Mid(clean, 2)
  441. Loop
  442. Do While Right(clean, 1) = "-"
  443. clean = Left(clean, Len(clean) - 1)
  444. Loop
  445. GenerateSlug = clean
  446. End Function
  447. Function GetRawJsonFromRequest()
  448. Dim stream, rawJson
  449. Set stream = Server.CreateObject("ADODB.Stream")
  450. stream.Type = 1 ' adTypeBinary
  451. stream.Open
  452. stream.Write Request.BinaryRead(Request.TotalBytes)
  453. stream.Position = 0
  454. stream.Type = 2 ' adTypeText
  455. stream.Charset = "utf-8"
  456. rawJson = stream.ReadText
  457. stream.Close
  458. Set stream = Nothing
  459. GetRawJsonFromRequest = rawJson
  460. End Function
  461. Function Active(controllerName)
  462. On Error Resume Next
  463. If Replace(Lcase(router.Resolve(Request.ServerVariables("REQUEST_METHOD"), TrimQueryParams(Request.ServerVariables("HTTP_X_ORIGINAL_URL")))(0)),"controller","") = LCase(controllerName) Then
  464. Active = "active"
  465. Else
  466. Active = ""
  467. End If
  468. On Error GoTo 0
  469. End Function
  470. '====================================================================
  471. ' FormatDateForSql
  472. ' Converts a VBScript Date to a SQL Server-compatible string
  473. ' Output: 'YYYY-MM-DD HH:MM:SS'
  474. '====================================================================
  475. Function FormatDateForSql(vbDate)
  476. If IsNull(vbDate) Or vbDate = "" Then
  477. FormatDateForSql = "NULL"
  478. Exit Function
  479. End If
  480. ' Ensure vbDate is a valid date
  481. If Not IsDate(vbDate) Then
  482. Err.Raise vbObjectError + 1000, "FormatDateForSql", "Invalid date: " & vbDate
  483. End If
  484. Dim yyyy, mm, dd, hh, nn, ss
  485. yyyy = Year(vbDate)
  486. mm = Right("0" & Month(vbDate), 2)
  487. dd = Right("0" & Day(vbDate), 2)
  488. hh = Right("0" & Hour(vbDate), 2)
  489. nn = Right("0" & Minute(vbDate), 2)
  490. ss = Right("0" & Second(vbDate), 2)
  491. ' Construct SQL Server datetime literal
  492. FormatDateForSql = "'" & yyyy & "-" & mm & "-" & dd & " " & hh & ":" & nn & ":" & ss & "'"
  493. End Function
  494. %>

Powered by TurnKey Linux.