JavaScript - Generating Image Boxes from a Text Area

From NoskeWiki
Jump to navigation Jump to search
Generating Ack Slides


About

NOTE: This page is a daughter page of: JavaScript


I'm a big fan of starting a presentation with an Acknowledgement slides which includes everyone's photo, but making such a slide is pretty slow if you have five or more people. This tool lets you enter the names of people and will either generate a link to their profile photo (most good orgs have this ability) or specify your own image URL for each person's photo.


Generation of Acknowledgement Slides from a Text Area

ack-generator.html:

<!DOCTYPE html>
<html>
<!--
Copyright 2017 Andrew Noske... (please just leave in my link)
https://andrewnoske.com/wiki/JavaScript_-_Generating_Image_Boxes_from_a_Text_Area
-->
<head>
  <title>Acknowledgement Slide Generator</title>
  <link href='https://fonts.googleapis.com/css?family=Overpass' rel='stylesheet'>
  <link href="ack-generator.css" rel="stylesheet">
  
  <script>
  function GenerateAcks() {
    // Get element references:
    var txtPeople = document.getElementById("txt-people");
    var txtFeedback = document.getElementById("txt-feedback");
    var cmbStyleName = document.getElementById("cmb-style-name");
    var divAckArea = document.getElementById("div-ack-area");
    
    var masterDivClass = cmbStyleName.value;
    var teamAreaClass = "team-area";
    var personAreaClass = "person-area";
    var nameAreaClass = "name-area";

    // Clear generated area:
    while (divAckArea.firstChild) {
      divAckArea.removeChild(divAckArea.firstChild);
    }
    
    // Add master div:
    var masterDiv =  document.createElement("div");
    masterDiv.setAttribute('class', masterDivClass);
    divAckArea.appendChild(masterDiv);
    var currentDiv = masterDiv;  // Points where we want to append next element.
    
    // Split text apart:
    var text = txtPeople.value;
    var errorsArr = [];    
    var lines = text.split("\n");
    
    // For each line:
    for (var i = 0; i < lines.length; i++) {
      var line = lines[i].trim();
      if (line.startsWith("#")) {         // Skip commented lines.
        continue;
      }
      if (line == "") {                   // Treat empty lines as newlines.
        line = "NEWLINE:";
      }
      if (line.startsWith("NEWLINE") ||   // Special case for newlines / hr lines.
          line.startsWith("HR")) {
        line = line + ":";                 
      }
      if (line.indexOf(":") == -1) {      // Default to big pic.
        line = "PERSON:" + line;
      }
 
      // Take line          (eg: "PERSON:Andrew,anoske@")
      // and isolate:
      //   the itemType     (eg: "PERSON")
      //   and properties   (eg: ["Andrew", "anoske@"]).
      var idxSplit = line.indexOf(":");
      var itemType = line.substr(0, idxSplit).trim();  // Item type should be at the front.
      var itemProperties = itemProperties = line.substr(idxSplit+1).trim().split(",");
      
      // Add correct content for item type:
      switch (itemType) {
          
        case "TEAM":
          var title = "";
          if (itemProperties.length >= 1) {
            title = itemProperties[0];
          } else {
            errorsArr.push("ERROR: Line " + String(i) + ": No team name.");
          }
          
          var teamDivHeader =  document.createElement("div");
          teamDivHeader.setAttribute('class', 'team-header');
          teamDivHeader.textContent = title;
          
          var teamDiv = document.createElement("div");
          teamDiv.setAttribute('class', teamAreaClass);
          teamDiv.appendChild(teamDivHeader);
                    
          masterDiv.appendChild(teamDiv);
          currentDiv = teamDiv;

          break;
          
        case "PERSON":
        case "PERSON_LITTLE_PIC":
        case "PERSON_NO_PIC":
        case "NAME":
          // Get property values:
          var name = "";
          var username = "";
          var comment = "";
          var imgSrcUrl = "";
          if (itemProperties.length >= 1) {
            name = itemProperties[0].trim();
          } else {
            errorsArr.push("ERROR: Line " + String(i) + ": No person name!");
            continue;
          }
          if (itemProperties.length >= 2) {
            username = itemProperties[1].trim();
            username = username.replace("@google.com", "");
            username = username.replace("@", "");
          }
          if (itemProperties.length >= 3) {
            comment = itemProperties[2].trim();
          }
          if (itemProperties.length >= 3) {
            comment = itemProperties[2].trim();
          }
          if (itemProperties.length >= 4) {
            imgSrcUrl = itemProperties[3].trim();
          }

          // Derived properties:
          var showPic = itemType == "PERSON" || itemType == "PERSON_LITTLE_PIC";
          var nameClass = itemType == "NAME";
          var personDivUernameLink =  document.createElement("a");
          if (imgSrcUrl == "") {
            imgSrcUrl = "https://moma-teams-photos.corp.google.com/photos/" + username;
          }
          var personClass = nameClass ? nameAreaClass : personAreaClass;

          // Create containing div for person:
          var personDiv = document.createElement("div");
          personDiv.setAttribute('class', personClass);
          
          // Add picture:
          if (username != "" && showPic) {
            var personImg =  document.createElement("img");
            if (itemType == "PERSON") {
              personImg.setAttribute('class', 'person-big-pic');
            } else if (itemType == "PERSON_LITTLE_PIC") {
              personImg.setAttribute('class', 'person-little-pic');
            }
            personImg.setAttribute('src', imgSrcUrl);
            personDiv.appendChild(personImg);
          }
          // Add name:
          if (name != "") {
            var personDivName =  document.createElement("div");
            personDivName.setAttribute('class', 'person-name');
            personDivName.textContent = name;
            personDiv.appendChild(personDivName);
          }
          // Add username:
          if (username != "") {
            console.log("OUT:" + line);
            var personDivUsername =  document.createElement("div");
            personDivUsername.setAttribute('class', 'person-username');
            personDivUsername.setAttribute('title', 'Open in Moma');
            var momaPageUrl = "http://teams/" + username;
            personDivUernameLink.setAttribute('href', momaPageUrl);
            personDivUernameLink.setAttribute('target', 'blank_');
            personDivUernameLink.textContent = username + '@';
            personDivUsername.appendChild(personDivUernameLink);
            personDiv.appendChild(personDivUsername);
          }
          // Add comment:
          if (comment != "") {
            var personDivComment =  document.createElement("div");
            personDivComment.setAttribute('class', 'person-comment');
            personDivComment.textContent = comment;
            personDiv.appendChild(personDivComment);
          }

          currentDiv.appendChild(personDiv);
          
          break;
          
        case "NEWLINE":
          var hrElement =  document.createElement("br");
          currentDiv.appendChild(hrElement);          
          break;

        case "HR":
          var hrElement =  document.createElement("hr");
          currentDiv.appendChild(hrElement);
          break;

        case "TEXT":
          var shortText = "";
          if (itemProperties.length >= 1) {
            shortText = itemProperties[0];
          } else {
            errorsArr.push("ERROR: Line " + String(i) + ": No text.");
          }
          var textDiv =  document.createElement("div");
          textDiv.textContent = shortText;
          currentDiv.appendChild(textDiv);

          break;

        default:
          errorsArr.push("ERROR: Not recognized '" + itemType + "'");
          console.log();
      }

      
    }
    
    // Update feedback area with text:
    if (errorsArr.length == 0) {
      txtFeedback.value = "No errors!";
    } else {
      txtFeedback.value = errorsArr.join("\n");
    }
  }
  </script>
  
</head>
<body>
  <h1>Acknowledgement Slide Generator</h1>
  
  Enter your Googler team mates below and hit generate.      

  <table border="0" width="100%">
   <tr>
    <td width="300px" valign="top">
      
<!-- INPUT AREA START =============================================== -->
<textarea rows="18" cols="50" id="txt-people">
TEAM:Geo Photo Crowd Sourcing
PERSON:Andrew,anoske@,(crowdsourcing)
PERSON:Ye,yeya@,(political)

TEAM:Machine Learning (New York)
PERSON_NO_PIC:Sema,berkiten@
PERSON_NO_PIC:Jared J,sloth@

TEAM:Others
TEXT:Special thanks to:
NAME:Amit,,(team lead)

NAME:Mona
NAME:Silvian
  
PERSON_LITTLE_PIC:Ronnie,linkedin,we miss you!,https://anoske.users.x20web.corp.google.com/www/googlerstats/ack_generator/images/ronnie.jpg
</textarea>

<br>
<br>

<table border="0" width="100%">
 <tr>
  <td>Style preset:</td>
  <td>
    <select id="cmb-style-name" onchange="GenerateAcks();">
      <option value="master-grey-boxes">Grey boxes</option>
      <option value="master-moma-round">Moma round</option>
      <option value="master-midnight" selected>Midnight</option>
    </select>
  </td>
 </tr>
</table>

<br>
<br>
<div id="div-tips-area">
Feedback:
<br>
<textarea rows="6" cols="50" id="txt-feedback" readonly>
Change the text above!... try:
TEAM:Bumper Cars
PERSON:Andrew,anoske@,Crowdsourcing
PERSON_LITTLE_PIC:Jared,sloth@,Crowdsourcing
</textarea>
</div>
<!-- INPUT AREA END ================================================= -->
      
    </td>
    <td valign="top" width="100ox">
      
<button type="button" onclick="GenerateAcks();">Generate!</button>

    </td>
    <td valign="top">

<!-- OUTPUT AREA START =============================================== -->
<div id="div-ack-area"></div>
<!-- OUTPUT AREA END ================================================= -->
      
    </td>
   </tr>
  </table>

  
  
  <script>
  GenerateAcks();
  </script>
  
  

</body>
</html>


ack-generator.css:

/**
 * Copyright 2017 Andrew Noske... (please just leave in my link)
 * https://andrewnoske.com/wiki/JavaScript_-_Generating_Image_Boxes_from_a_Text_Area
 */

html {
  height: 100%;
}

body {
  font-family: "Overpass";
  font-size: 13px;
  margin: 10px;
  padding: 10px;
}

/*
 * Div area CSS pieces:
 */

#div-tips-area {
  background: rgb(238, 238, 238);
}

#txt-feedback {
  margin-left: 15px;
  border: 0px solid #6b90da;
  color: #999;
  background: rgb(238, 238, 238);
  width: 90%;
}


/*
 * ============================================================
 * master-grey-boxes
 * ============================================================
 */
.master-grey-boxes {
  font-family: Arial, Sans-serif;
  text-decoration: none;
  color: #000;
}

/* Team area */
.master-grey-boxes .team-area {
  margin-bottom: 20px;
  border: 0;
  padding: 5;
  cursor: default;
  background: #fff;
  min-width: 200px;
}
.master-grey-boxes .team-area .team-header {
  font-size: 18px;
  font-weight: bolder;
}

/* Person area */
.master-grey-boxes .person-area {
  width: 200px;
  margin: 10px;
  padding: 5px;
  background: rgb(238, 238, 238);
  max-width: 90px;
  border: 1px solid grey;
  display: inline-block;
}
.master-grey-boxes .person-area .person-name {
  font-size: 14px;
  font-weight: bolder;
}
.master-grey-boxes .person-area .person-big-pic {
  object-fit: cover;
  object-position: center;
  width: 90px;
  height: 90px;
}
.master-grey-boxes .person-area .person-little-pic {
  object-fit: cover;
  object-position: center;
  width: 90px;
  height: 60px;
}
.master-grey-boxes .person-area .person-username {
  font-size: 10px;
  font-style: italic;
}
.master-grey-boxes .person-area .person-username a {
  color: #000;
  text-decoration: none;
}
.master-grey-boxes .person-area .person-comment {
  font-size: 12px;
}

/* Name area */
.master-grey-boxes .name-area {
  margin-left: 10px;
  display: inline-block;
}
.master-grey-boxes .name-area .person-name {
  font-size: 14px;
  font-weight: bolder;
  display: inline;
}
.master-grey-boxes .name-area .person-username {
  margin-left: 5px;
  font-size: 10px;
  font-style: italic;
  display: inline;
}
.master-grey-boxes .name-area .person-username a {
  color: #000;
  text-decoration: none;
  display: inline;
}
.master-grey-boxes .name-area .person-comment {
  margin-left: 5px;
  font-size: 10px;
  display: inline;
}


/*
 * ============================================================
 * master-moma-round
 * ============================================================
 */
.master-moma-round {
  font-family: Arial, Sans-serif;
  text-decoration: none;
  color: #000;
}

/* Team area */
.master-moma-round .team-area {
  margin-bottom: 20px;
  border: 0;
  padding: 5;
  cursor: default;
  position: relative;
}
.master-moma-round .team-area .team-header {
  font-size: 18px;
  font-weight: bolder;
}

/* Person area */
.master-moma-round .person-area {
  width: 200px;
  margin: 10px;
  max-width: 90px;
  display: inline-block;
  position: relative;
  min-width: 300px;
  min-height: 100px;
}
.master-moma-round .person-area .person-name {
  z-index: -1;  /* Behind photo. */
  position: absolute;
  top: 35px;
  left: 50px;
  font-size: 14px;
  font-weight: bolder;
  padding: 5px;
  padding-left: 60px;
  border: 0px solid grey;
  font-size: 20px;
  font-weight: bolder;
  background: #1967d2;
  color: white;
  width: 150px;
  height: 30px;
  line-height: 30px;
}
.master-moma-round .person-area .person-big-pic {
  position: absolute;
  border-radius: 50%;
  border: 4px solid #1967d2;
  object-fit: cover;
  object-position: center;
  width: 90px;
  height: 90px;
}
.master-moma-round .person-area .person-little-pic {
  position: absolute;
  top: 20px;
  border-radius: 50%;
  border: 4px solid #1967d2;
  object-fit: cover;
  object-position: center;
  width: 60px;
  height: 60px;
}
.master-moma-round .person-area .person-username {
  position: absolute;
  top: 80px;
  left: 100px;
  font-size: 12px;
  font-style: italic;
}
.master-moma-round .person-area .person-username a {
  color: #000;
  text-decoration: none;
}
.master-moma-round .person-area .person-comment {
  position: absolute;
  top: 80px;
  left: 160px;
  font-size: 12px;
}

/* Name area */
.master-moma-round .name-area {
  margin-left: 10px;
  display: inline-block;
}
.master-moma-round .name-area .person-name {
  font-size: 14px;
  font-weight: bolder;
  display: inline;
}
.master-moma-round .name-area .person-username {
  margin-left: 5px;
  font-size: 10px;
  font-style: italic;
  display: inline;
}
.master-moma-round .name-area .person-username a {
  color: #000;
  text-decoration: none;
  display: inline;
}
.master-moma-round .name-area .person-comment {
  margin-left: 5px;
  font-size: 10px;
  display: inline;
}


/*
 * ============================================================
 * master-midnight
 * ============================================================
 */
.master-midnight {
  font-family: Arial, Sans-serif;
  color: #fff;
}

/* Team area */
.master-midnight .team-area {
  margin-bottom: 20px;
  border: 15;
  padding: 15;
  color: black;
  background: #bbb;
  min-width: 80px;
}
.master-midnight .team-area .team-header {
  font-size: 18px;
  font-weight: bolder;
}

/* Person area */
.master-midnight .person-area {
  margin: 10px;
  padding: 5px;
  max-width: 90px;
  border-radius: 8px;
  border: 2px solid #111;
  color: #fff;
  background: #666;
  display: inline-block;
}
.master-midnight .person-area .person-name {
  font-size: 14px;
  font-weight: bolder;
}
.master-midnight .person-area .person-big-pic {
  object-fit: cover;
  object-position: center;
  width: 90px;
  height: 90px;
  display: inline-block;
}
.master-midnight .person-area .person-little-pic {
  object-fit: cover;
  object-position: center;
  width: 60px;
  height: 60px;
  display: inline-block;
}
.master-midnight .person-area .person-username {
  font-size: 10px;
  font-style: italic;
}
.master-midnight .person-area .person-username a {
  color: #ccc;
}
.master-midnight .person-area .person-comment {
  font-size: 12px;
}

/* Name area */
.master-midnight .name-area {
  margin-left: 10px;
  display: inline-block;
}
.master-midnight .name-area .person-name {
  font-size: 14px;
  font-weight: bolder;
  display: inline;
}
.master-midnight .name-area .person-username {
  margin-left: 5px;
  font-size: 10px;
  font-style: italic;
  display: inline;
}
.master-midnight .name-area .person-username a {
  color: #000;
  text-decoration: none;
  display: inline;
}
.master-midnight .name-area .person-comment {
  margin-left: 5px;
  font-size: 10px;
  display: inline;
}


Code license
For all of the code on my site... if there are specific instruction or licence comments please leave them in. If you copy my code with minimum modifications to another webpage, or into any code other people will see I would love an acknowledgment to my site.... otherwise, the license for this code is more-or-less WTFPL (do what you want)! If only copying <20 lines, then don't bother. That said - if you'd like to add a web-link to my site www.andrewnoske.com or (better yet) the specific page with code, that's a really sweet gestures! Links to the page may be useful to yourself or your users and helps increase traffic to my site. Hope my code is useful! :)