/** * Takes the instant law object and turns it into HTML, with embedded links, anchors, etc. */ function render() { /* * Get the dictionary terms for this chapter. */ $dictionary = new Dictionary(); $dictionary->structure_id = $this->structure_id; $dictionary->section_id = $this->section_id; $tmp = $dictionary->term_list(); if ($tmp !== FALSE) { $terms = (array) $tmp; unset($tmp); } /* * If we've gotten a list of dictionary terms. */ if ($terms !== FALSE && is_array($terms)) { /* * Arrange our terms from longest to shortest. This is to ensure that the most specific * terms are defined (e.g. "person of interest") rather than the broadest terms (e.g. * "person"). */ usort($terms, 'sort_by_length'); /* * Store a list of the dictionary terms as an array, which is required for * preg_replace_callback, the function that we use to insert the definitions. */ $term_pcres = array(); foreach ($terms as $term) { /* * Step through each character in this word. */ for ($i = 0; $i < strlen($term); $i++) { /* * If there are any uppercase characters, then make this PCRE string case * sensitive. */ if (ord($term[$i]) >= 65 && ord($term[$i]) <= 90) { $term_pcres[] = '/\\b' . $term . '(s?)\\b(?![^<]*>)/'; $caps = TRUE; break; } } /* * If we have determined that this term does not contain capitalized letters, then * create a case-insensitive PCRE string. */ if (!isset($caps)) { $term_pcres[] = '/\\b' . $term . '(s?)\\b(?![^<]*>)/i'; } /* * Unset our flag -- we don't want to have it set the next time through. */ if (isset($caps)) { unset($caps); } } } /* * Instantiate our autolinker, which embeds links. If we've defined a state-custom * autolinker, use that one. Otherwise, use the built-in one. Be sure not to attempt to * autoload a file fitting our class-name schema, since this class, if it exists, would be * found within class.[State].inc.php. */ if (class_exists('State_Autolinker', FALSE) === TRUE) { $autolinker = new State_Autolinker(); } $autolinker = new Autolinker(); /* * Iterate through every section to make some basic transformations. */ foreach ($this->text as $section) { /* * Prevent lines from wrapping in the middle of a section identifier. */ $section->text = str_replace('§ ', '§ ', $section->text); /* * Turn every code reference in every paragraph into a link. */ $section->text = preg_replace_callback(SECTION_REGEX, array($autolinker, 'replace_sections'), $section->text); /* * Turn every pair of newlines into carriage returns. */ $section->text = preg_replace('/\\R\\R/', '<br /><br />', $section->text); /* * Use our dictionary to embed dictionary terms in the form of span titles. */ if (isset($term_pcres)) { $section->text = preg_replace_callback($term_pcres, array($autolinker, 'replace_terms'), $section->text); } } $html = ''; /* * Iterate through each section of text to display it. */ $i = 0; $num_paragraphs = count((array) $this->text); foreach ($this->text as $paragraph) { /* * Identify the prior and next sections, by storing their prefixes. */ if ($i > 0) { $paragraph->prior_prefix = $this->text->{$i - 1}->entire_prefix; } if ($i + 1 < $num_paragraphs) { $paragraph->next_prefix = $this->text->{$i + 1}->entire_prefix; } /* * If this paragraph's prefix hierarchy is different than that of the prior prefix, then * indicate that this is a new section. */ if (!isset($paragraph->prior_prefix) || $paragraph->entire_prefix != $paragraph->prior_prefix) { $html .= ' <section'; if (!empty($paragraph->prefix_anchor)) { $html .= ' id="' . $paragraph->prefix_anchor . '"'; } /* * If this is a subsection, indent it. */ if ($paragraph->level > 1) { $html .= ' class="indent-' . ($paragraph->level - 1) . '"'; } $html .= '>'; } /* * Start a paragraph of the appropriate type. */ if ($paragraph->type == 'section') { $html .= '<p>'; } elseif ($paragraph->type == 'table') { $html .= '<div class="tabular"><pre class="table">'; } /* * If we've got a section prefix, and it's not the same as the last one, then display * it. */ if (!empty($paragraph->prefix) && (!isset($paragraph->prior_prefix) || $paragraph->entire_prefix != $paragraph->prior_prefix)) { $html .= $paragraph->prefix; /* * We could use a regular expression to determine if we need to append a period, but * that would be slower. */ if (substr($paragraph->prefix, -1) != ')' && substr($paragraph->prefix, -1) != '.') { $html .= '.'; } $html .= ' '; } /* * Display this section of text. Purely structural sections lack text of their own (only * their child structures contain text), which is why this is conditional. */ if (!empty($paragraph->text)) { $html .= $paragraph->text; } /* * If we've got a section prefix, append a paragraph link to the end of this section. */ if (!empty($paragraph->prefix) && !defined('EXPORT_IN_PROGRESS')) { /* * Assemble the permalink */ $permalink = $_SERVER['REQUEST_URI'] . '#' . $paragraph->prefix_anchor; $html .= ' <a id="paragraph-' . $paragraph->id . '" class="section-permalink" ' . 'href="' . $permalink . '"><i class="icon-link"></i></a>'; } if ($paragraph->type == 'section') { $html .= '</p>'; } elseif ($paragraph->type == 'table') { $html .= '</pre></div>'; } /* * If our next prefix is different than the current prefix, than terminate this section. */ if (!isset($paragraph->next_prefix) || $paragraph->entire_prefix != $paragraph->next_prefix || $i + 1 === $num_paragraphs) { $html .= '</section>'; } $i++; } return $html; }
function handle($args) { /* * If we have received neither a term nor a section, we can't do anything. */ if (empty($args['term']) && empty($_GET['section'])) { json_error('Neither a dictionary term nor a section number have been provided.'); die; } /* * Clean up the term. */ $term = filter_var($args['term'], FILTER_SANITIZE_STRING); /* * If a section has been specified, then clean that up. */ if (isset($_GET['section'])) { $section = filter_input(INPUT_GET, 'section', FILTER_SANITIZE_STRING); } $dict = new Dictionary(); /* * Get the definitions for the requested term, if a term has been requested. */ if (!empty($args['term'])) { if (isset($section)) { $dict->section_number = $section; } $dict->term = $term; $dictionary = $dict->define_term(); /* * If, for whatever reason, this term is not found, return an error. */ if ($dictionary === FALSE) { $response = array('definition' => 'Definition not available.'); } else { /* * Uppercase the first letter of the first (quoted) word. We perform this twice because * some egal codes begin the definition with a quotation mark and some do not. (That is, * some write '"Whale" is a large sea-going mammal' and some write 'Whale is a large * sea-going mammal.") */ if (preg_match('/[A-Za-z]/', $dictionary->definition[0]) === 1) { $dictionary->definition[0] = strtoupper($dictionary->definition[0]); } elseif (preg_match('/[A-Za-z]/', $dictionary->definition[1]) === 1) { $dictionary->definition[1] = strtoupper($dictionary->definition[1]); } /* * If the request contains a specific list of fields to be returned. */ if (isset($_GET['fields'])) { /* * Turn that list into an array. */ $returned_fields = explode(',', urldecode($_GET['fields'])); foreach ($returned_fields as &$field) { $field = trim($field); } /* * It's essential to unset $field at the conclusion of the prior loop. */ unset($field); foreach ($dictionary as &$term) { /* * Step through our response fields and eliminate those that aren't in the * requested list. */ foreach ($term as $field => &$value) { if (in_array($field, $returned_fields) === FALSE) { unset($term->{$field}); } } } } /* * If a section has been specified, then simplify this response by returning just a * single definition. */ if (isset($section)) { $dictionary = $dictionary->{0}; } /* * Rename this variable to use the expected name. */ $response = $dictionary; } // end else if term is found } elseif (!empty($_GET['section'])) { /* * Get the structural ID of the container for this section. */ $law = new Law(); $law->section_number = $section; $law->config = FALSE; $result = $law->get_law(); if ($result == FALSE) { $response = array('terms' => 'Term list not available.'); } else { /* * Now get the term list. */ $dict->section_id = $law->section_id; $dict->structure_id = $law->structure_id; $response = $dict->term_list(); if ($response == FALSE) { $response = array('terms' => 'Term list not available.'); } } } // end elseif (!empty($args['section'])) $this->render($response, 'OK', $_REQUEST['callback']); }