Dark-Pattern Scripting

As I was driving on the road, I received text messages, emails, and phone calls about our site was being hacked. When someone clicked on an email link on any page, they would get a pop-up form instead of their email client. The recipients would get an email from [email protected] instead of the senders’.

My first thought was our site was being hacked with XSS (Cross-Site Scripting) . I called my assistant on my phone and walked her through the diagnose. I asked her to look for strange scripts in our templates. Then I asked her to comment out the script tags, which included Google Tag Manager and Pixel Tracking. When she commented out the Pixel Tracking script from a third-party vendor, the pop-up form went away.

The Pixel Tracking script allowed them to hijack our site and inject XSS into our pages with any email links. The JavaScript codes created the pop-up form. The submission from the pop-up form allows them to obtain all of the email messages. This is a serious privacy concern. Email communications should be between the sender and receiver, not the third-party.

I didn’t work with them on this Pixel Tracking script. When I worked with third-party vendors in the past, I made sure that they told me exactly what they were capturing. They would need to check with me first before they implement these types of dark patterns. I would also limit their tracking to a specific set of pages under a directory instead of the entire site.

“Fuck You Pay Me” CMS

I am working with a proprietary CMS that might as well named “Fuck You Pay Me.”

We don’t have that feature in our CMS out of the box, but we can create it for you. “Fuck You Pay Me.” We don’t have that functionality right out of the box, but we can develop it for you. “Fuck You Pay Me.” We don’t support that technology yet, but we can incorporate it for you. “Fuck You Pay Me.”

The code we wrote won’t work with JavaScript turned off, but we can rewrite it. “Fuck You Pay Me.” We never worked with Service Worker API before, but we can implement it. “Fuck You Pay Me.” Our framework doesn’t support multi-column grid layout, but we can add it for you. “Fuck You Pay Me.”

I am not paying for the bill so go ahead and get your money.

Dynamic Content Migration

Can you explain the migration process for the course catalog, course schedule and syllabi, working papers, clinics and externships, class notes, and student organizations?

The current course catalog has over 400 courses. The landing page is automatically populated from individual courses. The JD focus areas and concentrations are also automatically populated based on the filtering options on individual courses. The discontinued courses are also automatically populated from individual courses. As a result, we only need to maintain and update the individual course. Each course has robust form fields such as course attribute, course credits, semester taught, focus areas and concentrations, and prerequisites. If we lose all of the dynamic functionalities, updating these pages will be a nightmare, especially for those who don’t know HTML. We would need to manually update at least three different places.

Before each semester began, we received the course schedules in Excel from our academic admin. We converted the Excel files into CSV files then imported them into MODX. Then MODX would populate the course schedules. We would need similar functionality in Cascade.

The faculty working papers wouldn’t be any good if they are migrated over as static pages. They are tied with the faculty directories and the none-Mason author directory. This morning I checked, we have 1457 papers. Making changes manually would be a nightmare.

If the new CMS is making the updating process much more complicated than we are not doing it right.

Cascade’s Connectors

As the Law School is migrating to Cascade, one of the services they will provide is connecting the current course catalog in MODX to Cascade. I don’t know much about Cascade and its knowledge base isn’t too helpful. It states that, “Connectors allow you to take advantage of third-party web services by creating a connection between these applications and Cascade CMS.” My understanding is that Cascade will connect with MODX for the course catalog. If that’s the case, we can’t get rid of MODX, but we will be using two CMSes simultaneously. Is this what you get for a $200,000 CMS? It’s not my call.

Implementation Technical Specifications for Cascade

Some of the items I put together for the technical teams at Cascade to review.

Multi-column Layouts

A request for multi-column layouts in Cascade to give us the flexibility to create diffent looks and feels.

RSS Feeds

We offer RSS feeds for our news, spotlights, and faculty working papers. Our events are powered by WordPress, which has an RSS feed as well. On our current site, spotlights aren’t part of the news. The difference is internal vs. external. A news item has a headline linking to an external source. Spotlights are articles we write ourselves. A spotlight has a headline, a thumbnail photo, optional feature photos, and a story. Even though spotlights are different, they can be a category in the news module in Cascade.

RSS Feed for Faculty Working Papers

For our faculty working papers, I recommend having an RSS feed as well. It gives readers an additional way to access the papers, which increases exposures and download rankings.

RSS Parser

We need the ability to parse RSS feeds to display content on our site. We use aggregate RSS feeds from outside sources to pull into our site. Some examples included Google News, Center news (from WordPress), and events (from our EMS Calendar). Both MODX and WordPress have plugins that can parse standard XML and Atom formats. They can be customizable to fit our needs. I thought Cascade could do the same.

Random Function

We use random functions in several cases. The most prominent one is for the image heroes on our homepage. For the technical implementation, we would prefer the execution on the server side rather than the client side. We don’t want to jam any more JS into the users’ browsers. If JS fails to load, our site will be inaccessible.

Responsive Images

For our current homepage banners, we provide two versions: desktop and mobile. Can we do the same in Cascade?

Custom CSS & JavaScript

We need to add custom CSS & JavaScript to a particular page or a set of pages under a directory (inheritance). Can we add custom CSS & JS to the header in Cascade?

Custom Meta Tags

Weworked with SEO agencies to improve our search-engine rankings. They requested the ability to add custom meta tags for keywords and descriptions to a particular page or a set of pages under a directory (inheritance). Can we add custom meta tags to the header in Cascade?

Inject Codes to Header and Footer

We worked with marketing agencies who requested the ability to add pixel trackings to a particular page or a set of pages under a directory (inheritance). Can we add codes to the header and footer in Cascade?

Inheritance

I mentioned inheritance in the three items above. In our current CMS, we have the option to add codes to a set of pages inherited from the parent directory. For instance, if we would like to add a pixel tracking to all of the pages under admissions, we could do so on the admission parent directory. This also works with the secondary set of navigations.

Blank Page Without Any Styling

At times, we needed to publish a blank page without any styling and it allows us to add custom styles for that particular page.

Auto-Generated Anchor Links

Let’s take a look at one of our LLM Admissions FAQs page. There are about 32 questions with answers. To help students read through the questions quickly, we use anchor links. Obviously we can do this manually, but it is super tedious. You have to:

  • Know HTML
  • Write the unordered list
  • Write anchor link for each question
  • Write ID for each H tags
  • Make sure anchor links and H tags match up.
  • In MODX, all of these are dynamically generated. MODX populates all the anchor links and injects IDs into the header of each section based on the H tags. H1 would generate an li, H2 would generate a child of li, and so forth.

    Someone without any knowledge of HTML can just copy and paste a Word Document into MODX, and MODX takes care of all of the coding. This functionality comes right out of the box in MODX. Does Cascade have this functionality out of the box or is it capable of doing this?

List Files In a Directory Using PHP

This handy PHP script will print out all the specified files (.jpg and .png):


<?php
// open this directory
$myDirectory = opendir(".");

// get each entry
while($entryName = readdir($myDirectory)) {
$dirArray[] = $entryName;
}

// close directory
closedir($myDirectory);

// count elements in array
$indexCount = count($dirArray);

// sort 'em
sort($dirArray);

// print 'em

// loop through the array of files and print them all
for($index=0; $index < $indexCount; $index++) {
if ((substr("$dirArray[$index]", -4, 4) == ".jpg") || (substr("$dirArray[$index]", -4, 4) == ".png")){ // only list jpg and png files
print('<img src="'.$dirArray[$index].'">');
}
}

?>

Simple Slideshow

I needed a simple slideshow to display images on a large-screen TV and I came across Simple Fullscreen Image Slideshow. It was exactly what I needed and the codes are just so simple. I loved it so much, I replaced all my Flickity slideshows with this one. Here’s an example. Although it works as webpage, my goal is to create a digital display slider. Here’s the entire page:


<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Slideshow</title>
<style>
@keyframes fadey {
0% { opacity: 0; }
15% { opacity: 1; }
85% { opacity: 1; }
100% { opacity: 0; }
}
body {
  font-family: Avenir, Arial, sans-serif;
  font-size: 0;
  background: #000;
}

body, figure {  margin: 0; padding: 0;}

figure#slideshow {
  width: 100%;
  margin: 0 auto;
  position: relative;
  /*border: 1px solid #000;*/
  cursor: pointer;
}
figure#slideshow img {
  position: absolute;
  left: 0; top: 0;
  width: 100%; height: auto;
  opacity: 0;
}
figure#slideshow img:first-child { position: relative; }

#container:fullscreen {
  display: flex;
  justify-content: center;
  align-items: center;
  background: #000;
}
#container:-moz-full-screen figure, #container:-ms-full-screen figure, #container:-webkit-fullscreen figure, #container:fullscreen figure {
  width: 100%;
  margin: 0 auto;
  background: #000;
}
:-webkit-full-screen {
  width: 100%; height: 100%;
}
*:-moz-full-screen {
  background: #000;
}
*:-webkit-full-screen {
  background: #000;
}
</style>

<script>
function cancelFullScreen() {
if (document.cancelFullScreen) {
document.cancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
} else if (document.msCancelFullScreen) {
document.msCancelFullScreen();
}
link = document.getElementById("container");
link.removeAttribute("onclick");
link.setAttribute("onclick", "fullScreen(this)");
}

function fullScreen(element) {
if (element.requestFullScreen) {
element.requestFullScreen();
} else if (element.webkitRequestFullScreen) {
element.webkitRequestFullScreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
}
link = document.getElementById("container");
link.removeAttribute("onclick");
link.setAttribute("onclick", "cancelFullScreen()");
}

window.onload = function() {
  imgs = document.getElementById('slideshow').children;
  interval = 8000;
  currentPic = 0;
  imgs[currentPic].style.webkitAnimation = 'fadey '+interval+'ms';
  imgs[currentPic].style.animation = 'fadey '+interval+'ms';
  var infiniteLoop = setInterval(function(){
imgs[currentPic].removeAttribute('style');
if ( currentPic == imgs.length - 1) { currentPic = 0; } else { currentPic++; }
imgs[currentPic].style.webkitAnimation = 'fadey '+interval+'ms';
imgs[currentPic].style.animation = 'fadey '+interval+'ms';
  }, interval);
}
</script>
</head>
<body>
<figure id="container" onclick="fullScreen(this)">
<figure id="slideshow">
<img loading="lazy" src="img/01.jpg" alt>
<img loading="lazy" src="img/02.jpg" alt>
<img loading="lazy" src="img/03.jpg" alt>
</figure>
</figure>
</body>
</html>

Hanging Punctuation in CSS

To hang your quotes in CSS, this is all you need:


html {
  hanging-punctuation: first allow-end last;
}

At the time of this writing, only Safari implemented this property. To make it work in other browsers, negative text-indent is needed. Nevertheless, I went ahead and added hanging-punctuation and removed text-indent for the title of JAY-Z’s song from the Beacon of HOV project. That way, the hanging punctuation would just work in all browsers in the future.

MODX Support Team Rocks!

The MODX Support Team had proved once again to be indisputable in customer service. Their team members assisted us every step of the way to migrate the Scalia Law School’s CDN and WAF from StackPath over to CloudFlare Enterprise. We ran into a few obstacles during the process, but they were patience, responsive, and diligence in making sure that we succeeded in the migration.

If you need a CMS that offers flexibility, durability, and security, MODX is the solution. If you need a rock-solid hosting with top-notch support, MODX Cloud is the way to go. The Scalia Law School Website has been powered by MODX for more than 15 years and hosted by MODX Cloud for more than 3 years.

In the CMS space, MODX beats WordPress, Drupal, Joomla, and Cascade to the pulp. Hats off to Jay, Liz, Garry, Ryan, and Jimmy. You all rock!

My Reports & Responses to User Testing Acceptance

My response on server configurations:

Hi D,

For the global elements, using include files make sense, but it is also too heavy-handed to rely on PHP or ASPX for these tasks.

For caching, not just images, but also HTML, JS, CSS, PDFs, DOCX, XLSX, PPTX, Font Files, etc. It is good that your server optimizes images for the web before they hit the sites, but furthermore, it should serve responsive images (small size for mobile, medium size for tablet, and large size for desktop). All the codes should also be compressed for optimization.

For the quotes on CDN and failover, I defer to my supervisor who will also have the final words on caching strategy and the server configurations for the global elements.

Thank you for your response and patience.

My response on Service Worker:

In our initial meeting, we asked for Service Workers API and M had agreed to implement it. The test page shows no registration and the pages do not work offline.

I am surprised to learn that your company had never implemented Service Workers. Registering the entire site would be too much, but just a handful of important pages such as PeopleFinder, Admissions, Course Offerings, etc. would be doable.

Getting a quote to implemented Service Workers is above my pay rate. I defer to my supervisor.

My response on no JavaScript:

As I had mentioned in our initial meeting, we would like our site to be built with progressive enhancement; therefore, our site should work even without JS to accommodate all type of users. JS should enhance the user experience and should not hinder basic functionality. The HTML pages provided are not working with JS turned off. Please fix this issue.

We received many complaints in the past that our site didn’t work with Javascript turned off. They didn’t want JS pop-up ads. They didn’t want JS third-party trackings. These are valid points; therefore, we had to make our site work without JS. Of course, we had to use JS for things like table sorting and such, but the tables still work without the sorting functions.

Our standard practice doesn’t depend on technologies. Our standard practice is to make our website as accessible and usable as possible. Our mission is to provide an inclusive, not exclusive, experience. We use JavaScript as an enhancement, not a requirement. If users have JavaScript turned on, they will get the enhanced interactive experience. If they don’t, they are not excluded from our content. The new test pages rely heavily on JavaScripts. Even if users have JavaScript enabled, they would also be blocked from accessing the website if JavaScripts failed to load.

As I had pointed out, we received complaints about our current site not being accessible without JavaScript and we had to rework our codes to make it work without JS first. It was easier for us to recode our site because we built everything from scratch and not relying on any frameworks that depended heavily on JavaScripts.

As a developer, I understand this is a daunting task, but my responsibility is to report the issues. My supervisor will make the final decision on how we should proceed.

My response on tables not display in full:

On large screens, especially desktops, the table should display in full and not cut off. This limitation will cause accessibility and usability issues. It’s my supervisor call.

My response on variable fonts:

Since Montserrat is a huge family. Using static fonts wastes too much bandwidth. Please switch to VF fonts.

Not just loading, but also adding extra fonts that we might never use. I am pretty sure we will never use hairline and thin weight or bold italics and black italics. Right now you are loading 18 font files. With variable fonts, you only need 2. You can cut down 16 files. VF is much more flexible. You can choose an infinite number of weights. For instance what if I want the text to be thinker but not too bold. With static fonts, I can choose either 400 or 500. With variable font, I can choose anything between 400-500.

My response on indicators for linking to documents:

This issue is reported by our IT Accessibility Expert. I concur with her and strongly recommend that we have an icon indicator for each linking file type to improve accessibility. We currently apply this practice on our current site. I defer to my supervisor if we need to continue this practice or not on the new site.

My response on header issue with nav links wrapped:

UI is best set in a sans-serif typeface. If we were to choose another sans serif, I wouldn’t keep Montserrat. Using 2 sans-serif typefaces would cause confusion. Furthermore, it would make us looks amateurs. If you want to keep Montserrat, we would need to find a different solution for the nav, which is to move it to the top.

That’s just my suggestion. My supervisor will make the call.

My response on layout options:

I am not seeing any layout options for the main text area. Is it always main content on the left and sidebar on the right? Is there a full-width option? Is there a split 2-2 option? 1-3 option?

We did talk about flexible layouts with Brad. We even showed examples.

I defer this to my supervisor.

My response on site performance:

The point of performance score is based on internet connections, images, assets (css, js, etc); therefore, the goal is to optimize for the sites for these circumstances. It is not related to your CMS, but definitely related to front-end development.

I have all of these issues written down for the record. I pointed out the problems and made the suggestions. I don’t have the power to make the final decisions. If the site wouldn’t work as expected later on, it would not be my fault.

Bonjour Vietnam