PageRenderTime 34ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/wheels/global/public.cfm

http://cfwheels.googlecode.com/
ColdFusion | 632 lines | 583 code | 38 blank | 11 comment | 131 complexity | 1ce8163e1d197d615ddaecc640c4a9cd MD5 | raw file
Possible License(s): Apache-2.0, CPL-1.0
  1. <!--- PUBLIC CONFIGURATION FUNCTIONS --->
  2. <cffunction name="addFormat" returntype="void" access="public" output="false" hint="Adds a new MIME format to your Wheels application for use with responding to multiple formats."
  3. examples='
  4. <!--- Add the `js` format --->
  5. <cfset addFormat(extension="js", mimeType="text/javascript")>
  6. <!--- Add the `ppt` and `pptx` formats --->
  7. <cfset addFormat(extension="ppt", mimeType="application/vnd.ms-powerpoint")>
  8. <cfset addFormat(extension="pptx", mimeType="application/vnd.ms-powerpoint")>
  9. '
  10. categories="configuration" chapters="responding-with-multiple-formats" functions="provides,renderWith">
  11. <cfargument name="extension" type="string" required="true" hint="File extension to add." />
  12. <cfargument name="mimeType" type="string" required="true" hint="Matching MIME type to associate with the file extension." />
  13. <cfset application.wheels.formats[arguments.extension] = arguments.mimeType />
  14. </cffunction>
  15. <cffunction name="addRoute" returntype="void" access="public" output="false" hint="Adds a new route to your application."
  16. examples=
  17. '
  18. <!--- Example 1: Adds a route which will invoke the `profile` action on the `user` controller with `params.userName` set when the URL matches the `pattern` argument --->
  19. <cfset addRoute(name="userProfile", pattern="user/[username]", controller="user", action="profile")>
  20. <!--- Example 2: Category/product URLs. Note the order of precedence is such that the more specific route should be defined first so Wheels will fall back to the less-specific version if it''s not found --->
  21. <cfset addRoute(name="product", pattern="products/[categorySlug]/[productSlug]", controller="products", action="product")>
  22. <cfset addRoute(name="productCategory", pattern="products/[categorySlug]", controller="products", action="category")>
  23. <cfset addRoute(name="products", pattern="products", controller="products", action="index")>
  24. <!--- Example 3: Change the `home` route. This should be listed last because it is least specific --->
  25. <cfset addRoute(name="home", pattern="", controller="main", action="index")>
  26. '
  27. categories="configuration" chapters="using-routes" functions="">
  28. <cfargument name="name" type="string" required="false" default="" hint="Name for the route. This is referenced as the `name` argument in functions based on @URLFor like @linkTo, @startFormTag, etc.">
  29. <cfargument name="pattern" type="string" required="true" hint="The URL pattern that the route will match.">
  30. <cfargument name="controller" type="string" required="false" default="" hint="Controller to call when route matches (unless the controller name exists in the pattern).">
  31. <cfargument name="action" type="string" required="false" default="" hint="Action to call when route matches (unless the action name exists in the pattern).">
  32. <cfscript>
  33. var loc = {};
  34. // throw errors when controller or action is not passed in as arguments and not included in the pattern
  35. if (!Len(arguments.controller) && arguments.pattern Does Not Contain "[controller]")
  36. $throw(type="Wheels.IncorrectArguments", message="The `controller` argument is not passed in or included in the pattern.", extendedInfo="Either pass in the `controller` argument to specifically tell Wheels which controller to call or include it in the pattern to tell Wheels to determine it dynamically on each request based on the incoming URL.");
  37. if (!Len(arguments.action) && arguments.pattern Does Not Contain "[action]")
  38. $throw(type="Wheels.IncorrectArguments", message="The `action` argument is not passed in or included in the pattern.", extendedInfo="Either pass in the `action` argument to specifically tell Wheels which action to call or include it in the pattern to tell Wheels to determine it dynamically on each request based on the incoming URL.");
  39. loc.thisRoute = Duplicate(arguments);
  40. loc.thisRoute.variables = "";
  41. if (Find(".", loc.thisRoute.pattern))
  42. {
  43. loc.thisRoute.format = ListLast(loc.thisRoute.pattern, ".");
  44. loc.thisRoute.formatVariable = ReplaceList(loc.thisRoute.format, "[,]", "");
  45. loc.thisRoute.pattern = ListFirst(loc.thisRoute.pattern, ".");
  46. }
  47. loc.iEnd = ListLen(loc.thisRoute.pattern, "/");
  48. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  49. {
  50. loc.item = ListGetAt(loc.thisRoute.pattern, loc.i, "/");
  51. if (REFind("^\[", loc.item))
  52. loc.thisRoute.variables = ListAppend(loc.thisRoute.variables, ReplaceList(loc.item, "[,]", ""));
  53. }
  54. ArrayAppend(application.wheels.routes, loc.thisRoute);
  55. </cfscript>
  56. </cffunction>
  57. <cffunction name="addDefaultRoutes" returntype="void" access="public" output="false" hint="Adds the default Wheels routes (for example, `[controller]/[action]/[key]`, etc.) to your application. Only use this method if you have set `loadDefaultRoutes` to `false` and want to control exactly where in the route order you want to place the default routes."
  58. examples=
  59. '
  60. <!--- Adds the default routes to your application (done in `config/routes.cfm`) --->
  61. <cfset addDefaultRoutes()>
  62. '
  63. categories="configuration" chapters="using-routes" functions="">
  64. <cfscript>
  65. addRoute(pattern="[controller]/[action]/[key]");
  66. addRoute(pattern="[controller]/[action]");
  67. addRoute(pattern="[controller]", action="index");
  68. </cfscript>
  69. </cffunction>
  70. <cffunction name="set" returntype="void" access="public" output="false" hint="Use to configure a global setting or set a default for a function."
  71. examples=
  72. '
  73. <!--- Example 1: Set the `URLRewriting` setting to `Partial` --->
  74. <cfset set(URLRewriting="Partial")>
  75. <!--- Example 2: Set default values for the arguments in the `buttonTo` view helper. This works for the majority of Wheels functions/arguments. --->
  76. <cfset set(functionName="buttonTo", onlyPath=true, host="", protocol="", port=0, text="", confirm="", image="", disable="")>
  77. <!--- Example 3: Set the default values for a form helper to get the form marked up to your preferences --->
  78. <cfset set(functionName="textField", labelPlacement="before", prependToLabel="<div>", append="</div>", appendToLabel="<br />")>
  79. '
  80. categories="configuration" chapters="configuration-and-defaults" functions="get">
  81. <cfscript>
  82. var loc = {};
  83. if (ArrayLen(arguments) > 1)
  84. {
  85. for (loc.key in arguments)
  86. {
  87. if (loc.key != "functionName")
  88. for (loc.i = 1; loc.i lte listlen(arguments.functionName); loc.i = loc.i + 1) {
  89. application.wheels.functions[Trim(ListGetAt(arguments.functionName, loc.i))][loc.key] = arguments[loc.key];
  90. }
  91. }
  92. }
  93. else
  94. {
  95. application.wheels[StructKeyList(arguments)] = arguments[1];
  96. }
  97. </cfscript>
  98. </cffunction>
  99. <!--- PUBLIC GLOBAL FUNCTIONS --->
  100. <!--- miscellaneous --->
  101. <cffunction name="controller" returntype="any" access="public" output="false" hint="Creates and returns a controller object with your own custom `name` and `params`. Used primarily for testing purposes."
  102. examples='
  103. <cfset testController = controller("users", params)>
  104. '
  105. categories="global,miscellaneous" chapters="" functions="">
  106. <cfargument name="name" type="string" required="true" hint="Name of the controller to create.">
  107. <cfargument name="params" type="struct" required="false" default="#StructNew()#" hint="The params struct (combination of `form` and `URL` variables).">
  108. <cfscript>
  109. var loc = {};
  110. loc.args = {};
  111. loc.args.name = arguments.name;
  112. loc.returnValue = $doubleCheckedLock(name="controllerLock", condition="$cachedControllerClassExists", execute="$createControllerClass", conditionArgs=loc.args, executeArgs=loc.args);
  113. if (!StructIsEmpty(arguments.params))
  114. loc.returnValue = loc.returnValue.$createControllerObject(arguments.params);
  115. return loc.returnValue;
  116. </cfscript>
  117. </cffunction>
  118. <cffunction name="deobfuscateParam" returntype="string" access="public" output="false" hint="Deobfuscates a value."
  119. examples=
  120. '
  121. <!--- Get the original value from an obfuscated one --->
  122. <cfset originalValue = deobfuscateParam("b7ab9a50")>
  123. '
  124. categories="global,miscellaneous" chapters="obfuscating-urls" functions="obfuscateParam">
  125. <cfargument name="param" type="string" required="true" hint="Value to deobfuscate.">
  126. <cfscript>
  127. var loc = {};
  128. if (Val(SpanIncluding(arguments.param, "0,1,2,3,4,5,6,7,8,9")) != arguments.param)
  129. {
  130. try
  131. {
  132. loc.checksum = Left(arguments.param, 2);
  133. loc.returnValue = Right(arguments.param, (Len(arguments.param)-2));
  134. loc.z = BitXor(InputBasen(loc.returnValue,16),461);
  135. loc.returnValue = "";
  136. loc.iEnd = Len(loc.z)-1;
  137. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  138. loc.returnValue = loc.returnValue & Left(Right(loc.z, loc.i),1);
  139. loc.checksumtest = "0";
  140. loc.iEnd = Len(loc.returnValue);
  141. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  142. loc.checksumtest = (loc.checksumtest + Left(Right(loc.returnValue, loc.i),1));
  143. loc.c1 = ToString(FormatBaseN((loc.checksumtest+154),10));
  144. loc.c2 = InputBasen(loc.checksum, 16);
  145. if (loc.c1 != loc.c2)
  146. loc.returnValue = arguments.param;
  147. }
  148. catch(Any e)
  149. {
  150. loc.returnValue = arguments.param;
  151. }
  152. }
  153. else
  154. {
  155. loc.returnValue = arguments.param;
  156. }
  157. </cfscript>
  158. <cfreturn loc.returnValue>
  159. </cffunction>
  160. <cffunction name="get" returntype="any" access="public" output="false" hint="Returns the current setting for the supplied Wheels setting or the current default for the supplied Wheels function argument."
  161. examples=
  162. '
  163. <!--- Get the current value for the `tableNamePrefix` Wheels setting --->
  164. <cfset setting = get("tableNamePrefix")>
  165. <!--- Get the default for the `message` argument of the `validatesConfirmationOf` method --->
  166. <cfset setting = get(functionName="validatesConfirmationOf", name="message")>
  167. '
  168. categories="global,miscellaneous" chapters="configuration-and-defaults" functions="set">
  169. <cfargument name="name" type="string" required="true" hint="Variable name to get setting for.">
  170. <cfargument name="functionName" type="string" required="false" default="" hint="Function name to get setting for.">
  171. <cfscript>
  172. var loc = {};
  173. if (Len(arguments.functionName))
  174. loc.returnValue = application.wheels.functions[arguments.functionName][arguments.name];
  175. else
  176. loc.returnValue = application.wheels[arguments.name];
  177. </cfscript>
  178. <cfreturn loc.returnValue>
  179. </cffunction>
  180. <cffunction name="model" returntype="any" access="public" output="false" hint="Returns a reference to the requested model so that class level methods can be called on it."
  181. examples=
  182. '
  183. <!--- The `model("author")` part of the code below gets a reference to the model from the application scope, and then the `findByKey` class level method is called on it --->
  184. <cfset authorObject = model("author").findByKey(1)>
  185. '
  186. categories="global,miscellaneous" chapters="object-relational-mapping" functions="">
  187. <cfargument name="name" type="string" required="true" hint="Name of the model to get a reference to.">
  188. <!--- we need an instance of the model to be able to build queries without adding the query data to the application scope model --->
  189. <cfreturn $doubleCheckedLock(name="modelLock", condition="$cachedModelClassExists", execute="$createModelClass", conditionArgs=arguments, executeArgs=arguments)>
  190. </cffunction>
  191. <cffunction name="obfuscateParam" returntype="string" access="public" output="false" hint="Obfuscates a value. Typically used for hiding primary key values when passed along in the URL."
  192. examples=
  193. '
  194. <!--- Obfuscate the primary key value `99` --->
  195. <cfset newValue = obfuscateParam(99)>
  196. '
  197. categories="global,miscellaneous" chapters="obfuscating-urls" functions="deobfuscateParam">
  198. <cfargument name="param" type="any" required="true" hint="Value to obfuscate.">
  199. <cfscript>
  200. var loc = {};
  201. if (IsValid("integer", arguments.param) && IsNumeric(arguments.param) && arguments.param > 0)
  202. {
  203. // railo strips leading zeros from integers so do this for both engines
  204. arguments.param = Val(SpanIncluding(arguments.param, "0,1,2,3,4,5,6,7,8,9"));
  205. loc.iEnd = Len(arguments.param);
  206. loc.a = (10^loc.iEnd) + Reverse(arguments.param);
  207. loc.b = "0";
  208. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  209. loc.b = (loc.b + Left(Right(arguments.param, loc.i), 1));
  210. loc.returnValue = FormatBaseN((loc.b+154),16) & FormatBaseN(BitXor(loc.a,461),16);
  211. }
  212. else
  213. {
  214. loc.returnValue = arguments.param;
  215. }
  216. </cfscript>
  217. <cfreturn loc.returnValue>
  218. </cffunction>
  219. <cffunction name="pluginNames" returntype="string" access="public" output="false" hint="Returns a list of all installed plugins' names."
  220. examples=
  221. '
  222. <!--- Check if the Scaffold plugin is installed --->
  223. <cfif ListFindNoCase("scaffold", pluginNames())>
  224. <!--- do something cool --->
  225. </cfif>
  226. '
  227. categories="global,miscellaneous" chapters="using-and-creating-plugins" functions="">
  228. <cfreturn StructKeyList(application.wheels.plugins)>
  229. </cffunction>
  230. <cffunction name="URLFor" returntype="string" access="public" output="false" hint="Creates an internal URL based on supplied arguments."
  231. examples=
  232. '
  233. <!--- Create the URL for the `logOut` action on the `account` controller, typically resulting in `/account/log-out` --->
  234. ##URLFor(controller="account", action="logOut")##
  235. <!--- Create a URL with an anchor set on it --->
  236. ##URLFor(action="comments", anchor="comment10")##
  237. <!--- Create a URL based on a route called `products`, which expects params for `categorySlug` and `productSlug` --->
  238. ##URLFor(route="product", categorySlug="accessories", productSlug="battery-charger")##
  239. '
  240. categories="global,miscellaneous" chapters="request-handling,linking-pages" functions="redirectTo,linkTo,startFormTag">
  241. <cfargument name="route" type="string" required="false" default="" hint="Name of a route that you have configured in `config/routes.cfm`.">
  242. <cfargument name="controller" type="string" required="false" default="" hint="Name of the controller to include in the URL.">
  243. <cfargument name="action" type="string" required="false" default="" hint="Name of the action to include in the URL.">
  244. <cfargument name="key" type="any" required="false" default="" hint="Key(s) to include in the URL.">
  245. <cfargument name="params" type="string" required="false" default="" hint="Any additional params to be set in the query string.">
  246. <cfargument name="anchor" type="string" required="false" default="" hint="Sets an anchor name to be appended to the path.">
  247. <cfargument name="onlyPath" type="boolean" required="false" hint="If `true`, returns only the relative URL (no protocol, host name or port).">
  248. <cfargument name="host" type="string" required="false" hint="Set this to override the current host.">
  249. <cfargument name="protocol" type="string" required="false" hint="Set this to override the current protocol.">
  250. <cfargument name="port" type="numeric" required="false" hint="Set this to override the current port number.">
  251. <cfargument name="$URLRewriting" type="string" required="false" default="#application.wheels.URLRewriting#">
  252. <cfscript>
  253. var loc = {};
  254. $args(name="URLFor", args=arguments);
  255. loc.params = {};
  256. if (StructKeyExists(variables, "params"))
  257. StructAppend(loc.params, variables.params, true);
  258. if (application.wheels.showErrorInformation)
  259. {
  260. if (arguments.onlyPath && (Len(arguments.host) || Len(arguments.protocol)))
  261. $throw(type="Wheels.IncorrectArguments", message="Can't use the `host` or `protocol` arguments when `onlyPath` is `true`.", extendedInfo="Set `onlyPath` to `false` so that `linkTo` will create absolute URLs and thus allowing you to set the `host` and `protocol` on the link.");
  262. }
  263. // get primary key values if an object was passed in
  264. if (IsObject(arguments.key))
  265. {
  266. arguments.key = arguments.key.key();
  267. }
  268. // build the link
  269. loc.returnValue = application.wheels.webPath & ListLast(request.cgi.script_name, "/");
  270. if (Len(arguments.route))
  271. {
  272. // link for a named route
  273. loc.route = $findRoute(argumentCollection=arguments);
  274. if (arguments.$URLRewriting == "Off")
  275. {
  276. loc.returnValue = loc.returnValue & "?controller=";
  277. if (Len(arguments.controller))
  278. loc.returnValue = loc.returnValue & hyphenize(arguments.controller);
  279. else
  280. loc.returnValue = loc.returnValue & hyphenize(loc.route.controller);
  281. loc.returnValue = loc.returnValue & "&action=";
  282. if (Len(arguments.action))
  283. loc.returnValue = loc.returnValue & hyphenize(arguments.action);
  284. else
  285. loc.returnValue = loc.returnValue & hyphenize(loc.route.action);
  286. // add it the format if it exists
  287. if (StructKeyExists(loc.route, "formatVariable") && StructKeyExists(arguments, loc.route.formatVariable))
  288. loc.returnValue = loc.returnValue & "&#loc.route.formatVariable#=#arguments[loc.route.formatVariable]#";
  289. loc.iEnd = ListLen(loc.route.variables);
  290. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  291. {
  292. loc.property = ListGetAt(loc.route.variables, loc.i);
  293. if (loc.property != "controller" && loc.property != "action")
  294. loc.returnValue = loc.returnValue & "&" & loc.property & "=" & $URLEncode(arguments[loc.property]);
  295. }
  296. }
  297. else
  298. {
  299. loc.iEnd = ListLen(loc.route.pattern, "/");
  300. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  301. {
  302. loc.property = ListGetAt(loc.route.pattern, loc.i, "/");
  303. if (loc.property Contains "[")
  304. {
  305. loc.property = Mid(loc.property, 2, Len(loc.property)-2);
  306. if (application.wheels.showErrorInformation && !StructKeyExists(arguments, loc.property))
  307. $throw(type="Wheels", message="Incorrect Arguments", extendedInfo="The route chosen by Wheels `#loc.route.name#` requires the argument `#loc.property#`. Pass the argument `#loc.property#` or change your routes to reflect the proper variables needed.");
  308. loc.param = $URLEncode(arguments[loc.property]);
  309. if (loc.property == "controller" || loc.property == "action")
  310. loc.param = hyphenize(loc.param);
  311. else if (application.wheels.obfuscateUrls)
  312. loc.param = obfuscateParam(loc.param);
  313. loc.returnValue = loc.returnValue & "/" & loc.param; // get param from arguments
  314. }
  315. else
  316. {
  317. loc.returnValue = loc.returnValue & "/" & loc.property; // add hard coded param from route
  318. }
  319. }
  320. // add it the format if it exists
  321. if (StructKeyExists(loc.route, "formatVariable") && StructKeyExists(arguments, loc.route.formatVariable))
  322. loc.returnValue = loc.returnValue & ".#arguments[loc.route.formatVariable]#";
  323. }
  324. }
  325. else // link based on controller/action/key
  326. {
  327. // when no controller or action was passed in we link to the current page (controller/action only, not query string etc) by default
  328. if (!Len(arguments.controller) && !Len(arguments.action) && StructKeyExists(loc.params, "action"))
  329. arguments.action = loc.params.action;
  330. if (!Len(arguments.controller) && StructKeyExists(loc.params, "controller"))
  331. arguments.controller = loc.params.controller;
  332. if (Len(arguments.key) && !Len(arguments.action) && StructKeyExists(loc.params, "action"))
  333. arguments.action = loc.params.action;
  334. loc.returnValue = loc.returnValue & "?controller=" & hyphenize(arguments.controller);
  335. if (Len(arguments.action))
  336. loc.returnValue = loc.returnValue & "&action=" & hyphenize(arguments.action);
  337. if (Len(arguments.key))
  338. {
  339. loc.param = $URLEncode(arguments.key);
  340. if (application.wheels.obfuscateUrls)
  341. loc.param = obfuscateParam(loc.param);
  342. loc.returnValue = loc.returnValue & "&key=" & loc.param;
  343. }
  344. }
  345. if (arguments.$URLRewriting != "Off")
  346. {
  347. loc.returnValue = Replace(loc.returnValue, "?controller=", "/");
  348. loc.returnValue = Replace(loc.returnValue, "&action=", "/");
  349. loc.returnValue = Replace(loc.returnValue, "&key=", "/");
  350. }
  351. if (arguments.$URLRewriting == "On")
  352. {
  353. loc.returnValue = Replace(loc.returnValue, application.wheels.rewriteFile, "");
  354. loc.returnValue = Replace(loc.returnValue, "//", "/");
  355. }
  356. if (Len(arguments.params))
  357. loc.returnValue = loc.returnValue & $constructParams(params=arguments.params, $URLRewriting=arguments.$URLRewriting);
  358. if (Len(arguments.anchor))
  359. loc.returnValue = loc.returnValue & "##" & arguments.anchor;
  360. if (!arguments.onlyPath)
  361. {
  362. if (arguments.port != 0)
  363. loc.returnValue = ":" & arguments.port & loc.returnValue; // use the port that was passed in by the developer
  364. else if (request.cgi.server_port != 80 && request.cgi.server_port != 443)
  365. loc.returnValue = ":" & request.cgi.server_port & loc.returnValue; // if the port currently in use is not 80 or 443 we set it explicitly in the URL
  366. if (Len(arguments.host))
  367. loc.returnValue = arguments.host & loc.returnValue;
  368. else
  369. loc.returnValue = request.cgi.server_name & loc.returnValue;
  370. if (Len(arguments.protocol))
  371. loc.returnValue = arguments.protocol & "://" & loc.returnValue;
  372. else
  373. loc.returnValue = SpanExcluding(LCase(request.cgi.server_protocol), "/") & "://" & loc.returnValue;
  374. }
  375. </cfscript>
  376. <cfreturn loc.returnValue>
  377. </cffunction>
  378. <!--- string helpers --->
  379. <cffunction name="capitalize" returntype="string" access="public" output="false" hint="Returns the text with the first character converted to uppercase."
  380. examples=
  381. '
  382. <!--- Capitalize a sentence, will result in "Wheels is a framework" --->
  383. ##capitalize("wheels is a framework")##
  384. '
  385. categories="global,string" chapters="miscellaneous-helpers" functions="humanize,pluralize,singularize">
  386. <cfargument name="text" type="string" required="true" hint="Text to capitalize.">
  387. <cfif !Len(arguments.text)>
  388. <cfreturn arguments.text />
  389. </cfif>
  390. <cfreturn UCase(Left(arguments.text, 1)) & Mid(arguments.text, 2, Len(arguments.text)-1)>
  391. </cffunction>
  392. <cffunction name="humanize" returntype="string" access="public" output="false" hint="Returns readable text by capitalizing and converting camel casing to multiple words."
  393. examples=
  394. '
  395. <!--- Humanize a string, will result in "Wheels Is A Framework" --->
  396. ##humanize("wheelsIsAFramework")##
  397. <!--- Humanize a string, force wheels to replace "Cfml" with "CFML" --->
  398. ##humanize("wheelsIsACFMLFramework", "CFML")##
  399. '
  400. categories="global,string" chapters="miscellaneous-helpers" functions="capitalize,pluralize,singularize">
  401. <cfargument name="text" type="string" required="true" hint="Text to humanize.">
  402. <cfargument name="except" type="string" required="false" default="" hint="a list of strings (space separated) to replace within the output.">
  403. <cfscript>
  404. var loc = {};
  405. loc.returnValue = REReplace(arguments.text, "([[:upper:]])", " \1", "all"); // adds a space before every capitalized word
  406. loc.returnValue = REReplace(loc.returnValue, "([[:upper:]]) ([[:upper:]])(?:\s|\b)", "\1\2", "all"); // fixes abbreviations so they form a word again (example: aURLVariable)
  407. if (Len(arguments.except))
  408. {
  409. loc.iEnd = ListLen(arguments.except, " ");
  410. for (loc.i = 1; loc.i lte loc.iEnd; loc.i++)
  411. {
  412. loc.a = ListGetAt(arguments.except, loc.i);
  413. loc.returnValue = ReReplaceNoCase(loc.returnValue, "#loc.a#(?:\b)", "#loc.a#", "all");
  414. }
  415. }
  416. loc.returnValue = Trim(capitalize(loc.returnValue)); // capitalize the first letter and trim final result (which removes the leading space that happens if the string starts with an upper case character)
  417. </cfscript>
  418. <cfreturn loc.returnValue>
  419. </cffunction>
  420. <cffunction name="pluralize" returntype="string" access="public" output="false" hint="Returns the plural form of the passed in word. Can also pluralize a word based on a value passed to the `count` argument."
  421. examples=
  422. '
  423. <!--- Pluralize a word, will result in "people" --->
  424. ##pluralize("person")##
  425. <!--- Pluralize based on the count passed in --->
  426. Your search returned ##pluralize(word="person", count=users.RecordCount)##
  427. '
  428. categories="global,string" chapters="miscellaneous-helpers" functions="capitalize,humanize,singularize">
  429. <cfargument name="word" type="string" required="true" hint="The word to pluralize.">
  430. <cfargument name="count" type="numeric" required="false" default="-1" hint="Pluralization will occur when this value is not `1`.">
  431. <cfargument name="returnCount" type="boolean" required="false" default="true" hint="Will return `count` prepended to the pluralization when `true` and `count` is not `-1`.">
  432. <cfreturn $singularizeOrPluralizeWithCount(text=arguments.word, which="pluralize", count=arguments.count, returnCount=arguments.returnCount)>
  433. </cffunction>
  434. <cffunction name="singularize" returntype="string" access="public" output="false" hint="Returns the singular form of the passed in word."
  435. examples=
  436. '
  437. <!--- Singularize a word, will result in "language" --->
  438. ##singularize("languages")##
  439. '
  440. categories="global,string" chapters="miscellaneous-helpers" functions="capitalize,humanize,pluralize">
  441. <cfargument name="word" type="string" required="true" hint="String to singularize.">
  442. <cfreturn $singularizeOrPluralizeWithCount(text=arguments.word, which="singularize")>
  443. </cffunction>
  444. <cffunction name="toXHTML" returntype="string" access="public" output="false" hint="Returns an XHTML-compliant string."
  445. examples=
  446. '
  447. <!--- Outputs `productId=5&amp;categoryId=12&amp;returningCustomer=1` --->
  448. <cfoutput>
  449. ##toXHTML("productId=5&categoryId=12&returningCustomer=1")##
  450. </cfoutput>
  451. '
  452. categories="global,string" chapters="" functions="">
  453. <cfargument name="text" type="string" required="true" hint="String to make XHTML-compliant.">
  454. <cfset arguments.text = Replace(arguments.text, "&", "&amp;", "all")>
  455. <cfreturn arguments.text>
  456. </cffunction>
  457. <cffunction name="mimeTypes" returntype="string" access="public" output="false" hint="Returns an associated MIME type based on a file extension."
  458. examples=
  459. '
  460. <!--- Get the internally-stored MIME type for `xls` --->
  461. <cfset mimeType = mimeTypes("xls")>
  462. <!--- Get the internally-stored MIME type for a dynamic value. Fall back to a MIME type of `text/plain` if it''s not found --->
  463. <cfset mimeType = mimeTypes(extension=params.type, fallback="text/plain")>
  464. '
  465. categories="global,miscellaneous" chapters="" functions="">
  466. <cfargument name="extension" required="true" type="string" hint="The extension to get the MIME type for.">
  467. <cfargument name="fallback" required="false" type="string" default="application/octet-stream" hint="the fallback MIME type to return.">
  468. <cfif StructKeyExists(application.wheels.mimetypes, arguments.extension)>
  469. <cfset arguments.fallback = application.wheels.mimetypes[arguments.extension]>
  470. </cfif>
  471. <cfreturn arguments.fallback>
  472. </cffunction>
  473. <cffunction name="hyphenize" returntype="string" access="public" output="false" hint="Converts camelCase strings to lowercase strings with hyphens as word delimiters instead. Example: `myVariable` becomes `my-variable`."
  474. examples=
  475. '
  476. <!--- Outputs "my-blog-post" --->
  477. <cfoutput>
  478. ##hyphenize("myBlogPost")##
  479. </cfoutput>
  480. '
  481. categories="global,string" chapters="" functions="">
  482. <cfargument name="string" type="string" required="true" hint="The string to hyphenize.">
  483. <cfset arguments.string = REReplace(arguments.string, "([A-Z][a-z])", "-\l\1", "all")>
  484. <cfset arguments.string = REReplace(arguments.string, "([a-z])([A-Z])", "\1-\l\2", "all")>
  485. <cfset arguments.string = REReplace(arguments.string, "^-", "", "one")>
  486. <cfreturn LCase(arguments.string)>
  487. </cffunction>
  488. <!--- PRIVATE FUNCTIONS --->
  489. <cffunction name="$singularizeOrPluralizeWithCount" returntype="string" access="public" output="false" hint="Decides if we need to convert the word based on the count value passed in and then adds the count to the string.">
  490. <cfargument name="text" type="string" required="true" hint="See documentation for @pluralize.">
  491. <cfargument name="count" type="numeric" required="false" default="-1" hint="See documentation for @pluralize.">
  492. <cfargument name="returnCount" type="boolean" required="false" default="true" hint="See documentation for @pluralize.">
  493. <cfargument name="which" type="string" required="true" hint="Should be either `singularize` or `pluralize`.">
  494. <cfscript>
  495. var loc = {};
  496. loc.returnValue = $args(name="$singularizeOrPluralizeWithCount", cachable=true, args=arguments);
  497. if (!StructKeyExists(loc, "returnValue"))
  498. {
  499. // run conversion unless count is passed in and its value means conversion is unnecessary
  500. if (arguments.which == "pluralize" && arguments.count == 1)
  501. loc.returnValue = arguments.text;
  502. else
  503. loc.returnValue = $singularizeOrPluralize(text=arguments.text, which=arguments.which);
  504. // return the count number in the string (e.g. "5 sites" instead of just "sites")
  505. if (arguments.returnCount && arguments.count != -1)
  506. loc.returnValue = LSNumberFormat(arguments.count) & " " & loc.returnValue;
  507. }
  508. return loc.returnValue;
  509. </cfscript>
  510. </cffunction>
  511. <cffunction name="$singularizeOrPluralize" returntype="string" access="public" output="false" hint="Converts a word to singular or plural form.">
  512. <cfargument name="text" type="string" required="true" hint="See documentation for @pluralize.">
  513. <cfargument name="which" type="string" required="true" hint="See documentation for @$singularizeOrPluralizeWithCount.">
  514. <cfscript>
  515. var loc = {};
  516. loc.returnValue = $args(name="$singularizeOrPluralize", cachable=true, args=arguments);
  517. if (!StructKeyExists(loc, "returnValue"))
  518. {
  519. // default to returning the same string when nothing can be converted
  520. loc.returnValue = arguments.text;
  521. // only pluralize/singularize the last part of a camelCased variable (e.g. in "websiteStatusUpdate" we only change the "update" part)
  522. // also set a variable with the unchanged part of the string (to be prepended before returning final result)
  523. if (REFind("[A-Z]", arguments.text))
  524. {
  525. loc.upperCasePos = REFind("[A-Z]", Reverse(arguments.text));
  526. loc.prepend = Mid(arguments.text, 1, Len(arguments.text)-loc.upperCasePos);
  527. arguments.text = Reverse(Mid(Reverse(arguments.text), 1, loc.upperCasePos));
  528. }
  529. loc.uncountables = "advice,air,blood,deer,equipment,fish,food,furniture,garbage,graffiti,grass,homework,housework,information,knowledge,luggage,mathematics,meat,milk,money,music,pollution,research,rice,sand,series,sheep,soap,software,species,sugar,traffic,transportation,travel,trash,water,feedback";
  530. loc.irregulars = "child,children,foot,feet,man,men,move,moves,person,people,sex,sexes,tooth,teeth,woman,women";
  531. if (ListFindNoCase(loc.uncountables, arguments.text))
  532. {
  533. // this word is the same in both plural and singular so it can just be returned as is
  534. loc.returnValue = arguments.text;
  535. }
  536. else if (ListFindNoCase(loc.irregulars, arguments.text))
  537. {
  538. // this word cannot be converted in a standard way so we return a preset value as specifed in the list above
  539. loc.pos = ListFindNoCase(loc.irregulars, arguments.text);
  540. if (arguments.which == "singularize" && loc.pos MOD 2 == 0)
  541. loc.returnValue = ListGetAt(loc.irregulars, loc.pos-1);
  542. else if (arguments.which == "pluralize" && loc.pos MOD 2 != 0)
  543. loc.returnValue = ListGetAt(loc.irregulars, loc.pos+1);
  544. else
  545. loc.returnValue = arguments.text;
  546. }
  547. else
  548. {
  549. // this word can probably be converted to plural/singular using standard rules so we'll do that
  550. // we'll start by setting the rules and create an array from them
  551. if (arguments.which == "pluralize")
  552. loc.ruleList = "(quiz)$,\1zes,^(ox)$,\1en,([m|l])ouse$,\1ice,(matr|vert|ind)ix|ex$,\1ices,(x|ch|ss|sh)$,\1es,([^aeiouy]|qu)y$,\1ies,(hive)$,\1s,(?:([^f])fe|([lr])f)$,\1\2ves,sis$,ses,([ti])um$,\1a,(buffal|tomat|potat|volcan|her)o$,\1oes,(bu)s$,\1ses,(alias|status)$,\1es,(octop|vir)us$,\1i,(ax|test)is$,\1es,s$,s,$,s";
  553. else if (arguments.which == "singularize")
  554. loc.ruleList = "(quiz)zes$,\1,(matr)ices$,\1ix,(vert|ind)ices$,\1ex,^(ox)en,\1,(alias|status)es$,\1,([octop|vir])i$,\1us,(cris|ax|test)es$,\1is,(shoe)s$,\1,(o)es$,\1,(bus)es$,\1,([m|l])ice$,\1ouse,(x|ch|ss|sh)es$,\1,(m)ovies$,\1ovie,(s)eries$,\1eries,([^aeiouy]|qu)ies$,\1y,([lr])ves$,\1f,(tive)s$,\1,(hive)s$,\1,([^f])ves$,\1fe,(^analy)ses$,\1sis,((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$,\1\2sis,([ti])a$,\1um,(n)ews$,\1ews,(.*)?ss$,\1ss,s$,#Chr(7)#";
  555. loc.rules = ArrayNew(2);
  556. loc.count = 1;
  557. loc.iEnd = ListLen(loc.ruleList);
  558. for (loc.i=1; loc.i <= loc.iEnd; loc.i=loc.i+2)
  559. {
  560. loc.rules[loc.count][1] = ListGetAt(loc.ruleList, loc.i);
  561. loc.rules[loc.count][2] = ListGetAt(loc.ruleList, loc.i+1);
  562. loc.count = loc.count + 1;
  563. }
  564. // loop through the rules looking for a match and perform the regex replace when we find one
  565. loc.iEnd = ArrayLen(loc.rules);
  566. for (loc.i=1; loc.i <= loc.iEnd; loc.i++)
  567. {
  568. if (REFindNoCase(loc.rules[loc.i][1], arguments.text))
  569. {
  570. loc.returnValue = REReplaceNoCase(arguments.text, loc.rules[loc.i][1], loc.rules[loc.i][2]);
  571. break;
  572. }
  573. }
  574. // set back to blank string since we worked around the fact that we can't have blank values in lists above by using Chr(7) instead
  575. loc.returnValue = Replace(loc.returnValue, Chr(7), "", "all");
  576. }
  577. // if this is a camel cased string we need to prepend the unchanged part to the result
  578. if (StructKeyExists(loc, "prepend"))
  579. loc.returnValue = loc.prepend & loc.returnValue;
  580. }
  581. return loc.returnValue;
  582. </cfscript>
  583. </cffunction>