--- /dev/null
+
+[% BLOCK state_selector %]
+<select name="[% name %]" id="[% id %]">
+<option value="Alabama">Alabama</option>
+<option value="Alaska">Alaska</option>
+<option value="Arizona">Arizona</option>
+<option value="Arkansas">Arkansas</option>
+<option value="California">California</option>
+<option value="Colorado">Colorado</option>
+<option value="Connecticut">Connecticut</option>
+<option value="Delaware">Delaware</option>
+<option value="District of Columbia">District of Columbia</option>
+<option value="Florida">Florida</option>
+<option value="Georgia">Georgia</option>
+<option value="Hawaii">Hawaii</option>
+<option value="Idaho">Idaho</option>
+<option value="Illinois">Illinois</option>
+<option value="Indiana">Indiana</option>
+<option value="Iowa">Iowa</option>
+<option value="Kansas">Kansas</option>
+<option value="Kentucky">Kentucky</option>
+<option value="Louisiana">Louisiana</option>
+<option value="Maine">Maine</option>
+<option value="Maryland">Maryland</option>
+<option value="Massachusetts">Massachusetts</option>
+<option value="Michigan">Michigan</option>
+<option value="Minnesota">Minnesota</option>
+<option value="Mississippi">Mississippi</option>
+<option value="Missouri">Missouri</option>
+<option value="Montana">Montana</option>
+<option value="Nebraska">Nebraska</option>
+<option value="Nevada">Nevada</option>
+<option value="New Hampshire">New Hampshire</option>
+<option value="New Jersey">New Jersey</option>
+<option value="New Mexico">New Mexico</option>
+<option value="New York">New York</option>
+<option value="North Carolina">North Carolina</option>
+<option value="North Dakota">North Dakota</option>
+<option value="Ohio">Ohio</option>
+<option value="Oklahoma">Oklahoma</option>
+<option value="Oregon">Oregon</option>
+<option value="Pennsylvania">Pennsylvania</option>
+<option value="Rhode Island">Rhode Island</option>
+<option value="South Carolina">South Carolina</option>
+<option value="South Dakota">South Dakota</option>
+<option value="Tennessee">Tennessee</option>
+<option value="Texas">Texas</option>
+<option value="Utah">Utah</option>
+<option value="Vermont">Vermont</option>
+<option value="Virginia">Virginia</option>
+<option value="WA" selected="selected">Washington</option>
+<option value="West Virginia">West Virginia</option>
+<option value="Wisconsin">Wisconsin</option>
+<option value="Wyoming">Wyoming</option>
+<option value="Armed Forces Americas">Armed Forces Americas</option>
+<option value="Armed Forces Europe">Armed Forces Europe</option>
+<option value="Armed Forces Pacific">Armed Forces Pacific</option>
+</select>
+[% END %]
--- /dev/null
+[%- PROCESS "opac/parts/header.tt2";
+ PROCESS "opac/parts/org_selector.tt2";
+ PROCESS "opac/parts/state_selector.tt2";
+ WRAPPER "opac/parts/base.tt2";
+ ctx.page_title = l("Request Library Card");
+
+# for privacy, reload the page after (default) 5 minutes
+refresh_time = ctx.register.settings.refresh_timeout || 300;
+ctx.refresh = refresh_time _ '; ' _ ctx.opac_root _ '/home';
+
+# some useful variables and MACROs for display,
+# field validation, and added info display
+ctx_org = ctx.physical_loc || ctx.search_ou || ctx.aou_tree.id;
+
+# TODO put these on the EG server?
+card_url = 'https://www.kcls.org/images/library/cards/Card_';
+wallet_cards = ['12man', 'blank', 'books', 'mirror'];
+keychain_cards = ['keychain'];
+
+MACRO input_field(fclass, fname, label, type, css_class) BLOCK;
+ field_path = fclass _ "." _ fname;
+ value = ctx.register.values.$fclass.$fname;
+ type = type || 'text';
+ css_class = css_class || '';
+%]
+ <input
+ maxlength="1000"
+ size="25"
+ class='[% css_class %]'
+ aria-label="[% label | html %]"
+ type='[% type %]'
+ id='[% field_path %]'
+ name='[% field_path %]'
+ onchange="validate('[% field_path %]')"
+ value='[% value || CGI.param(field_path) | html %]'/>
+
+ [% IF invalid_require %]
+ <span class='patron-reg-required'>
+ [% l('This field is required') %]
+ </span>
+ [% ELSIF invalid_regex %]
+ <span class='patron-reg-required'>
+ [% l('The value entered does not have the correct format') %]
+ </span>
+ [% END %]
+[%
+END; # input_field()
+
+%]
+
+<script type="text/javascript"
+ src="[% ctx.media_prefix %]/js/ui/default/opac/register.js"></script>
+
+<style>
+/* Keep the CSS here for now for simplicity.
+ If it gets too big, move to a dedicated file. */
+.patron-reg-invalid {
+ font-weight: bold;
+ background-color: red;
+}
+.patron-reg-required {
+ font-weight: bold;
+ color: red;
+}
+.card-style-option {
+ text-align:center;
+}
+.patron-reg-action {
+ padding-right: 10px;
+}
+#main-content-register {
+ margin: 6px;
+ margin-bottom: 20px;
+ color: #585d5e;
+ font-family: 'Open Sans', sans-serif;
+ letter-spacing: .5pt;
+ font-size: 15px;
+ width: 700px; /* to match bibliocms */
+}
+#main-content-register label {
+ font-weight: bold;
+}
+#main-content-register h2 {
+ font-weight: bold;
+ font-size: 18px;
+}
+#main-content-register li {
+ margin-top: 12px;
+ list-style-type: none;
+}
+.grid { width: 95%; }
+.grid-cell {
+ float: left;
+ margin-right: 10px;
+}
+.grid-clear {
+ clear:both;
+}
+#main-content-register .wide-input {
+ width: 90%;
+}
+#main-content-register .card-img {
+ width: 120px;
+ height:76px;
+}
+.mailing-address-hidden {
+ display:none;
+}
+</style>
+
+<div id="content-wrapper">
+ <div id="main-content-register">
+
+ <h1>[% l('Request a Library Card')%]</h1>
+
+ [% IF ctx.register.success %]
+ <h2>[% l('Registration successful!') %]<h3>
+ <h3>[% l('Please see library staff to complete your registration.') %]</h4>
+ <div>
+ <button onclick="location.href='https://kcls.bibliocms.com/'">
+ Return to KCLS
+ </button>
+ </div>
+ <hr/>
+ [% END %]
+
+ <!--DO WE NEED THIS?
+ <ul>
+ <li>
+ To fully activate your card you will need to visit a KCLS
+ library with proof of address and photo ID that shows your
+ date of birth. Parents/guardians can assist with proof of
+ address for full activation for applicants under 18. Find a
+ list of the documents you may use to provide proof of address
+ on our
+ <a href="https://www.kcls.org/usingthelibrary/card/applications/KCLS%20600%20ENG.pdf">
+ downloadable application.</a>
+ </li>
+ <li>
+ Want your card right away? Apply in person at any
+ <a href="https://www.kcls.org/usingthelibrary/locations/">KCLS library.</a>
+ In-person applicants can also choose from more card
+ designs, while supplies last.
+ </li>
+ </ul>
+ -->
+
+ <form method='POST' onsubmit="return onsub()">
+ <ul>
+ <li>
+ <label>Choose a card size....</label>
+ <span class="patron-reg-required">*</span>
+ <div>
+ <ul>
+ <li>
+ <input type="radio" name='card-type' id="card-type-wallet"
+ onclick="show_card_types('wallet')">
+ <label for="">Wallet</label>
+ </li>
+ <li>
+ <input type="radio" id="card-type-keychain" name='card-type'
+ onclick="show_card_types('keychain')">
+ <label for="card-type-keychain">Keychain</label>
+ </li>
+ </ul>
+ </div>
+ </li>
+ <li id='wallet-cards' style='display:none'>
+ <label>Wallet Options</label>
+ <div class="grid">
+ [% FOR ctype IN wallet_cards %]
+ <div class="grid-cell">
+ <div><img class="card-img" src="[% card_url _ ctype _ '.jpg' %]"/></div>
+ <div class="card-style-option">
+ <input [% IF loop.first %]id='first-wallet-card'[% END %]
+ type="radio" name="stgu.card_style" value="[% ctype %]"/>
+ </div>
+ </div>
+ [% END %]
+ </div>
+ <div class="grid-clear"></div>
+ </li>
+ <li id='keychain-cards' style='display:none'>
+ <label>Keychain Options</label>
+ <div class="grid">
+ [% FOR ctype IN keychain_cards %]
+ <div class="grid-cell">
+ <div><img class="card-img" src="[% card_url _ ctype _ '.jpg' %]"/></div>
+ <div class="card-style-option">
+ <input [% IF loop.first %]id='first-keychain-card'[% END %]
+ type="radio" name="stgu.card_style" value="[% ctype %]"/>
+ </div>
+ </div>
+ [% END %]
+ </div>
+ <div class="grid-clear"></div>
+ </li>
+
+ <li><h2>Your Information</h2></li>
+ <hr/>
+
+ <li>
+ <div class="grid">
+ <div class="grid-cell">
+ <div>
+ <label for="sgtu.first_given_name">First Name</label>
+ <span class="patron-reg-required">*</span>
+ </div>
+ <div>[% input_field('stgu', 'first_given_name', 'First Name') %]</div>
+ </div>
+ <div class="grid-cell">
+ <div><label for="sgtu.second_given_name">Middle Name</label></div>
+ <div>[% input_field('stgu', 'second_given_name', 'Middle Name') %]</div>
+ </div>
+ <div class="grid-cell">
+ <div>
+ <label for="sgtu.family_name">Last Name</label>
+ <span class="patron-reg-required">*</span>
+ </div>
+ <div>[% input_field('stgu', 'family_name', 'Last Name') %]</div>
+ </div>
+ </div>
+ <div class="grid-clear"></div>
+ </li>
+
+ <li>
+ <label for="stgu.day_phone">Phone Number</label>
+ <div class="grid">
+ <div class="grid-cell">
+ <div>[% input_field('stgu', 'day_phone', 'Phone Number') %]</div>
+ </div>
+ <div class="grid-cell">(xxx-xxx-xxxx)</div>
+ </div>
+ <div class="grid-clear"></div>
+ </li>
+
+ <li>
+ <label for="stgu.dob">
+ Birth Date<span class="patron-reg-required">*</span>
+ </label>
+ <input type="hidden" name="stgu.dob" id="stgu.dob"/>
+ <div class="grid">
+ <div class="grid-cell">
+ <div><input onchange="compile_dob()" type="text"
+ maxlength="2" size="2" id="dob.month"></div>
+ <div><label for="dob.month">MM</label></div>
+ </div>
+ <div class="grid-cell">
+ <div><input onchange="compile_dob()" type="text"
+ maxlength="2" size="2" id="dob.day"></div>
+ <div><label for="dob.day">DD</label></div>
+ </div>
+ <div class="grid-cell">
+ <div><input onchange="compile_dob()" type="text"
+ maxlength="4" size="4" id="dob.year"></div>
+ <div><label for="dob.year">YYYY</label></div>
+ </div>
+ <div class="grid-cell">
+ <div><span id='dob.display'></span></div>
+ </div>
+ </div>
+ <div class="grid-clear"></div>
+ </li>
+
+ <li>
+ <label for="stgu.email">
+ Your email address for faster library notices
+ </label>
+ <div>[% input_field('stgu', 'email', 'Email', 'email') %]</div>
+ </li>
+
+ <li>
+ <label>Optional: What is your gender identity?</label>
+ <div>[% input_field('stgsc', '1', 'Gender') %]</div>
+ </li>
+
+ <li>
+ <label class="gfield_label" for="">
+ If you are under age 18, list all parents<br/>and guardians living at your address:
+ </label>
+ <div>[% input_field('stgu', 'ident_value2', 'Parent / Guardian', 'text', 'wide-input') %]</div>
+ </li>
+
+ <li>
+ <label for="stgu.home_ou">
+ What do you want your home library to be?
+ </label>
+ <div>
+ [% INCLUDE build_org_selector
+ name='stgu.home_ou'
+ id='stgu.home_ou'
+ value=value || ''
+ can_have_users_only=1
+ no_indent=1
+ no_root=1
+ valid_org_list=ctx.register.valid_orgs
+ %]
+ <span class="patron-reg-required">*</span>
+ [% IF ctx.register.invalid.bad_home_ou %]
+ <span class='patron-reg-required'>
+ [% l('Please select a valid library') %]
+ </span>
+ [% END %]
+ </div>
+ </li>
+
+ <li><h2>Contact Preferences</h2></li>
+ <hr/>
+
+ <li>
+ <label>May we contact you?</label>
+ <div>
+ <ul>
+ <li>
+ [% input_field('stgsc', '3', 'Events Mailing', 'checkbox') %]
+ <label for="stgsc.3">Tell me about KCLS news and events</label>
+ </li>
+ <li>
+ [% input_field('stgsc', '4', 'Foundation Mailing', 'checkbox') %]
+ <label for="stgsc.4">
+ Send me information about The King County Library System Foundation
+ </label>
+ </li>
+ </ul>
+ </div>
+ </li>
+
+ <li>
+ <h3>
+ Residential Address<span class="patron-reg-required">*</span>
+ </h3>
+ </li>
+
+ <li>
+ <div>[% input_field(
+ 'stgba', 'street1', 'Street Address', 'text', 'wide-input') %]</div>
+ <label for="stgba.street1">
+ Street Address
+ <span class="patron-reg-required">*</span>
+ </label>
+ </li>
+ <li>
+ <div class="grid">
+ <div class="grid-cell" style="width:40%">
+ <div>[% input_field(
+ 'stgba', 'street2', 'Address Line 2', 'text', 'wide-input') %]</div>
+ <div><label for="stgba.street2">Address Line 2</label></div>
+ </div>
+ <div class="grid-cell" style="width:40%">
+ <div>[% input_field('stgba', 'city', 'City') %]</div>
+ <div>
+ <label for="stgba.city">
+ City<span class="patron-reg-required">*</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="grid-clear"></div>
+ </li>
+ <li>
+ <div class="grid">
+ <div class="grid-cell" style="width:40%">
+ <div>[% PROCESS state_selector name='stgba.state' id='stgba.state' %]</div>
+ <div>
+ <label for="stgba.state">
+ State<span class="patron-reg-required">*</span>
+ </label>
+ </div>
+ </div>
+ <div class="grid-cell" style="width:40%">
+ <div>[% input_field('stgba', 'post_code', 'Zip / Post Code') %]</div>
+ <div>
+ <label for="stgba.post_code">
+ Zip / Post Code<span class="patron-reg-required">*</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="grid-clear"></div>
+ <input type='hidden' name='stgba.country' value='USA'/>
+ </li>
+
+ <li>
+ <label>Mailing Address</label>
+ <div>
+ <input type="checkbox" onclick="show_hide_mailing(this.checked)"
+ name="mailing_matches_billing"
+ id="mail_addr_matches_billing" checked="checked">
+ <label for="mail_addr_matches_billing">Same as Residential Address</label>
+ </div>
+ </li>
+
+ <li id='mailing-address-1' style='display:none'>
+ <div>[% input_field(
+ 'stgma', 'street1', 'Street Address', 'text', 'wide-input') %]</div>
+ <label for="stgma.street1">
+ Street Address
+ <span class="patron-reg-required">*</span>
+ </label>
+ </li>
+ <li id='mailing-address-2' style='display:none'>
+ <div class="grid">
+ <div class="grid-cell" style="width:40%">
+ <div>[% input_field(
+ 'stgma', 'street2', 'Address Line 2', 'text', 'wide-input') %]</div>
+ <div><label for="stgma.street2">Address Line 2</label></div>
+ </div>
+ <div class="grid-cell" style="width:40%">
+ <div>[% input_field('stgma', 'city', 'City') %]</div>
+ <div>
+ <label for="stgma.city">
+ City<span class="patron-reg-required">*</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="grid-clear"></div>
+ </li>
+ <li id='mailing-address-3' style='display:none'>
+ <div class="grid">
+ <div class="grid-cell" style="width:40%">
+ <div>[% PROCESS state_selector name='stgma.state' id='stgma.state' %]</div>
+ <div>
+ <label for="stgma.state">
+ State<span class="patron-reg-required">*</span>
+ </label>
+ </div>
+ </div>
+ <div class="grid-cell" style="width:40%">
+ <div>[% input_field('stgma', 'post_code', 'Zip / Post Code') %]</div>
+ <div>
+ <label for="stgma.post_code">
+ Zip / Post Code<span class="patron-reg-required">*</span>
+ </label>
+ </div>
+ </div>
+ </div>
+ <div class="grid-clear"></div>
+ <input type='hidden' name='stgma.country' value='USA'/>
+ </li>
+
+ <li>
+ <div class="grid">
+ <div class="grid-cell">
+ <input type="submit" value="[% l('Submit Registration') %]"/>
+ </div>
+ <div class="grid-cell">
+ <button onclick="location.href='https://kcls.bibliocms.com/'; return false">
+ Cancel and Return to KCLS
+ </button>
+ </div>
+ </div>
+ <div class="grid-clear"></div>
+ </li>
+ </ul>
+ </form>
+ </div>
+</div>
+
+[% END %]
+
--- /dev/null
+/*
+ KCLS custom patron self-registration functions
+*/
+
+var invalid_fields = {};
+var is_juvenile = false;
+var required_fields = [
+ 'stgu.card_style',
+ 'stgu.first_given_name',
+ 'stgu.family_name',
+ 'stgu.dob',
+ 'stgba.street1',
+ 'stgba.city',
+ 'stgba.state',
+ 'stgba.post_code',
+];
+
+var copy_addr_fields = ['street1','street2','city','state','post_code'];
+
+/* show/hide card options depending on the selected type. */
+function show_card_types(type) {
+ var wal = document.getElementById('wallet-cards');
+ var key = document.getElementById('keychain-cards');
+ if (type == 'wallet') {
+ wal.style.display = 'block';
+ key.style.display = 'none';
+ } else {
+ wal.style.display = 'none';
+ key.style.display = 'block';
+ }
+
+ // Select the first card in each group.
+ // Cards are put into groups, but use the same form name.
+ document.getElementById('first-'+type+'-card').checked = 'checked';
+}
+
+function check_juvenile(dobString) {
+ var dobDate = Date.parse(dobString);
+ var ageDate = new Date(); // minimum age for non-juvenile
+ ageDate.setFullYear(ageDate.getFullYear() - 18);
+ is_juvenile = (dobDate > ageDate);
+}
+
+/*
+Show or hide the mailing address.
+*/
+function show_hide_mailing(hide) {
+ var display = hide ? 'none' : 'block';
+ document.getElementById('mailing-address-1').style.display = display;
+ document.getElementById('mailing-address-2').style.display = display;
+ document.getElementById('mailing-address-3').style.display = display;
+}
+
+function validate(dom_id) {
+ var element = document.getElementById(dom_id);
+ var value = element ? element.value : '';
+ var valid = true;
+
+ switch(dom_id) {
+ case 'stgu.first_given_name':
+ if (value) {
+ delete invalid_fields[dom_id];
+ } else {
+ invalid_fields[dom_id] = 'Please include first name';
+ valid = false;
+ }
+
+ break;
+
+ case 'stgu.family_name':
+ if (value) {
+ delete invalid_fields[dom_id];
+ } else {
+ invalid_fields[dom_id] = 'Please include last name';
+ valid = false;
+ }
+
+ break;
+
+ case 'stgu.dob':
+ // dob value is generated by compile_dob().
+ if (value) {
+ delete invalid_fields[dom_id];
+ check_juvenile(value);
+ } else {
+ valid = false;
+ is_juvenile = false;
+ invalid_fields[dom_id] =
+ "Please enter a valid date of birth.";
+ }
+ validate('stgu.ident_value2');
+ break;
+
+ case 'stgu.ident_value2': // parent/guardian
+ // A value is only required if is_juvenile is true.
+ valid = Boolean(value) || !is_juvenile;
+ if (valid) {
+ delete invalid_fields[dom_id];
+ } else {
+ invalid_fields[dom_id] =
+ "Please list all parents or guardians living at your address."
+ }
+
+ break;
+
+ case 'stgu.card_style':
+ // be sure the user has selected a card style.
+ // In this case dom_id is really a radio selector name.
+ var styles = document.getElementsByName(dom_id);
+ var checked = false;
+ for (var i = 0; i < styles.length; i++) {
+ if (styles[i].checked) {
+ checked = true;
+ break;
+ }
+ }
+
+ if (checked) {
+ valid = false;
+ delete invalid_fields[dom_id];
+ } else {
+ invalid_fields[dom_id] = "Please select a card style."
+ }
+ break;
+
+ case 'stgba.street1':
+ if (value) {
+ delete invalid_fields[dom_id];
+ } else {
+ invalid_fields[dom_id] = "Please enter an address street";
+ }
+ break;
+
+ case 'stgba.city':
+ if (value) {
+ delete invalid_fields[dom_id];
+ } else {
+ invalid_fields[dom_id] = "Please enter a address city";
+ }
+ break;
+
+ case 'stgba.post_code':
+ if (value) {
+ delete invalid_fields[dom_id];
+ } else {
+ invalid_fields[dom_id] = "Please enter an address zip/post code";
+ }
+ break;
+ }
+
+ if (element) {
+ element.className = valid ? '' : 'patron-reg-invalid';
+ }
+}
+
+function compile_dob() {
+ var day = document.getElementById('dob.day').value || '';
+ var mon = document.getElementById('dob.month').value || '';
+ var year = document.getElementById('dob.year').value || '';
+ var dob = document.getElementById('stgu.dob');
+ var dob_display = document.getElementById('dob.display');
+
+ if (day && mon && year.length == 4 && Number(year) >= 1900) {
+ var dob_date = new Date(year, Number(mon) - 1, Number(day));
+
+ if (dob_date) {
+
+ // push the time forward by our timezone offset to force the
+ // stored (UTC) date to match the entered date.
+ dob_date.setTime(dob_date.getTime() +
+ dob_date.getTimezoneOffset() * 60 * 1000);
+
+ dob.value = dob_date.toISOString().replace(/T.*/,'');
+ dob_display.innerHTML = '(' + dob_date.toDateString() + ')';
+ validate('stgu.dob');
+ return;
+ }
+ }
+
+ // date is incomplete or invalid. clear the compiled dob value.
+ dob.value = '';
+ dob_display.innerHTML = '';
+ validate('stgu.dob');
+}
+
+/*
+If we have collected any invalid field messages, bundle
+them into a single alert message, alert it, then prevent
+the form from submitting by returning false.
+*/
+function onsub() {
+
+ // force the validator to run on all required fields regardless
+ // of whether they have been changed.
+ for (var i = 0; i < required_fields.length; i++)
+ validate(required_fields[i]);
+
+ var msg = '';
+ for (var key in invalid_fields) {
+ msg += '\n*' + invalid_fields[key] + '\n';
+ }
+
+ if (msg) {
+ alert(msg);
+ return false;
+ }
+ return true;
+}
+
+