I am trying to take convert urls in a block of html to ensure they are lowercase.
Some of the links are a mix of uppercase and lowercase and they need to be converted to just lowercase.
It would be impossible to run round the site and redo every link so was looking to use a Regex when outputting the text.
<p>Hello world Some link.</p>
Needs to be converted to:
<p>Hello world Some link.</p>
Using a ColdFusion Regex such as below (although this doesn't work):
<cfset content = Rereplace(content,'(http[*])','\L\1','All')>
Any help much appreciated.
I think I would use the lower case function, lCase().
Put your URL into a variable, if it's not already:
<cfset MyVar = "http://www.ThisSite.com">
Force it to lower case here:
<cfset MyVar = lCase(MyVar)>
Or here:
<cfoutput>
Some Link
</cfoutput>
UPDATE: Actually, I see that what you are actually asking is how to generate your entire HTML page (or a big portion) and then go back through it, find all of the links, and then lower their cases. Is that what you are trying to do?
Since you have the HTML stored in a database, there is a bit more work that needs to be done than just using lcase(). I would wrap the functionality into a function that can be easily reused. Check out this code for an example.
content = '<p>Hello world Some link.</p>
<p>Hello world Some link.</p>
<p>Hello world <a href=''http://www.somelink.com/BLARG''>Some link</a>.</p>';
writeDump( content );
writeDump( fixLinks( content ) );
function fixLinks( str ){
var links = REMatch( 'http[^"'']*', str );
for( var link in links ){
str = replace( str, link, lcase( link ), "ALL" );
}
return str;
}
This has only been tested in CF9 & CF10.
Using REMatch() you get an array of matches. You then simply loop over that array and use replace() with lcase() to make the links lowercase.
And...based on Leigh's suggestion, here is a solution in one line of code using REReplace()
REReplace( content, '(http[^"'']*)', '\L\1', 'all' )
Use a HTML parser to parse HTML, not regex.
Here's how you can do it with jQuery:
<!doctype html>
<script src="jquery.js"></script>
<cfsavecontent variable="HtmlCode">
<p>Hello world Some link.</p>
</cfsavecontent>
<pre></pre>
<script>
var HtmlCode = "<cfoutput>#JsStringFormat(HtmlCode)#</cfoutput>";
HtmlCode = jQuery('a[href]',HtmlCode).each( lowercaseHref ).end().html();
function lowercaseHref(index,item)
{
var $item = jQuery(item);
// prevent non-links from being changed
// (alternatively, can check for specific domain, etc)
if ( $item.attr('href').startsWith('#') )
return
$item.attr( 'href' , $item.attr('href').toLowerCase() );
}
jQuery('pre').text(HtmlCode);
</script>
This works for href attributes on a tags, but can of course be updated for other things.
It will ignore in-page links like <a href="#SomeId"> but not stuff like <a href="/HOME/#SomeId"> - if that's an issue you'd need to update the function to exclude page fragment part (e.g. split on # then rejoin, or whatever). Same goes if you might have case-sensitive querystrings.
And of course the above is just jQuery because I felt like it - you could also use a server-side HTML parser, like jSoup to achieve this.
I want a clientside user to be able to insert text in text input box, click 'replace' and have a list of hyperlinks replaced accordingly. Anchor text will stay the same, but the hyperlink will change.
My problem: I am only getting the first hyperlink to change. I have a fiddle set up with two links, and you can see only the first changes. I want a list of, say, 20 links to change at once.
jsfiddle.net/TKxuf/
HTML:
<input id="replace" type="text" value="newphrase" />
<input onclick="doReplace()" type="button" value="Replace!" />
<br/>
<p id="list">Google Keyword Search</p>
<p id="list">Yahoo Keyword Search</p>
JavaScript:
function doReplace() {
var s = "keyword";
var r = document.getElementById('replace').value;
var oldtext = document.getElementById('list').innerHTML;
var newtext = oldtext.replace( s, r );
console.log(s);
console.log(r);
console.log(document.getElementById('list'));
document.getElementById('list').innerHTML = newtext;
}
I can't work out why you'd want the original strings in the HTML page code to begin with, so I'd suggest that you may have a problem with your approach. Note also that it's illegal in HTML to have more than one element with the same Id, which mostly explains why getElementById only returns one item. Also external urls must be preceded by http:// too.
I usually use jQuery these days - in jQuery you could simply swap id="list" to class="list" and use $('.list') to get a list of them all. $('.list').each(function() { var item = this; /* manipulation code here */ }); would allow you to change them all, but you may have to do some reading.
In any case, I still think that your approach is wrong.
What I'd do is have a normal javascript array of Urls, with replacable keys that are difficult to confuse as part of the url, e.g.
var addresses = [
{ text: "Google Keyword Search", url: "http://google.com?q=%keyword%" },
{ text: "Yahoo Keyword Search", url: "http://yahoo.com?q=%keyword%" }
];
When your user searches, you then build up your new html code into a string by iterating through the array:
var output = '';
for (var i = 0; i<addresses.length; i++) {
var item = addresses[i];
output += '<p>'+item.text+'</p>';
}
Note: I haven't checked this code, but you should be able to get the idea. You'd actually write out all the entire list by using innerHTML on the list container.
Hope that this helps.
Best Regards,
Mark Rabjohn
Integrated Arts Limited
I am implementing a Google (line) Chart based on a DataTable so I can change the type of graph 'on the fly'. I have successfully generated the data table (generated by script) based on https://developers.google.com/chart/interactive/docs/reference#dataparam
And implemented in an HTML Page (for testing purpose the page is empty so there is no interference with any other script/content)
The Y-axis, Legenda and lines are correctly generated, yet the x-axis appears to be missing.
I am using the following content for the data table:
{"cols":[{"id":"timestamp","label":"timestamp","pattern":"","type":"string"},{"id":"sy","label":"sy","pattern":"","type":"number"},{"id":"us","label":"us","pattern":"","type":"number"},{"id":"average_cpu","label":"average_cpu","pattern":"","type":"number"}],"rows":[{"c":[{"v":"1372249356","f":""},{"v":0,"f":""},{"v":4,"f":""},{"v":43,"f":""}]},{"c":[{"v":"1372249650","f":""},{"v":13,"f":""},{"v":46,"f":""},{"v":49,"f":""}]},{"c":[{"v":"1372249950","f":""},{"v":4,"f":""},{"v":45,"f":""},{"v":47,"f":""}]},{"c":[{"v":"1372250250","f":""},{"v":2,"f":""},{"v":19,"f":""},{"v":46,"f":""}]},{"c":[{"v":"1372250550","f":""},{"v":3,"f":""},{"v":46,"f":""},{"v":51,"f":""}]}]}
This all comes together in the following Javascript
<html>
<head>
<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script type="text/javascript">
// Load the Visualization API and the piechart package.
google.load('visualization', '1', {'packages':['corechart']});
</script>
<script type="text/javascript">
google.setOnLoadCallback(draw_15a6f1d2a7556b357de0d315596aa96c);
function draw_15a6f1d2a7556b357de0d315596aa96c() {
var data = new google.visualization.DataTable({"cols":[{"id":"timestamp","label":"timestamp","pattern":"","type":"string"},{"id":"sy","label":"sy","pattern":"","type":"number"},{"id":"us","label":"us","pattern":"","type":"number"},{"id":"average_cpu","label":"average_cpu","pattern":"","type":"number"}],"rows":[{"c":[{"v":"1372249356","f":""},{"v":0,"f":""},{"v":4,"f":""},{"v":43,"f":""}]},{"c":[{"v":"1372249650","f":""},{"v":13,"f":""},{"v":46,"f":""},{"v":49,"f":""}]},{"c":[{"v":"1372249950","f":""},{"v":4,"f":""},{"v":45,"f":""},{"v":47,"f":""}]},{"c":[{"v":"1372250250","f":""},{"v":2,"f":""},{"v":19,"f":""},{"v":46,"f":""}]},{"c":[{"v":"1372250550","f":""},{"v":3,"f":""},{"v":46,"f":""},{"v":51,"f":""}]}]});
var chart = new google.visualization.LineChart(document.getElementById('draw_15a6f1d2a7556b357de0d315596aa96c'));
chart.draw(data, {width: 800, height: 600});
}
</script>
</head>
<body>
<div id="draw_15a6f1d2a7556b357de0d315596aa96c"></div>
</body>
</html>
Yet I have no idea why the X-axis is not showing up. I have looked into the DataTable Roles but could not find a reference to show the X-axis
https://developers.google.com/chart/interactive/docs/roles?hl=ja#jsonliteral
Nor does the LineChart documentation say which additional arguments have to be supplied.
jsfiddle.net/WuLWF/ (When breaking it up in pieces according to Fiddle standard it did not work)
Or perhaps my DataTable is wrong generated.
Please guide me in the correct direction,
Many thanks
The x-axis is showing up but the labels are not showing up. Your first column is of type string, so you wouldn't see gridlines in any case, but for each row, the first column "f" property is an empty string, which means it will be displayed in the axis label as an empty string, just as it does.
I bet you did this so the tooltips would not show these same values. You might want to investigate custom tooltips to display whatever you want in the tooltips.
If you had used numbers instead of strings for the first column, then the axis labels would be generated and displayed as numbers, using the axis format option, and the values might happen to be close to the same values as in your first column. Discrete string values are used as is.
Or perhaps you would prefer to use a type of date, datetime, or timeofday. These are also treated as continuous, like numbers, rather than discrete, so the formatting of the tick labels is determined by the axis format option. Hope that helps.
I just started using dotCMS for work to modify the existing website. I am trying to create a widget that takes a custom structure field called urlTitle. It takes the Title of an event and makes it url friendly. Here is a tutorial describing the urlTitle
I have a regex that is written fine for javascript. My problem is when I try to use the same regex in velocity, I am getting some troubles.
Here is the javascript from the tutorial:
<script>
function updateDisplayURLTitle(){
// get the title entered by the user
var plainTitle = dojo.byId("title");
// make a friendly url
var urlTitle = plainTitle.value.toLowerCase();
urlTitle= urlTitle.replace(/^\s+|\s+$/g,"");
urlTitle = urlTitle.replace(/[^a-zA-Z 0-9]+/g,' ');
urlTitle = urlTitle.replace(/\s/g, "-");
while(urlTitle.indexOf("--") > -1){
urlTitle = urlTitle.replace("--",'-');
}
// set the values of the display place holder and the custom field
// the is to hold the div open
dojo.byId("displayURLTitle").innerHTML = urlTitle;
dojo.byId("urlTitle").value=urlTitle;
}
// attach this the text1 field onchange
dojo.connect(dojo.byId("title"), "onchange", null, "updateDisplayURLTitle");
// populate the field on load
dojo.addOnLoad(updateDisplayURLTitle);
</script>
<div id="displayURLTitle" style="height:20px"> </div>
Then here is my velocity code for my widget:
#set($nowsers = $date.format('yyyyMMddHHmmss', $date.getDate()))
#set($con = $dotcontent.pull("+structureName:calendarEvent +(conhost:48190c8c-42c4-46af-8d1a-0cd5db894797 conhost:SYSTEM_HOST) +calendarEvent.startDate:[$nowsers TO 21001010101000]",1,"calendarEvent.startDate"))
<ul>
#foreach($event in $con)
<li>
$event.title
<p> $event.description</p>
</li>
#set($temp = $event.title.toLowerCase())
#set($temp = $temp.replaceAll('/^\s+|\s+$/g', ""))
#set($temp = $temp.replaceAll('/[^a-zA-Z 0-9]+/g', " "))
#set($temp = $temp.replaceAll('/\s/g', "-"))
$temp
$temp
#end
My goal is to have the regex from the javascript work with the velocity. Right now it doesn't work and I'm not that skilled with regex, so far my research has lead me nowhere.
Another thing I cant figure out is what the /g does. I can't find it in any regex resource website.
I figured it out. It turns out that the escape characer / in front of the regex patter, and the /g were causing the pattern to fail so it must not be needed for the method used in velocity.
Here is the scenario... I have a a checkbox next to each field that I am replacing on page load with jquery with "Delete" text that enables me to delete the field via jquery, which is working fine. Like so...
$(".profile-status-box").each(function(){ $(this).replaceWith('<span class="delete">' + 'Delete' + '</span>') });
The problem comes in however is that after page load, I am also giving the user the option to dynamically add new fields. The new added fields though have the checkbox and not the delete link because they are not being replaced by jquery since they are being added after the initial page load.
Is't possible to replace the content of new elements added to the page without doing a page refresh? If not, I can always have two templates with different markup depending one for js and one for non js, but I was trying to avoind taht.
Thanks in advance.
You can use the .livequery() plugin, like this:
$(".profile-status-box").livequery(function(){
$(this).replaceWith('<span class="delete">Delete</span>')
});
The anonymous function is run against every element found, and each new element matching the selector as they're added.
Have a look at this kool demo. It removes and adds elements like a charm.
http://www.dustindiaz.com/basement/addRemoveChild.html
Here's how:
First of all, the (x)html is real simple.
xHTML Snippet
<input type="hidden" value="0" id="theValue" />
<p>Add Some Elements</p>
<div id="myDiv"> </div>
The hidden input element simply gives you a chance to dynamically call a number you could start with. This, for instance could be set with PHP or ASP. The onclick event handler is used to call the function. Lastly, the div element is set and ready to receive some children appended unto itself (gosh that sounds wierd).
Mkay, so far so easy. Now the JS functions.
addElement JavaScript Function
function addElement() {
var ni = document.getElementById('myDiv');
var numi = document.getElementById('theValue');
var num = (document.getElementById('theValue').value -1)+ 2;
numi.value = num;
var newdiv = document.createElement('div');
var divIdName = 'my'+num+'Div';
newdiv.setAttribute('id',divIdName);
newdiv.innerHTML = 'Element Number '+num+' has been added! <a href=\'#\' onclick=\'removeElement('+divIdName+')\'>Remove the div "'+divIdName+'"</a>';
ni.appendChild(newdiv);
}
And if you want to,
removeElement JavaScript Function
function removeElement(divNum) {
var d = document.getElementById('myDiv');
var olddiv = document.getElementById(divNum);
d.removeChild(olddiv);
}
and thats that. bobs your uncle.
This is taken from this article/tutorial: http://www.dustindiaz.com/add-and-remove-html-elements-dynamically-with-javascript/
I've just learnt this myself. thank you for the question
Hope that helps.
PK