Index: trunk/extensions/WikiCitation/WikiCitationTests.txt |
— | — | @@ -0,0 +1,50 @@ |
| 2 | +!! test |
| 3 | +A single author author with no other data. |
| 4 | +!! input |
| 5 | +{{#cite:Chicago|long|note |
| 6 | + | first=Gérard |
| 7 | + | dropping-particle=de |
| 8 | + | non-dropping-particle=la |
| 9 | + | last=Martinière |
| 10 | + | suffix=III |
| 11 | +}} |
| 12 | +!! result |
| 13 | +<p><span class="citation">Wales, Jimmy.</span> |
| 14 | +</p> |
| 15 | +!! end |
| 16 | + |
| 17 | +!! test |
| 18 | +Just an author by surname and given |
| 19 | +!! input |
| 20 | +{{#citation:|given=Jimmy|surname=Wales}} |
| 21 | +!! result |
| 22 | +<p><span class="citation">Wales, Jimmy.</span> |
| 23 | +</p> |
| 24 | +!! end |
| 25 | + |
| 26 | +!! test |
| 27 | +Two authors by surname and given |
| 28 | +!! input |
| 29 | +{{#citation:|given 1=Jimmy|surname 1=Wales|given 2=Jimmy|surname 2=Wales}} |
| 30 | +!! result |
| 31 | +<p><span class="citation">Wales, Jimmy & Wales, Jimmy.</span> |
| 32 | +</p> |
| 33 | +!! end |
| 34 | + |
| 35 | +!! test |
| 36 | +Three authors by surname and given |
| 37 | +!! input |
| 38 | +{{#citation:|given=Jimmy|surname=Wales|given 2=Jimmy|surname 2=Wales|given 3=Jimmy|surname 3=Wales}} |
| 39 | +!! result |
| 40 | +<p><span class="citation">Wales, Jimmy; Wales, Jimmy & Wales, Jimmy.</span> |
| 41 | +</p> |
| 42 | +!! end |
| 43 | + |
| 44 | +!! test |
| 45 | +An author with a link |
| 46 | +!! input |
| 47 | +{{#citation:|author=Wales, Jimmy |url=http://example.com/ |title=Example}} |
| 48 | +!! result |
| 49 | +<p><span class="citation">Wales, Jimmy. <a href="http://example.com/" class="external text" rel="nofollow">Example</a> |
| 50 | +</p> |
| 51 | +!! end |
\ No newline at end of file |
Property changes on: trunk/extensions/WikiCitation/WikiCitationTests.txt |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 52 | + native |
Index: trunk/extensions/WikiCitation/WikiCitation.body.php |
— | — | @@ -0,0 +1,287 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Entry point file for the WikiCitation extension. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Entry-point class for the WikiCitation extension. |
| 13 | + * |
| 14 | + * This is a static factory class, containing necessary entry points for |
| 15 | + * parser hooks. The class creates a parser (WCArgumentReader) to parse |
| 16 | + * the parser function. This class then calls the parser to create an |
| 17 | + * appropriate citation styler (children of WCStyle). This class also |
| 18 | + * creates an object (WCArticle) representing all the citations on a |
| 19 | + * single page. |
| 20 | + */ |
| 21 | +class WikiCitation { |
| 22 | + |
| 23 | + /** |
| 24 | + * @var string citeID String containing a magic word representing the |
| 25 | + * parser function name. In English, it will be "cite", as in |
| 26 | + * {{#cite:...|...}. |
| 27 | + */ |
| 28 | + const citeID = 'wc_cite_tag'; |
| 29 | + |
| 30 | + /** |
| 31 | + * @var string biblioID String containing a magic word representing the |
| 32 | + * tag extension name. In English, it will be "biblio", as in |
| 33 | + * <biblio>...</biblio>. |
| 34 | + */ |
| 35 | + const biblioID = 'wc_biblio_tag'; |
| 36 | + |
| 37 | + /** |
| 38 | + * @var string noteID String containing a magic word representing the |
| 39 | + * tag extension name for notes. In English, it will be "note", as in |
| 40 | + * <note>...</note>. |
| 41 | + */ |
| 42 | + const noteID = 'wc_note_tag'; |
| 43 | + |
| 44 | + /** |
| 45 | + * @var string notesID String containing a magic word representing the |
| 46 | + * tag extension name for endnotes. In English, it will be "notes", |
| 47 | + * as in <notes>...</notes>. |
| 48 | + */ |
| 49 | + const endnotesID = 'wc_notes_tag'; |
| 50 | + |
| 51 | + /** |
| 52 | + * @var string notesID String containing a magic word representing the |
| 53 | + * tag extension name for a note section. In English, it will be |
| 54 | + * "notesection", as in <notesection>...</notesection>. |
| 55 | + */ |
| 56 | + const noteSectionID = 'wc_note_section_tag'; |
| 57 | + |
| 58 | + /** |
| 59 | + * An object representing a single article containing citations and/or |
| 60 | + * a bibliography. |
| 61 | + * |
| 62 | + * @static |
| 63 | + * @var WCArticle $article |
| 64 | + */ |
| 65 | + protected static $article; |
| 66 | + |
| 67 | + |
| 68 | + /** |
| 69 | + * Handler for 'ParserFirstCallInit' parser hook. |
| 70 | + * |
| 71 | + * Called by Parser object to initialize the WikiCitation extension. |
| 72 | + * Sets up parser hook, so that WikiCitation::parse(...) will be called |
| 73 | + * whenever the parser encounters "{{#cite:...}}" or an equivalent |
| 74 | + * localized expression, or the "<biblio>" tag. |
| 75 | + * |
| 76 | + * @static |
| 77 | + * @param Parser $parser the Parser object calling this hook |
| 78 | + */ |
| 79 | + public static function onParserFirstCallInit( Parser $parser ) { |
| 80 | + |
| 81 | + # Construct WCArticle object $article. The old $article, if it exists, |
| 82 | + # will be recovered by garbage collector. |
| 83 | + self::$article = new WCArticle(); |
| 84 | + |
| 85 | + # Create parser function hook to $article->parseFunctionTemplate(...). |
| 86 | + $parser->setFunctionHook( |
| 87 | + self::citeID, # citeID is the magic word representing the parser function. |
| 88 | + 'WikiCitation::parseFunctionTemplate', # the function Parser will call |
| 89 | + SFH_OBJECT_ARGS # The function call will be via PPNode_DOM arguments, rather than text, |
| 90 | + # except for the first argument after the colon. |
| 91 | + ); |
| 92 | + |
| 93 | + # Set hooks for biblio tag and its synonyms, if any. |
| 94 | + foreach( MagicWord::get( self::biblioID )->getSynonyms() as $synonym ) { |
| 95 | + $parser->setHook( |
| 96 | + $synonym, |
| 97 | + 'WikiCitation::parseBibliographyTag' |
| 98 | + ); |
| 99 | + } |
| 100 | + |
| 101 | + # Set hooks for note tag and its synonyms, if any. |
| 102 | + foreach( MagicWord::get( self::noteID )->getSynonyms() as $synonym ) { |
| 103 | + $parser->setHook( |
| 104 | + $synonym, |
| 105 | + 'WikiCitation::parseNoteTag' |
| 106 | + ); |
| 107 | + } |
| 108 | + |
| 109 | + # Set hooks for note section tag and its synonyms, if any. |
| 110 | + foreach( MagicWord::get( self::noteSectionID )->getSynonyms() as $synonym ) { |
| 111 | + $parser->setHook( |
| 112 | + $synonym, |
| 113 | + 'WikiCitation::parseSectionTag' |
| 114 | + ); |
| 115 | + } |
| 116 | + |
| 117 | + # Set hooks for endnote tag and its synonyms, if any. |
| 118 | + foreach( MagicWord::get( self::endnotesID )->getSynonyms() as $synonym ) { |
| 119 | + $parser->setHook( |
| 120 | + $synonym, |
| 121 | + 'WikiCitation::parseNotesTag' |
| 122 | + ); |
| 123 | + } |
| 124 | + |
| 125 | + # Associate style sheet with page. |
| 126 | + global $wgOut, $wgWCStyleSheet; |
| 127 | + $wgOut->addExtensionStyle( $wgWCStyleSheet ); |
| 128 | + #$wgOut->addScript( '<link rel="stylesheet" type="text/css" media="any" href="' . $wgWCStyleSheet . '" />' ); |
| 129 | + |
| 130 | + return True; |
| 131 | + } |
| 132 | + |
| 133 | + |
| 134 | + /** |
| 135 | + * Parses the WikiCitation parser function and leaves marker in wikitext. |
| 136 | + * |
| 137 | + * This function is called by the Parser when it encounters the parser |
| 138 | + * function "{{#cite:...}}" or an equivalent localized expression) |
| 139 | + * Creates WCArgumentReader object to parse flags and parameters, |
| 140 | + * then creates an appropriate child of class WCStyle based on the |
| 141 | + * first parameter after the colon, then returns the citation as text. |
| 142 | + * @remark Note that this $parser is guaranteed to be the same parser that |
| 143 | + * initialized the object. |
| 144 | + * |
| 145 | + * @param Parser $parser = the parser |
| 146 | + * @param PPFrame_DOM $frame = the DOM frame |
| 147 | + * @param array $args = arguments |
| 148 | + * @return array text |
| 149 | + */ |
| 150 | + public static function parseFunctionTemplate( Parser $parser, PPFrame_DOM $frame, array $args ) { |
| 151 | + if ( count( $args ) == 0 ) { |
| 152 | + return ''; |
| 153 | + } |
| 154 | + try { |
| 155 | + $argumentReader = new WCArgumentReader( $parser, $frame, $args ); |
| 156 | + $text = self::$article->parseCitation( $argumentReader ); |
| 157 | + } catch ( WCException $e ) { |
| 158 | + # Exception messages appear in place of the citation. |
| 159 | + $text = '<strong class="' . WCStyle::citationHTML . ' ' . WCStyle::errorHTML . '">' . $e->getMessage() . '</strong>'; |
| 160 | + } |
| 161 | + return $text; |
| 162 | + } |
| 163 | + |
| 164 | + |
| 165 | + /** |
| 166 | + * Parses the <biblio> tag extension and leaves a marker in the wikitext. |
| 167 | + * |
| 168 | + * This function is called by the Parser when it encounters the parser |
| 169 | + * function "<biblio>...</biblio>" or an equivalent localized expression). |
| 170 | + * |
| 171 | + * @param type $input = the text within the tags |
| 172 | + * @param array $args = the HTML attributes |
| 173 | + * @param Parser $parser = the parser object |
| 174 | + * @param PPFrame $frame = the frame |
| 175 | + * @return string |
| 176 | + */ |
| 177 | + public static function parseBibliographyTag( $input, array $args, Parser $parser, PPFrame $frame ) { |
| 178 | + self::$article->startBibliography( $args ); |
| 179 | + # Parse the text inside the <biblio> tags, which will contain embedded citations parser functions. |
| 180 | + $parser->recursiveTagParse( $input, $frame ); |
| 181 | + return self::$article->endBibliography(); |
| 182 | + } |
| 183 | + |
| 184 | + |
| 185 | + /** |
| 186 | + * Parses the <note> tag extension and leaves a marker in the wikitext. |
| 187 | + * |
| 188 | + * This function is called by the Parser when it encounters the parser |
| 189 | + * function "<note>...</note>" or an equivalent localized expression). |
| 190 | + * |
| 191 | + * @param type $input = the text within the tags |
| 192 | + * @param array $args = the HTML attributes |
| 193 | + * @param Parser $parser = the parser object |
| 194 | + * @param PPFrame $frame = the frame |
| 195 | + * @return string |
| 196 | + */ |
| 197 | + public static function parseNoteTag( $input, array $args, Parser $parser, PPFrame $frame ) { |
| 198 | + self::$article->startNote( $args ); |
| 199 | + # Parse the text inside the <note> tags, which will contain embedded citations. |
| 200 | + $output = $parser->recursiveTagParse( $input, $frame ); |
| 201 | + # Leaves behind a single marker for the (probably subscripted) endnote marker. |
| 202 | + return self::$article->finishNote( $output ); |
| 203 | + } |
| 204 | + |
| 205 | + |
| 206 | + /** |
| 207 | + * Parses the <notesection> tag extension and returns an endnote section. |
| 208 | + * |
| 209 | + * This function is called by the Parser when it encounters the parser |
| 210 | + * function "<notesection>...</notesection>" or an equivalent localized expression). |
| 211 | + * |
| 212 | + * @param type $input = the text within the tags |
| 213 | + * @param array $args = the HTML attributes |
| 214 | + * @param Parser $parser = the parser object |
| 215 | + * @param PPFrame $frame = the frame |
| 216 | + * @return string |
| 217 | + */ |
| 218 | + public static function parseSectionTag( $input, array $args, Parser $parser, PPFrame $frame ) { |
| 219 | + if ( $input ) { |
| 220 | + # If text is presented inside the <notes> tags, the text will appear first, followed |
| 221 | + # by the associated endnotes. |
| 222 | + self::$article->startSection( $args ); |
| 223 | + # Parse the text inside the <notes> tags, which may contain embedded |
| 224 | + # parser functions. |
| 225 | + $output = $parser->recursiveTagParse( $input, $frame ); |
| 226 | + # End the note section. |
| 227 | + self::$article->endSection(); |
| 228 | + return output; |
| 229 | + } else { |
| 230 | + return ''; |
| 231 | + } |
| 232 | + } |
| 233 | + |
| 234 | + |
| 235 | + /** |
| 236 | + * Parses the <notes> tag extension and returns the endnote section. |
| 237 | + * |
| 238 | + * This function is called by the Parser when it encounters the parser |
| 239 | + * function "<notes/>" or an equivalent localized expression). |
| 240 | + * |
| 241 | + * @param type $input = the text within the tags |
| 242 | + * @param array $args = the HTML attributes |
| 243 | + * @param Parser $parser = the parser object |
| 244 | + * @param PPFrame $frame = the frame |
| 245 | + * @return string |
| 246 | + */ |
| 247 | + public static function parseNotesTag( $input, array $args, Parser $parser, PPFrame $frame ) { |
| 248 | + # Leaves a marker for all prior notes to this point within the notes section. |
| 249 | + return self::$article->markEndnotes(); |
| 250 | + } |
| 251 | + |
| 252 | + |
| 253 | + /** |
| 254 | + * Handler for 'ParseClearState' hook. |
| 255 | + * |
| 256 | + * Called by parser to clear the parser state. This function clears the |
| 257 | + * WCArticle object. |
| 258 | + * |
| 259 | + * @static |
| 260 | + * @param Parser $parser = the parser |
| 261 | + */ |
| 262 | + public static function onParserClearState( Parser $parser ) { |
| 263 | + self::$article->clear(); |
| 264 | + return True; |
| 265 | + } |
| 266 | + |
| 267 | + |
| 268 | + /** |
| 269 | + * Handler for 'ParserBeforeTidy' parser hook. |
| 270 | + * |
| 271 | + * Called by Parser object near the end of parsing. Renders citations in |
| 272 | + * html and replaces the citation markers with the html citations. |
| 273 | + * Also, this method links a style sheet to pages containing citations. |
| 274 | + * |
| 275 | + * @static |
| 276 | + * @global type $wgOut |
| 277 | + * @global type $wgWCStyleSheet |
| 278 | + * @param Parser $parser = the parser |
| 279 | + * @param string $text = the current parsed text of the article |
| 280 | + */ |
| 281 | + public static function onParserBeforeTidy( Parser $parser, &$text ) { |
| 282 | + # Insert citations. |
| 283 | + self::$article->render( $text ); |
| 284 | + return True; |
| 285 | + } |
| 286 | + |
| 287 | + |
| 288 | +} |
Property changes on: trunk/extensions/WikiCitation/WikiCitation.body.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 289 | + native |
Index: trunk/extensions/WikiCitation/WikiCitation.i18n.magic.php |
— | — | @@ -0,0 +1,253 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | +$magicWords = array(); |
| 11 | + |
| 12 | +$magicWords['en'] = array( |
| 13 | + |
| 14 | + /** |
| 15 | + * Parser function and tag extension elements and attributes. |
| 16 | + */ |
| 17 | + 'wc_cite_tag' => array( 1, 'cite' ), # {{#cite:______}} |
| 18 | + 'wc_biblio_tag' => array( 1, 'biblio' ), # <biblio>...</biblio> |
| 19 | + 'wc_note_tag' => array( 1, 'note' ), # <note>...</note> |
| 20 | + 'wc_notes_tag' => array( 1, 'notes' ), # <notes/> |
| 21 | + 'wc_section_tag' => array( 1, 'notesection'), # <notesection>...</notesection> |
| 22 | + |
| 23 | + 'wc_citestyle_attrib' => array( 1, 'citestyle' ), # attribute for <biblio> and <section> tags |
| 24 | + 'wc_type_attrib' => array( 1, 'type' ), # attribute for <biblio> and <section> tags |
| 25 | + |
| 26 | + |
| 27 | + /** |
| 28 | + * Words used by WCArgumentReader.php |
| 29 | + */ |
| 30 | + # name of defined styles, including default |
| 31 | + 'wc_default' => array( 0, 'default' ), |
| 32 | + 'wc_Chicago' => array( 0, 'Chicago' ), |
| 33 | + 'wc_Bluebook' => array( 0, 'Bluebook' ), |
| 34 | + |
| 35 | + |
| 36 | + /** |
| 37 | + * Flags |
| 38 | + */ |
| 39 | + # citation type |
| 40 | + 'wc_inline' => array( 0, 'inline' ), |
| 41 | + 'wc_bibliography' => array( 0, 'bibliography', 'biblio' ), |
| 42 | + 'wc_note' => array( 0, 'note' ), |
| 43 | + 'wc_author_date' => array( 0, 'author-date' ), # indicates author-date style variant |
| 44 | + |
| 45 | + # citation length |
| 46 | + 'wc_long' => array( 0, 'long' ), |
| 47 | + 'wc_short' => array( 0, 'short' ), |
| 48 | + |
| 49 | + /** |
| 50 | + * Scope and type parameters |
| 51 | + */ |
| 52 | + # Combining parameters denoting works or names relating to the work. These |
| 53 | + # will be prefixes. |
| 54 | + 'wc_work' => array( 0, 'work' ), # This will be the default. |
| 55 | + 'wc_container' => array( 0, 'container' ), |
| 56 | + 'wc_series' => array( 0, 'series', 'periodical', 'journal' ), |
| 57 | + 'wc_original' => array( 0, 'original' ), |
| 58 | + 'wc_subject' => array( 0, 'subject' ), |
| 59 | + |
| 60 | + /** |
| 61 | + * Parameters defining data about the work as a whole. |
| 62 | + */ |
| 63 | + # Type of reference (e.g., book, article, etc.). See below |
| 64 | + 'wc_type' => array( 0, 'type' ), |
| 65 | + |
| 66 | + # links |
| 67 | + 'wc_link' => array( 0, 'link' ), # wikilink to page about source. In English, this needs to be processed before authors, to avoid conflict. |
| 68 | + 'wc_URL' => array( 0, 'url', 'uri' ), |
| 69 | + |
| 70 | + # reference numbers |
| 71 | + 'wc_call_number' => array( 0, 'call-number' ), |
| 72 | + 'wc_DOI' => array( 0, 'DOI' ), |
| 73 | + 'wc_ISBN' => array( 0, 'ISBN' ), |
| 74 | + |
| 75 | + # date variables |
| 76 | + 'wc_date' => array( 0, 'date', 'dates', 'year', 'years' ), |
| 77 | + 'wc_accessed' => array( 0, 'accessed' ), |
| 78 | + 'wc_issued' => array( 0, 'issued' ), |
| 79 | + 'wc_filed' => array( 0, 'filed' ), |
| 80 | + |
| 81 | + # other data parameters |
| 82 | + 'wc_title' => array( 0, 'title' ), |
| 83 | + 'wc_short_title' => array( 0, 'short-title' ), |
| 84 | + 'wc_place' => array( 0, 'place', 'publisher-place', 'publication-place', 'archive-location', 'archive-place' ), |
| 85 | + 'wc_edition' => array( 0, 'edition' ), |
| 86 | + 'wc_volume' => array( 0, 'volume' ), |
| 87 | + 'wc_issue' => array( 0, 'issue' ), |
| 88 | + 'wc_first_page' => array( 0, 'first-page' ), |
| 89 | + 'wc_version' => array( 0, 'version' ), |
| 90 | + 'wc_number' => array( 0, 'number' ), |
| 91 | + 'wc_opus' => array( 0, 'opus' ), |
| 92 | + 'wc_archive' => array( 0, 'archive' ), |
| 93 | + 'wc_jurisdiction' => array( 0, 'jurisdiction' ), |
| 94 | + 'wc_keyword' => array( 0, 'keyword' ), |
| 95 | + |
| 96 | + /** |
| 97 | + * Parameters denoting one or more locations within a work (i.e., locators). |
| 98 | + */ |
| 99 | + 'wc_book_loc' => array( 0, 'book', 'books' ), # i.e., biblical "book," book III of Lord of the Rings, etc. |
| 100 | + 'wc_part' => array( 0, 'part', 'parts' ), |
| 101 | + 'wc_chapter_loc' => array( 0, 'chapter', 'chapters' ), |
| 102 | + 'wc_page' => array( 0, 'page', 'pages' ), |
| 103 | + 'wc_page_range' => array( 0, 'page-range' ), |
| 104 | + 'wc_folio' => array( 0, 'folio', 'folios' ), |
| 105 | + 'wc_column' => array( 0, 'column', 'columns' ), |
| 106 | + 'wc_table' => array( 0, 'table', 'tables' ), |
| 107 | + 'wc_figure' => array( 0, 'figure', 'figures' ), |
| 108 | + 'wc_section' => array( 0, 'section', 'sections' ), |
| 109 | + 'wc_paragraph' => array( 0, 'paragraph', 'paragraphs' ), |
| 110 | + 'wc_note_loc' => array( 0, 'note', 'notes' ), |
| 111 | + 'wc_footnote' => array( 0, 'footnote', 'footnotes' ), |
| 112 | + 'wc_endnote' => array( 0, 'endnote', 'endnotes' ), |
| 113 | + 'wc_verse' => array( 0, 'verse', 'verses' ), |
| 114 | + 'wc_line' => array( 0, 'line', 'lines' ), |
| 115 | + 'wc_locator' => array( 0, 'locator', 'locators' ), # a generic or descriptive locator |
| 116 | + |
| 117 | + # Values for type of reference |
| 118 | + 'wc_general' => array( 0, 'general' ), # the default: could be any type of reference |
| 119 | + 'wc_book' => array( 0, 'book' ), |
| 120 | + 'wc_dictionary' => array( 0, 'dictionary' ), |
| 121 | + 'wc_encyclopedia' => array( 0, 'encyclopedia' ), |
| 122 | + 'wc_periodical' => array( 0, 'periodical' ), |
| 123 | + 'wc_magazine' => array( 0, 'magazine' ), |
| 124 | + 'wc_newspaper' => array( 0, 'newspaper' ), |
| 125 | + 'wc_journal' => array( 0, 'journal' ), |
| 126 | + 'wc_entry' => array( 0, 'entry' ), |
| 127 | + 'wc_article' => array( 0, 'article' ), |
| 128 | + 'wc_chapter' => array( 0, 'chapter' ), |
| 129 | + 'wc_review' => array( 0, 'review' ), |
| 130 | + 'wc_paper' => array( 0, 'paper' ), |
| 131 | + 'wc_manuscript' => array( 0, 'manuscript' ), |
| 132 | + 'wc_musical_score' => array( 0, 'musical-score' ), |
| 133 | + 'wc_pamphlet' => array( 0, 'pamphlet' ), |
| 134 | + 'wc_conference_paper' => array( 0, 'conference-paper' ), |
| 135 | + 'wc_thesis' => array( 0, 'thesis' ), |
| 136 | + 'wc_dissertation' => array( 0, 'PhD-dissertation' ), |
| 137 | + 'wc_report' => array( 0, 'report' ), |
| 138 | + 'wc_poem' => array( 0, 'poem' ), |
| 139 | + 'wc_song' => array( 0, 'song' ), |
| 140 | + 'wc_enactment' => array( 0, 'enactment', 'legislation' ), |
| 141 | + 'wc_bill' => array( 0, 'bill' ), |
| 142 | + 'wc_statute' => array( 0, 'statute' ), |
| 143 | + 'wc_treaty' => array( 0, 'treaty' ), |
| 144 | + 'wc_rule' => array( 0, 'rule' ), |
| 145 | + 'wc_regulation' => array( 0, 'regulation' ), |
| 146 | + 'wc_legal_document' => array( 0, 'legal-document' ), |
| 147 | + 'wc_patent' => array( 0, 'patent' ), |
| 148 | + 'wc_deed' => array( 0, 'deed' ), |
| 149 | + 'wc_government_grant' => array( 0, 'government-grant' ), |
| 150 | + 'wc_filing' => array( 0, 'filing' ), |
| 151 | + 'wc_patent_application' => array( 0, 'patent-application' ), |
| 152 | + 'wc_regulatory_filing' => array( 0, 'regulatory-filing' ), |
| 153 | + 'wc_litigation' => array( 0, 'litigation' ), |
| 154 | + 'wc_legal_opinion' => array( 0, 'legal-opinion' ), |
| 155 | + 'wc_legal_case' => array( 0, 'legal-case' ), |
| 156 | + 'wc_graphic' => array( 0, 'graphic' ), |
| 157 | + 'wc_photograph' => array( 0, 'photograph' ), |
| 158 | + 'wc_map' => array( 0, 'map' ), |
| 159 | + 'wc_statement' => array( 0, 'statement'), |
| 160 | + 'wc_press_release' => array( 0, 'press-release'), |
| 161 | + 'wc_interview' => array( 0, 'interview' ), |
| 162 | + 'wc_speech' => array( 0, 'speech' ), |
| 163 | + 'wc_personal_communication' => array( 0, 'personal-communication' ), |
| 164 | + 'wc_internet_resource' => array( 0, 'internet-resource' ), |
| 165 | + 'wc_web_page' => array( 0, 'web-page', 'webpage' ), |
| 166 | + 'wc_post' => array( 0, 'post' ), |
| 167 | + 'wc_production' => array( 0, 'production' ), |
| 168 | + 'wc_motion_picture' => array( 0, 'motion-picture' ), |
| 169 | + 'wc_recording' => array( 0, 'recording' ), |
| 170 | + 'wc_play' => array( 0, 'play' ), |
| 171 | + 'wc_broadcast' => array( 0, 'broadcast' ), |
| 172 | + 'wc_television_broadcast' => array( 0, 'television-broadcast' ), |
| 173 | + 'wc_radio_broadcast' => array( 0, 'radio-broadcast' ), |
| 174 | + 'wc_internet_broadcast' => array( 0, 'internet-broadcast' ), |
| 175 | + 'wc_object' => array( 0, 'object' ), |
| 176 | + 'wc_star' => array( 0, 'star' ), |
| 177 | + 'wc_gravestone' => array( 0, 'gravestone', 'headstone' ), |
| 178 | + 'wc_monument' => array( 0, 'monument' ), |
| 179 | + 'wc_real_property' => array( 0, 'real-property' ), |
| 180 | + |
| 181 | + /** |
| 182 | + * Name parameters |
| 183 | + */ |
| 184 | + # Parameters denoting names, including persons |
| 185 | + 'wc_author' => array( 0, 'author' ), |
| 186 | + 'wc_publisher' => array( 0, 'publisher' ), |
| 187 | + 'wc_editor_translator' => array( 0, 'editor-translator', 'translator-editor' ), |
| 188 | + 'wc_editor' => array( 0, 'editor' ), |
| 189 | + 'wc_translator' => array( 0, 'translator' ), |
| 190 | + 'wc_interviewer' => array( 0, 'interviewer' ), |
| 191 | + 'wc_recipient' => array( 0, 'recipient' ), |
| 192 | + 'wc_composer' => array( 0, 'composer' ), |
| 193 | + |
| 194 | + # words denoting types of name data |
| 195 | + 'wc_surname' => array( 0, 'surname', 'last' ), |
| 196 | + 'wc_given' => array( 0, 'given', 'first' ), |
| 197 | + 'wc_namelink' => array( 0, 'link' ), |
| 198 | + 'wc_suffix' => array( 0, 'suffix' ), |
| 199 | + 'wc_droppingparticle' => array( 0, 'dropping-particle' ), |
| 200 | + 'wc_nondroppingparticle' => array( 0, 'non-dropping-particle' ), |
| 201 | + 'wc_literalname' => array( 0, 'literal', 'organization' ), |
| 202 | + |
| 203 | + |
| 204 | + /** |
| 205 | + * Other magic words |
| 206 | + */ |
| 207 | + 'wc_ad_magic_word' => array( 1, 'A.D.', 'AD', 'C.E.', 'CE' ), |
| 208 | + 'wc_bc_magic_word' => array( 1, 'B.C.', 'BC', 'B.C.E.', 'BCE' ), |
| 209 | + 'wc_circa' => array( 0, 'circa', 'c.', 'around', 'about' ), |
| 210 | + 'wc_spring' => array( 0, 'spring' ), |
| 211 | + 'wc_summer' => array( 0, 'summer' ), |
| 212 | + 'wc_autumn' => array( 0, 'autumn', 'fall' ), |
| 213 | + 'wc_winter' => array( 0, 'winter' ), |
| 214 | + 'wc_year' => array( 0, 'year' ), # 年 |
| 215 | + 'wc_month' => array( 0, 'month' ), # 月 |
| 216 | + 'wc_day' => array( 0, 'day' ), # 日 |
| 217 | + |
| 218 | + 'wc_list_delimiter' => array( 0, ',', 'and', '&' ), # Delimits various discrete numbers or number ranges |
| 219 | + 'wc_range_delimiter' => array( 0, 'to' ), # Indicates a continuous number range |
| 220 | + |
| 221 | + 'wc_initial_exterior_quote' => array( 0, '"', '“', ), # initial exterior quote symbol for input purposes |
| 222 | + 'wc_final_exterior_quote' => array( 0, '"', '”', ), # final exterior quote symbol |
| 223 | + 'wc_initial_interior_quote' => array( 0, "'", '‘', ), # initial interior quote symbol |
| 224 | + 'wc_final_interior_quote' => array( 0, "'", '’', ), # final interior quote symbol |
| 225 | + 'wc_articles' => array( 0, 'a', 'an', 'the', 'el', 'la' ), |
| 226 | + 'wc_prepositions' => array( 0, 'aboard', 'about', 'abaft', 'aboard', 'about', 'above', 'absent', 'across', 'afore', 'after', 'against', 'along', 'alongside', 'amid', 'amidst', 'among', 'amongst', 'apropos', 'around', 'as', 'aside', 'astride', 'at', 'athwart', 'atop', |
| 227 | + 'barring', 'before', 'behind', 'below', 'beneath', 'beside', 'besides', 'between', 'betwixt', 'beyond', 'but', 'by', |
| 228 | + 'circa', 'c.', 'ca.', 'concerning', |
| 229 | + 'despite', 'down', 'during', |
| 230 | + 'except', 'excluding', |
| 231 | + 'failing', 'following', 'for', 'from', |
| 232 | + 'given', |
| 233 | + 'in', 'including', 'inside', 'into', |
| 234 | + 'like', |
| 235 | + 'mid,', 'midst', 'minus', |
| 236 | + 'near', 'next', 'notwithstanding', |
| 237 | + 'of', 'off', 'on', 'onto', 'opposite', 'out', 'outside', 'over', |
| 238 | + 'pace', 'past', 'per', 'plus', 'pro', |
| 239 | + 'qua', |
| 240 | + 'regarding', 'round', |
| 241 | + 'sans', 'save', 'since', |
| 242 | + 'than', 'through,', 'thru,', 'throughout,', 'thruout', 'till', 'times', 'to', 'toward', 'towards', |
| 243 | + 'under', 'underneath', 'unlike', 'until', 'up', 'upon', |
| 244 | + 'versus', 'vs.', 'v.', 'via', 'vice', |
| 245 | + 'with', 'within', 'without', 'worth' |
| 246 | + ), |
| 247 | + 'wc_coordinating_conjunctions' => array( 0, 'and', 'but', 'for', 'nor', 'or', 'so', 'yet' ), |
| 248 | + 'wc_subordinating_conjunctions' => array( 0, 'after', 'although', 'as', 'because', 'before', 'both', 'either', |
| 249 | + 'how', 'however', 'if', 'neither', 'now', 'once', 'only', 'provided', |
| 250 | + 'since', 'than', 'that', 'though', 'till', 'unless', 'until', |
| 251 | + 'when', 'whenever', 'where', 'whereas', 'wherever', 'whether', 'while' ), |
| 252 | + |
| 253 | + |
| 254 | +); |
Property changes on: trunk/extensions/WikiCitation/WikiCitation.i18n.magic.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 255 | + native |
Index: trunk/extensions/WikiCitation/WikiCitation.i18n.php |
— | — | @@ -0,0 +1,240 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | +$messages = array (); |
| 11 | + |
| 12 | + |
| 13 | +/** Pseudo-language with explanations */ |
| 14 | +$messages['qqq'] = array( |
| 15 | + 'wc-description' => 'Description of the WikiCitation extension.', |
| 16 | + 'wc-ws' => 'The normal delimiter or punctuation between two names. For example, if there are two authors, text would be placed between them, except when the citation is presented with surname first, for sorting within a bibliography (in which case "wc-name-punct" would be used).', |
| 17 | + 'wc-name-punct' => 'The normal delimiter or punctuation between two names, when the citation is presented with surname first, for sorting within a bibliography', |
| 18 | + ); |
| 19 | + |
| 20 | + |
| 21 | +/** English */ |
| 22 | +$messages['en'] = array ( |
| 23 | + |
| 24 | + # Extension description |
| 25 | + 'wc-description' => 'Adds tags for fast standard reference citations and automatic bibliographies', |
| 26 | + |
| 27 | + |
| 28 | + # Name separators |
| 29 | + 'wc-name-whitespace' => ' ', # whitespace, if any, between names |
| 30 | + 'wc-name-sort-order-delimiter' => ', ', # punctuation between names in name-sort mode |
| 31 | + 'wc-surname-delimiter' => ', ', # punctuation after surname in name-sort mode |
| 32 | + 'wc-name-suffix-delimiter' => ' ', # Delimiter before name suffix |
| 33 | + 'wc-name-missing' => '___', # blank to represent a missing name |
| 34 | + |
| 35 | + 'wc-names-delim' => ', ', # the normal delimiter between names |
| 36 | + 'wc-names-et-al-delim' => ', ', # the delimiter before the "and others" designation |
| 37 | + 'wc-names-and-2' => ' and ', # the delimiter between two names if there are only two |
| 38 | + 'wc-names-and-3' => ', and ', # the last delimiter for three or more names |
| 39 | + 'wc-names-and-others' => 'et al.', # "and others" |
| 40 | + |
| 41 | + # Citation separators and punctuation |
| 42 | + 'wc-initial-exterior-quote' => '"', # initial exterior quote symbol. (Note: for now, typewriter quotes are widely used in English wikis.) |
| 43 | + 'wc-final-exterior-quote' => '"', # final exterior quote symbol |
| 44 | + 'wc-initial-interior-quote' => "'", # initial interior quote symbol |
| 45 | + 'wc-final-interior-quote' => "'", # final interior quote symbol |
| 46 | + 'wc-segment-missing' => '___', # blank to represent a missing segment |
| 47 | + 'wc-range-delimiter' => '–', # delimiter for ranges (usually en-dash). |
| 48 | + |
| 49 | + # Date localization |
| 50 | + 'wc-ad' => 'A.D.', |
| 51 | + 'wc-ad-no-punct' => 'AD', |
| 52 | + 'wc-ce' => 'C.E.', |
| 53 | + 'wc-ce-no-punct' => 'CE', |
| 54 | + 'wc-bc' => 'B.C.', |
| 55 | + 'wc-bc-no-punct' => 'BC', |
| 56 | + 'wc-bce' => 'B.C.E.', |
| 57 | + 'wc-bce-no-punct' => 'BCE', |
| 58 | + 'wc_spring' => 'spring', |
| 59 | + 'wc_summer' => 'summer', |
| 60 | + 'wc_autumn' => 'fall', |
| 61 | + 'wc_winter' => 'winter', |
| 62 | + 'wc_year' => 'year', # 年 |
| 63 | + 'wc_month' => 'month', # 月 |
| 64 | + 'wc_day' => 'day', # 日 |
| 65 | + |
| 66 | + /* |
| 67 | + * Literal text |
| 68 | + */ |
| 69 | + 'wc-personal-communication' => 'personal communication', |
| 70 | + |
| 71 | + |
| 72 | + /* |
| 73 | + * Labels |
| 74 | + */ |
| 75 | + 'wc-author-long-singular' => 'author', |
| 76 | + 'wc-author-long-plural' => 'authors', |
| 77 | + 'wc-author-verb-singular' => 'authored by', |
| 78 | + 'wc-author-verb-plural' => 'authored by', |
| 79 | + 'wc-author-short-singular' => 'auth.', |
| 80 | + 'wc-author-short-plural' => 'auths.', |
| 81 | + 'wc-author-verb-short-singular' => 'auth.', |
| 82 | + 'wc-author-verb-short-plural' => 'auth.', |
| 83 | + 'wc-author-symbol-singular' => 'auth.', |
| 84 | + 'wc-author-symbol-plural' => 'auths.', |
| 85 | + |
| 86 | + 'wc-editor-long-singular' => 'editor', |
| 87 | + 'wc-editor-long-plural' => 'editors', |
| 88 | + 'wc-editor-verb-singular' => 'edited by', |
| 89 | + 'wc-editor-verb-plural' => 'edited by', |
| 90 | + 'wc-editor-short-singular' => 'ed.', |
| 91 | + 'wc-editor-short-plural' => 'eds.', |
| 92 | + 'wc-editor-verb-short-singular' => 'ed.', |
| 93 | + 'wc-editor-verb-short-plural' => 'eds.', |
| 94 | + 'wc-editor-symbol-singular' => 'ed.', |
| 95 | + 'wc-editor-symbol-plural' => 'eds.', |
| 96 | + |
| 97 | + 'wc-translator-long-singular' => 'translator', |
| 98 | + 'wc-translator-long-plural' => 'translators', |
| 99 | + 'wc-translator-verb-singular' => 'translated by', |
| 100 | + 'wc-translator-verb-plural' => 'translated by', |
| 101 | + 'wc-translator-short-singular' => 'trans.', |
| 102 | + 'wc-translator-short-plural' => 'trans.', |
| 103 | + 'wc-translator-verb-short-singular' => 'trans.', |
| 104 | + 'wc-translator-verb-short-plural' => 'trans.', |
| 105 | + 'wc-translator-symbol-singular' => 'trans.', |
| 106 | + 'wc-translator-symbol-plural' => 'trans.', |
| 107 | + |
| 108 | + 'wc-editor-translator-long-singular' => 'editor and translator', |
| 109 | + 'wc-editor-translator-long-plural' => 'editors and translators', |
| 110 | + 'wc-editor-translator-verb-singular' => 'edited and translated by', |
| 111 | + 'wc-editor-translator-verb-plural' => 'edited and translated by', |
| 112 | + 'wc-editor-translator-short-singular' => 'ed. and trans.', |
| 113 | + 'wc-editor-translator-short-plural' => 'eds. and trans.', |
| 114 | + 'wc-editor-translator-verb-short-singular' => 'ed. and trans.', |
| 115 | + 'wc-editor-translator-verb-short-plural' => 'eds. and trans.', |
| 116 | + 'wc-editor-translator-symbol-singular' => 'ed. & trans.', |
| 117 | + 'wc-editor-translator-symbol-plural' => 'ed. & trans.', |
| 118 | + |
| 119 | + 'wc-publisher-long-singular' => 'publisher', |
| 120 | + 'wc-publisher-long-plural' => 'publishers', |
| 121 | + 'wc-publisher-verb-singular' => 'published by', |
| 122 | + 'wc-publisher-verb-plural' => 'published by', |
| 123 | + 'wc-publisher-short-singular' => 'pub.', |
| 124 | + 'wc-publisher-short-plural' => 'pubs.', |
| 125 | + 'wc-publisher-verb-short-singular' => 'pub. by', |
| 126 | + 'wc-publisher-verb-short-plural' => 'pubs. by', |
| 127 | + 'wc-publisher-symbol-singular' => 'pub.', |
| 128 | + 'wc-publisher-symbol-plural' => 'pubs.', |
| 129 | + |
| 130 | + 'wc-interviewer-long-singular' => 'interviewer', |
| 131 | + 'wc-interviewer-long-plural' => 'interviewers', |
| 132 | + 'wc-interviewer-verb-singular' => 'interview by', |
| 133 | + 'wc-interviewer-verb-plural' => 'interview by', |
| 134 | + 'wc-interviewer-short-singular' => 'interviewer', |
| 135 | + 'wc-interviewer-short-plural' => 'interviewers', |
| 136 | + 'wc-interviewer-verb-short-singular' => 'interview by', |
| 137 | + 'wc-interviewer-verb-short-plural' => 'interview by', |
| 138 | + 'wc-interviewer-symbol-singular' => 'interviewer', |
| 139 | + 'wc-interviewer-symbol-plural' => 'interviewers', |
| 140 | + |
| 141 | + 'wc-recipient-long-singular' => 'recipient', |
| 142 | + 'wc-recipient-long-plural' => 'recipients', |
| 143 | + 'wc-recipient-verb-singular' => 'received by', |
| 144 | + 'wc-recipient-verb-plural' => 'received by', |
| 145 | + 'wc-recipient-short-singular' => 'to', |
| 146 | + 'wc-recipient-short-plural' => 'to', |
| 147 | + 'wc-recipient-verb-short-singular' => 'to', |
| 148 | + 'wc-recipient-verb-short-plural' => 'to', |
| 149 | + 'wc-recipient-symbol-singular' => 'to', |
| 150 | + 'wc-recipient-symbol-plural' => 'to', |
| 151 | + |
| 152 | + 'wc-composer-long-singular' => 'composer', |
| 153 | + 'wc-composer-long-plural' => 'composers', |
| 154 | + 'wc-composer-verb-singular' => 'composed by', |
| 155 | + 'wc-composer-verb-plural' => 'composed by', |
| 156 | + 'wc-composer-short-singular' => 'composer', |
| 157 | + 'wc-composer-short-plural' => 'composers', |
| 158 | + 'wc-composer-verb-short-singular' => 'composed by', |
| 159 | + 'wc-composer-verb-short-plural' => 'composed by', |
| 160 | + 'wc-composer-symbol-singular' => 'composer', |
| 161 | + 'wc-composer-symbol-plural' => 'composers', |
| 162 | + |
| 163 | + 'wc-page-long-singular' => 'page', |
| 164 | + 'wc-page-long-plural' => 'pages', |
| 165 | + 'wc-page-verb-singular' => 'page', |
| 166 | + 'wc-page-verb-plural' => 'pages', |
| 167 | + 'wc-page-short-singular' => 'p.', |
| 168 | + 'wc-page-short-plural' => 'pp.', |
| 169 | + 'wc-page-verb-short-singular' => 'p.', |
| 170 | + 'wc-page-verb-short-plural' => 'pp.', |
| 171 | + 'wc-page-symbol-singular' => 'p.', |
| 172 | + 'wc-page-symbol-plural' => 'pp.', |
| 173 | + |
| 174 | + 'wc-section-long-singular' => 'section', |
| 175 | + 'wc-section-long-plural' => 'sections', |
| 176 | + 'wc-section-verb-singular' => 'section', |
| 177 | + 'wc-section-verb-plural' => 'sections', |
| 178 | + 'wc-section-short-singular' => 'sec.', |
| 179 | + 'wc-section-short-plural' => 'secs.', |
| 180 | + 'wc-section-verb-short-singular' => 'sec.', |
| 181 | + 'wc-section-verb-short-plural' => 'sec.', |
| 182 | + 'wc-section-symbol-singular' => '§', |
| 183 | + 'wc-section-symbol-plural' => '§§', |
| 184 | + |
| 185 | + 'wc-paragraph-long-singular' => 'paragraph', |
| 186 | + 'wc-paragraph-long-plural' => 'paragraphs', |
| 187 | + 'wc-paragraph-verb-singular' => 'paragraph', |
| 188 | + 'wc-paragraph-verb-plural' => 'paragraphs', |
| 189 | + 'wc-paragraph-short-singular' => 'para.', |
| 190 | + 'wc-paragraph-short-plural' => 'paras.', |
| 191 | + 'wc-paragraph-verb-short-singular' => 'para.', |
| 192 | + 'wc-paragraph-verb-short-plural' => 'paras.', |
| 193 | + 'wc-paragraph-symbol-singular' => '¶', |
| 194 | + 'wc-paragraph-symbol-plural' => '¶¶', |
| 195 | + |
| 196 | + 'wc-volume-long-singular' => 'volume', |
| 197 | + 'wc-volume-long-plural' => 'volumes', |
| 198 | + 'wc-volume-verb-singular' => 'volume', |
| 199 | + 'wc-volume-verb-plural' => 'volumes', |
| 200 | + 'wc-volume-short-singular' => 'vol.', |
| 201 | + 'wc-volume-short-plural' => 'volss.', |
| 202 | + 'wc-volume-verb-short-singular' => 'vol.', |
| 203 | + 'wc-volume-verb-short-plural' => 'vols.', |
| 204 | + 'wc-volume-symbol-singular' => 'vol.', |
| 205 | + 'wc-volume-symbol-plural' => 'vols.', |
| 206 | + |
| 207 | + 'wc-issue-long-singular' => 'issue', |
| 208 | + 'wc-issue-long-plural' => 'issues', |
| 209 | + 'wc-issue-verb-singular' => 'issue', |
| 210 | + 'wc-issue-verb-plural' => 'issue', |
| 211 | + 'wc-issue-short-singular' => 'no.', |
| 212 | + 'wc-issue-short-plural' => 'nos.', |
| 213 | + 'wc-issue-verb-short-singular' => 'no.', |
| 214 | + 'wc-issue-verb-short-plural' => 'nos.', |
| 215 | + 'wc-issue-symbol-singular' => 'no.', |
| 216 | + 'wc-issue-symbol-plural' => 'nos.', |
| 217 | + |
| 218 | + 'wc-circa-long-singular' => 'circa', |
| 219 | + 'wc-circa-long-plural' => 'circa', |
| 220 | + 'wc-circa-verb-singular' => 'about', |
| 221 | + 'wc-circa-verb-plural' => 'about', |
| 222 | + 'wc-circa-short-singular' => 'c.', |
| 223 | + 'wc-circa-short-plural' => 'c.', |
| 224 | + 'wc-circa-verb-short-singular' => 'abt.', |
| 225 | + 'wc-circa-verb-short-plural' => 'abt.', |
| 226 | + 'wc-circa-symbol-singular' => 'c.', |
| 227 | + 'wc-circa-symbol-plural' => 'c.', |
| 228 | + |
| 229 | + /* |
| 230 | + * Error messages |
| 231 | + */ |
| 232 | + 'wc-style-not-recognized' => 'Cite error: <code>$1</code> citation style not recognized.', |
| 233 | + 'wc-flag-unknown' => 'Cite error: unknown <code>$1</code>.', |
| 234 | + 'wc-incompatible-flags' => 'Cite error: citation cannot be <code>$1</code> and <code>$2</code>.', |
| 235 | + 'wc-parameter_defined_twice' => 'Cite error: <code>$1</code> defined twice.', |
| 236 | + 'wc-parameter-unknown' => 'Cite error: <code>$1</code> not a recognized property.', |
| 237 | + 'wc-type-parameter-unknown' => 'Cite error: <code>$1</code> not a recognized <code>type</code>.', |
| 238 | + |
| 239 | + |
| 240 | +); |
| 241 | + |
Property changes on: trunk/extensions/WikiCitation/WikiCitation.i18n.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 242 | + native |
Index: trunk/extensions/WikiCitation/styles/WCChicagoStyle.php |
— | — | @@ -0,0 +1,511 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCChicagoStyle extends WCStyle { |
| 12 | + |
| 13 | + public static $titleFormatArray = array ( |
| 14 | + WCSourceTypeEnum::general => WCTitleFormat::italic, |
| 15 | + WCSourceTypeEnum::book => WCTitleFormat::italic, |
| 16 | + WCSourceTypeEnum::dictionary => WCTitleFormat::italic, |
| 17 | + WCSourceTypeEnum::encyclopedia => WCTitleFormat::italic, |
| 18 | + WCSourceTypeEnum::periodical => WCTitleFormat::italic, |
| 19 | + WCSourceTypeEnum::magazine => WCTitleFormat::italic, |
| 20 | + WCSourceTypeEnum::newspaper => WCTitleFormat::italic, |
| 21 | + WCSourceTypeEnum::journal => WCTitleFormat::italic, |
| 22 | + WCSourceTypeEnum::entry => WCTitleFormat::quoted, |
| 23 | + WCSourceTypeEnum::article => WCTitleFormat::quoted, |
| 24 | + WCSourceTypeEnum::chapter => WCTitleFormat::quoted, |
| 25 | + WCSourceTypeEnum::review => WCTitleFormat::quoted, |
| 26 | + WCSourceTypeEnum::paper => WCTitleFormat::quoted, |
| 27 | + WCSourceTypeEnum::manuscript => WCTitleFormat::quoted, |
| 28 | + WCSourceTypeEnum::musicalScore => WCTitleFormat::quoted, |
| 29 | + WCSourceTypeEnum::pamphlet => WCTitleFormat::italic, |
| 30 | + WCSourceTypeEnum::conferencePaper => WCTitleFormat::quoted, |
| 31 | + WCSourceTypeEnum::thesis => WCTitleFormat::quoted, |
| 32 | + WCSourceTypeEnum::report => WCTitleFormat::italic, |
| 33 | + WCSourceTypeEnum::poem => WCTitleFormat::quoted, |
| 34 | + WCSourceTypeEnum::song => WCTitleFormat::italic, |
| 35 | + WCSourceTypeEnum::enactment => WCTitleFormat::quoted, |
| 36 | + WCSourceTypeEnum::bill => WCTitleFormat::quoted, |
| 37 | + WCSourceTypeEnum::statute => WCTitleFormat::quoted, |
| 38 | + WCSourceTypeEnum::treaty => WCTitleFormat::quoted, |
| 39 | + WCSourceTypeEnum::rule => WCTitleFormat::quoted, |
| 40 | + WCSourceTypeEnum::regulation => WCTitleFormat::quoted, |
| 41 | + WCSourceTypeEnum::legalDocument => WCTitleFormat::quoted, |
| 42 | + WCSourceTypeEnum::patent => WCTitleFormat::quoted, |
| 43 | + WCSourceTypeEnum::deed => WCTitleFormat::quoted, |
| 44 | + WCSourceTypeEnum::governmentGrant => WCTitleFormat::quoted, |
| 45 | + WCSourceTypeEnum::filing => WCTitleFormat::quoted, |
| 46 | + WCSourceTypeEnum::patentApplication => WCTitleFormat::quoted, |
| 47 | + WCSourceTypeEnum::regulatoryFiling => WCTitleFormat::quoted, |
| 48 | + WCSourceTypeEnum::litigation => WCTitleFormat::italic, |
| 49 | + WCSourceTypeEnum::legalOpinion => WCTitleFormat::italic, |
| 50 | + WCSourceTypeEnum::legalCase => WCTitleFormat::italic, |
| 51 | + WCSourceTypeEnum::graphic => WCTitleFormat::italic, |
| 52 | + WCSourceTypeEnum::photograph => WCTitleFormat::italic, |
| 53 | + WCSourceTypeEnum::map => WCTitleFormat::italic, |
| 54 | + WCSourceTypeEnum::statement => WCTitleFormat::quoted, |
| 55 | + WCSourceTypeEnum::pressRelease => WCTitleFormat::quoted, |
| 56 | + WCSourceTypeEnum::interview => WCTitleFormat::quoted, |
| 57 | + WCSourceTypeEnum::speech => WCTitleFormat::quoted, |
| 58 | + WCSourceTypeEnum::personalCommunication => WCTitleFormat::quoted, |
| 59 | + WCSourceTypeEnum::internetResource => WCTitleFormat::quoted, |
| 60 | + WCSourceTypeEnum::webpage => WCTitleFormat::quoted, |
| 61 | + WCSourceTypeEnum::post => WCTitleFormat::quoted, |
| 62 | + WCSourceTypeEnum::production => WCTitleFormat::italic, |
| 63 | + WCSourceTypeEnum::motionPicture => WCTitleFormat::italic, |
| 64 | + WCSourceTypeEnum::recording => WCTitleFormat::italic, |
| 65 | + WCSourceTypeEnum::play => WCTitleFormat::italic, |
| 66 | + WCSourceTypeEnum::broadcast => WCTitleFormat::italic, |
| 67 | + WCSourceTypeEnum::televisionBroadcast => WCTitleFormat::italic, |
| 68 | + WCSourceTypeEnum::radioBroadcast => WCTitleFormat::italic, |
| 69 | + WCSourceTypeEnum::internetBroadcast => WCTitleFormat::italic, |
| 70 | + WCSourceTypeEnum::object => WCTitleFormat::quoted, |
| 71 | + WCSourceTypeEnum::star => WCTitleFormat::quoted, |
| 72 | + WCSourceTypeEnum::gravestone => WCTitleFormat::quoted, |
| 73 | + WCSourceTypeEnum::monument => WCTitleFormat::quoted, |
| 74 | + WCSourceTypeEnum::realProperty => WCTitleFormat::quoted, |
| 75 | + ); |
| 76 | + |
| 77 | + |
| 78 | + /** |
| 79 | + * Constructor. Overwrites a few style properties of parent class, but |
| 80 | + * otherwise keeps everything the same as default. |
| 81 | + */ |
| 82 | + public function __construct() { |
| 83 | + parent::__construct(); |
| 84 | + $this->punctuationInQuotes = True; |
| 85 | + $this->replaceAmpersands = False; |
| 86 | + $this->eraWithoutPunctuation = True; |
| 87 | + $this->eraNoSpace = False; |
| 88 | + $this->eraBeforeYear = False; |
| 89 | + $this->styleHTML = 'Chicago'; |
| 90 | + |
| 91 | + } |
| 92 | + |
| 93 | + |
| 94 | + /** |
| 95 | + * Composes a short inline citation. |
| 96 | + * In the Chicago Manual of Style, inline citations are only used as part of |
| 97 | + * author-date system. Thus, this calls $this->renderShortInlineCitation. |
| 98 | + * is set. |
| 99 | + * @return array |
| 100 | + */ |
| 101 | + public function renderShortInlineCitation( WCCitation $citation ) { |
| 102 | + return $this->renderShortAuthorDateCitation( $citation ); |
| 103 | + } |
| 104 | + |
| 105 | + |
| 106 | + /** |
| 107 | + * Renders a short citation for use in a footnote or endnote. |
| 108 | + * The resulting citation includes closing sentence punctuation. |
| 109 | + * @return array |
| 110 | + */ |
| 111 | + public function renderShortNoteCitation( WCCitation $citation ) { |
| 112 | + $workTypeEnum = $citation->reference->getWorkType(); |
| 113 | + |
| 114 | + $titleFormat = new WCTitleFormat( self::$titleFormatArray[ $workTypeEnum->key ] ); |
| 115 | + |
| 116 | + $cite = new WCGroupSegment( |
| 117 | + array( |
| 118 | + new WCNamesSegment( $citation, $this->important, WCScopeEnum::$work, WCNameTypeEnum::$author, $this->first, WCCitationLengthEnum::$short, False ), |
| 119 | + new WCTitleSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$shortTitle, $titleFormat ), |
| 120 | + new WCLocatorSegment( $citation, $this->important, WCPropertyEnum::$page ), |
| 121 | + ), |
| 122 | + ', ' # delimiter |
| 123 | + ); |
| 124 | + |
| 125 | + return array( $cite->render( $this, '.' ), $cite ); |
| 126 | + } |
| 127 | + |
| 128 | + |
| 129 | + /** |
| 130 | + * Composes a short author-date citation. |
| 131 | + * @return string |
| 132 | + */ |
| 133 | + public function renderShortAuthorDateCitation( WCCitation $citation ) { |
| 134 | + $workTypeEnum = $citation->reference->getWorkType(); |
| 135 | + |
| 136 | + if ( $workTypeEnum->key == WCSourceTypeEnum::personalCommunication ) { |
| 137 | + $locator = new WCAlternativeSegment( |
| 138 | + array ( |
| 139 | + new WCLocatorSegment( $citation, $this->important, WCPropertyEnum::$page ), |
| 140 | + new WCLiteralSegment( $this->personalCommunitation ), |
| 141 | + ) |
| 142 | + ); |
| 143 | + } else { |
| 144 | + $locator = new WCLocatorSegment( $citation, $this->important, WCPropertyEnum::$page ); |
| 145 | + } |
| 146 | + |
| 147 | + $cite = new WCGroupSegment( |
| 148 | + array( |
| 149 | + new WCGroupSegment( |
| 150 | + array( |
| 151 | + new WCNamesSegment( $citation, $this->mandatory, WCScopeEnum::$work, WCNameTypeEnum::$author, $this->first, WCCitationLengthEnum::$short, False ), |
| 152 | + new WCDateSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$date, new WCDateParts( WCDateParts::year ), new WCDateOrder( WCDateOrder::littleEndian ), new WCDateForm( WCDateForm::numeric ), new WCDateRange( WCDateRange::range ), '', '' ), |
| 153 | + ), ' ' |
| 154 | + ), |
| 155 | + $locator, |
| 156 | + ), |
| 157 | + ', ', # delimiter |
| 158 | + '(', # prefix |
| 159 | + ')' # suffix |
| 160 | + ); |
| 161 | + |
| 162 | + return array( $cite->render( $this ), $cite ); |
| 163 | + } |
| 164 | + |
| 165 | + |
| 166 | + /** |
| 167 | + * Renders a long inline citation. |
| 168 | + * This citation should omit ending punctuation, and be suitable for |
| 169 | + * inclusion in inline text as part of a larger sentence. |
| 170 | + * @return string |
| 171 | + */ |
| 172 | + public function renderLongInlineCitation( WCCitation $citation, $endPunctuation = '' ) { |
| 173 | + return $this->renderLongCitation( $citation, WCCitationTypeEnum::$inline, ', ', $endPunctuation ); |
| 174 | + } |
| 175 | + |
| 176 | + |
| 177 | + /** |
| 178 | + * Composes a long citation for a bibliography |
| 179 | + * By default, this calls renderLongInlineCitation(). |
| 180 | + * @return string |
| 181 | + */ |
| 182 | + public function renderLongBiblioCitation( WCCitation $citation ) { |
| 183 | + return $this->renderLongCitation( $citation, WCCitationTypeEnum::$biblio, '. ', '.' ); |
| 184 | + } |
| 185 | + |
| 186 | + |
| 187 | + /** |
| 188 | + * Composes a long note citation |
| 189 | + * By default, this calls renderLongInlineCitation(). |
| 190 | + * @return string |
| 191 | + */ |
| 192 | + public function renderLongNoteCitation( WCCitation $citation ) { |
| 193 | + return $this->renderLongCitation( $citation, WCCitationTypeEnum::$note, ', ', '.' ); |
| 194 | + } |
| 195 | + |
| 196 | + |
| 197 | + /** |
| 198 | + * Composes a long author-date citation |
| 199 | + * By default, this calls renderLongInlineCitation(). |
| 200 | + * @return string |
| 201 | + */ |
| 202 | + public function renderLongAuthorDateCitation( WCCitation $citation ) { |
| 203 | + return $this->renderLongCitation( $citation, WCCitationTypeEnum::$authorDate, '. ', '.' ); |
| 204 | + } |
| 205 | + |
| 206 | + |
| 207 | + /** |
| 208 | + * Renders a long inline citation. |
| 209 | + * @return string |
| 210 | + */ |
| 211 | + protected function renderLongCitation( WCCitation $citation, WCCitationTypeEnum $citationType, $segmentSeparator, $endPunctuation ) { |
| 212 | + switch ( $citation->reference->getWorkType()->key ) { |
| 213 | + |
| 214 | + /************************ |
| 215 | + * Books and book-like sources |
| 216 | + ************************/ |
| 217 | + case WCSourceTypeEnum::general: |
| 218 | + |
| 219 | + case WCSourceTypeEnum::book: |
| 220 | + case WCSourceTypeEnum::dictionary: |
| 221 | + case WCSourceTypeEnum::encyclopedia: |
| 222 | + case WCSourceTypeEnum::pamphlet: |
| 223 | + case WCSourceTypeEnum::report: |
| 224 | + switch ( $citationType->key ) { |
| 225 | + case WCCitationTypeEnum::biblio: |
| 226 | + case WCCitationTypeEnum::authorDate: |
| 227 | + $ed2LabelForm = $this->labelFormVerb; |
| 228 | + $ed2Case = $this->capitalizeFirst; |
| 229 | + $nameSort = True; |
| 230 | + break; |
| 231 | + default: |
| 232 | + $ed2LabelForm = $this->labelFormVerbShort; |
| 233 | + $ed2Case = $this->normalCase; |
| 234 | + $nameSort = False; |
| 235 | + } |
| 236 | + |
| 237 | + $editorTranslators1 = new WCLabelSegment( |
| 238 | + new WCNamesSegment( $citation, $this->optional, WCScopeEnum::$work, WCNameTypeEnum::$editorTranslator, $this->first, WCCitationLengthEnum::$long, $nameSort, '', '' ), |
| 239 | + $this->after, $this->labelFormShort, $this->normalCase, $this->contextual |
| 240 | + ); |
| 241 | + $editors1 = new WCLabelSegment( |
| 242 | + new WCNamesSegment( $citation, $this->optional, WCScopeEnum::$work, WCNameTypeEnum::$editor, $this->first, WCCitationLengthEnum::$long, $nameSort, '', '' ), |
| 243 | + $this->after, $this->labelFormShort, $this->normalCase, $this->contextual |
| 244 | + ); |
| 245 | + $translators1 = new WCLabelSegment( |
| 246 | + new WCNamesSegment( $citation, $this->optional, WCScopeEnum::$work, WCNameTypeEnum::$translator, $this->first, WCCitationLengthEnum::$long, $nameSort, '', '' ), |
| 247 | + $this->after, $this->labelFormShort, $this->normalCase, $this->contextual |
| 248 | + ); |
| 249 | + |
| 250 | + $editorTranslators2 = new WCLabelSegment( |
| 251 | + new WCNamesSegment( $citation, $this->optional, WCScopeEnum::$work, WCNameTypeEnum::$editorTranslator, $this->first, WCCitationLengthEnum::$long, False, '', '' ), |
| 252 | + $this->before, $ed2LabelForm, $ed2Case, new WCLabelPluralEnum( WCLabelPluralEnum::contextual ) |
| 253 | + ); |
| 254 | + $editors2 = new WCLabelSegment( |
| 255 | + new WCNamesSegment( $citation, $this->optional, WCScopeEnum::$work, WCNameTypeEnum::$editor, $this->first, WCCitationLengthEnum::$long, False, '', '' ), |
| 256 | + $this->before, $ed2LabelForm, $ed2Case, $this->contextual |
| 257 | + ); |
| 258 | + $translators2 = new WCLabelSegment( |
| 259 | + new WCNamesSegment( $citation, $this->optional, WCScopeEnum::$work, WCNameTypeEnum::$translator, $this->first, WCCitationLengthEnum::$long, False, '', '' ), |
| 260 | + $this->before, $ed2LabelForm, $ed2Case, $this->contextual |
| 261 | + ); |
| 262 | + $date = new WCDateSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$date, new WCDateParts( WCDateParts::year ), new WCDateOrder( WCDateOrder::littleEndian ), new WCDateForm( WCDateForm::numeric ), new WCDateRange( WCDateRange::range ), '', '' ); |
| 263 | + |
| 264 | + $authorsAndTitles = new WCGroupSegment( |
| 265 | + array( |
| 266 | + new WCAlternativeSegment( |
| 267 | + array ( |
| 268 | + new WCNamesSegment( $citation, $this->optional, WCScopeEnum::$work, WCNameTypeEnum::$author, $this->first, WCCitationLengthEnum::$long, $nameSort, '', '' ), |
| 269 | + $editorTranslators1, |
| 270 | + $editors1, |
| 271 | + $translators1, |
| 272 | + ) |
| 273 | + ), |
| 274 | + new WCConditionalSegment( $citationType->key == WCCitationTypeEnum::authorDate, $date ), |
| 275 | + new WCTitleSegment( $citation, $this->mandatory, WCScopeEnum::$work, WCPropertyEnum::$title, new WCTitleFormat( WCTitleFormat::italic ), '', '' ), |
| 276 | + $editorTranslators2, |
| 277 | + $editors2, |
| 278 | + $translators2, |
| 279 | + ), |
| 280 | + $segmentSeparator, # delimiter |
| 281 | + '', # prefix |
| 282 | + '' # suffix |
| 283 | + ); |
| 284 | + if ( $editorTranslators1->exists() ) $editorTranslators2->cancel(); |
| 285 | + if ( $editors1->exists() ) $editors2->cancel(); |
| 286 | + if ( $translators1->exists() ) $translators2->cancel(); |
| 287 | + |
| 288 | + $bookPart = $this->bookPart( $citation, $citationType, $segmentSeparator ); |
| 289 | + |
| 290 | + switch ( $citationType->key ) { |
| 291 | + case WCCitationTypeEnum::biblio: |
| 292 | + case WCCitationTypeEnum::authorDate: |
| 293 | + $cite = new WCGroupSegment( |
| 294 | + array( |
| 295 | + $authorsAndTitles, |
| 296 | + $bookPart, |
| 297 | + ), '. ' |
| 298 | + ); |
| 299 | + break; |
| 300 | + default: # note and inline |
| 301 | + $cite = new WCGroupSegment( |
| 302 | + array( |
| 303 | + $authorsAndTitles, |
| 304 | + $bookPart, |
| 305 | + ), ' ' |
| 306 | + ); |
| 307 | + } |
| 308 | + return array( $cite->render( $this, $endPunctuation ), $cite ); |
| 309 | + |
| 310 | + case WCSourceTypeEnum::periodical: |
| 311 | + case WCSourceTypeEnum::magazine: |
| 312 | + case WCSourceTypeEnum::newspaper: |
| 313 | + case WCSourceTypeEnum::journal: |
| 314 | + |
| 315 | + |
| 316 | + case WCSourceTypeEnum::chapter: |
| 317 | + case WCSourceTypeEnum::entry: |
| 318 | + |
| 319 | + |
| 320 | + /************************ |
| 321 | + * Articles |
| 322 | + ************************/ |
| 323 | + case WCSourceTypeEnum::article: |
| 324 | + $date = new WCDateSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$date, new WCDateParts( WCDateParts::year ), new WCDateOrder( WCDateOrder::littleEndian ), new WCDateForm( WCDateForm::numeric ), new WCDateRange( WCDateRange::range ), '(', ')' ); |
| 325 | + switch ( $citationType->key ) { |
| 326 | + case WCCitationTypeEnum::biblio: |
| 327 | + case WCCitationTypeEnum::authorDate: |
| 328 | + $artPages = new WCLocatorSegment( $citation, $this->important, WCPropertyEnum::$pageRange, '', '' ); |
| 329 | + $nameSort = True; |
| 330 | + break; |
| 331 | + default: # This includes WCCitationTypeEnum::note and inline |
| 332 | + $artPages = new WCLocatorSegment( $citation, $this->important, WCPropertyEnum::$page, '', '' ); |
| 333 | + $nameSort = False; |
| 334 | + } |
| 335 | + switch( $citation->reference->getSeriesType()->key ) { |
| 336 | + case WCSourceTypeEnum::magazine: |
| 337 | + case WCSourceTypeEnum::newspaper: |
| 338 | + case WCSourceTypeEnum::journal: |
| 339 | + $cite = new WCGroupSegment( |
| 340 | + array( |
| 341 | + new WCNamesSegment( $citation, $this->optional, WCScopeEnum::$work, WCNameTypeEnum::$author, $this->first, WCCitationLengthEnum::$long, $nameSort, '', '' ), |
| 342 | + new WCConditionalSegment( $citationType->key == WCCitationTypeEnum::authorDate, new WCDateSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$date, new WCDateParts( WCDateParts::year ), new WCDateOrder( WCDateOrder::littleEndian ), new WCDateForm( WCDateForm::numeric ), new WCDateRange( WCDateRange::range ), '(', ')' ) ), |
| 343 | + new WCTitleSegment( $citation, $this->mandatory, WCScopeEnum::$work, WCPropertyEnum::$title, new WCTitleFormat( WCTitleFormat::quoted ), '', '' ), |
| 344 | + new WCGroupSegment( |
| 345 | + array( |
| 346 | + new WCGroupSegment( |
| 347 | + array( |
| 348 | + new WCTitleSegment( $citation, $this->mandatory, WCScopeEnum::$series, WCPropertyEnum::$title, new WCTitleFormat( WCTitleFormat::italic ), '', '' ), |
| 349 | + new WCGroupSegment( |
| 350 | + array( |
| 351 | + new WCLocatorSegment( $citation, $this->important, WCPropertyEnum::$volume, '', '' ), |
| 352 | + new WCLabelSegment( |
| 353 | + new WCLocatorSegment( $citation, $this->optional, WCPropertyEnum::$issue, '', '' ), |
| 354 | + $this->before, $this->labelFormShort, $this->normalCase, $this->contextual |
| 355 | + ), |
| 356 | + ), ', ', '', '' |
| 357 | + ), |
| 358 | + new WCConditionalSegment( $citationType->key != WCCitationTypeEnum::authorDate, new WCDateSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$date, new WCDateParts( WCDateParts::year ), new WCDateOrder( WCDateOrder::littleEndian ), new WCDateForm( WCDateForm::numeric ), new WCDateRange( WCDateRange::range ), '(', ')' ) ), |
| 359 | + ), ' ', '', '' |
| 360 | + ), |
| 361 | + $artPages, |
| 362 | + ), ': ', '', '' |
| 363 | + ) |
| 364 | + ), |
| 365 | + $segmentSeparator, # delimiter |
| 366 | + '', # prefix |
| 367 | + '' # suffix |
| 368 | + ); |
| 369 | + return array( $cite->render( $this, $endPunctuation ), $cite ); |
| 370 | + default: #includes magazine, newspaper, and periodical |
| 371 | + $cite = new WCGroupSegment( |
| 372 | + array( |
| 373 | + new WCNamesSegment( $citation, $this->optional, WCScopeEnum::$work, WCNameTypeEnum::$author, $this->first, WCCitationLengthEnum::$long, $nameSort, '', '' ), |
| 374 | + new WCConditionalSegment( $citationType->key == WCCitationTypeEnum::authorDate, new WCDateSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$date, new WCDateParts( WCDateParts::year ), new WCDateOrder( WCDateOrder::littleEndian ), new WCDateForm( WCDateForm::numeric ), new WCDateRange( WCDateRange::range ), '(', ')' ) ), |
| 375 | + new WCTitleSegment( $citation, $this->mandatory, WCScopeEnum::$work, WCPropertyEnum::$title, new WCTitleFormat( WCTitleFormat::quoted ), '', '' ), |
| 376 | + new WCGroupSegment( |
| 377 | + array( |
| 378 | + new WCGroupSegment( |
| 379 | + array( |
| 380 | + new WCTitleSegment( $citation, $this->mandatory, WCScopeEnum::$series, WCPropertyEnum::$title, new WCTitleFormat( WCTitleFormat::italic ), '', '' ), |
| 381 | + new WCGroupSegment( |
| 382 | + array( |
| 383 | + new WCTextSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$place, '(', ')' ), |
| 384 | + new WCDateSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$date, new WCDateParts( WCDateParts::year ), new WCDateOrder( WCDateOrder::littleEndian ), new WCDateForm( WCDateForm::numeric ), new WCDateRange( WCDateRange::range ), '', '' ), # this date should be a full date, or month and day if author-date system. |
| 385 | + ), ' ', '', '' |
| 386 | + ), |
| 387 | + new WCConditionalSegment( $citationType->key != WCCitationTypeEnum::authorDate, new WCDateSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$date, new WCDateParts( WCDateParts::year ), new WCDateOrder( WCDateOrder::littleEndian ), new WCDateForm( WCDateForm::numeric ), new WCDateRange( WCDateRange::range ), '(', ')' ) ), |
| 388 | + ), ' ', '', '' |
| 389 | + ), |
| 390 | + $artPages, |
| 391 | + ), ': ', '', '' |
| 392 | + ) |
| 393 | + ), |
| 394 | + $segmentSeparator, # delimiter |
| 395 | + '', # prefix |
| 396 | + '' # suffix |
| 397 | + ); |
| 398 | + return array( $cite->render( $this, $endPunctuation ), $cite ); |
| 399 | + } |
| 400 | + |
| 401 | +/* case WCTypeEnum::review: |
| 402 | + case WCTypeEnum::paper: |
| 403 | + case WCTypeEnum::manuscript: |
| 404 | + case WCTypeEnum::musicalScore: |
| 405 | + case WCTypeEnum::conferencePaper: |
| 406 | + case WCTypeEnum::thesis: |
| 407 | + case WCTypeEnum::poem: |
| 408 | + case WCTypeEnum::song: |
| 409 | + case WCTypeEnum::enactment: |
| 410 | + case WCTypeEnum::bill: |
| 411 | + case WCTypeEnum::statute: |
| 412 | + case WCTypeEnum::treaty: |
| 413 | + case WCTypeEnum::rule: |
| 414 | + case WCTypeEnum::regulation: |
| 415 | + case WCTypeEnum::legalDocument: |
| 416 | + case WCTypeEnum::patent: |
| 417 | + case WCTypeEnum::deed: |
| 418 | + case WCTypeEnum::governmentGrant: |
| 419 | + case WCTypeEnum::filing: |
| 420 | + case WCTypeEnum::patentApplication: |
| 421 | + case WCTypeEnum::regulatoryFiling: |
| 422 | + case WCTypeEnum::litigation: |
| 423 | + case WCTypeEnum::legalOpinion: |
| 424 | + case WCTypeEnum::legalCase: |
| 425 | + case WCTypeEnum::graphic: |
| 426 | + case WCTypeEnum::photograph: |
| 427 | + case WCTypeEnum::map: |
| 428 | + case WCTypeEnum::statement: |
| 429 | + case WCTypeEnum::pressRelease: |
| 430 | + case WCTypeEnum::interview: |
| 431 | + case WCTypeEnum::speech: |
| 432 | + case WCTypeEnum::personalCommunication: |
| 433 | + case WCTypeEnum::internetResource: |
| 434 | + case WCTypeEnum::webpage: |
| 435 | + case WCTypeEnum::post: |
| 436 | + case WCTypeEnum::production: |
| 437 | + case WCTypeEnum::motionPicture: |
| 438 | + case WCTypeEnum::recording: |
| 439 | + case WCTypeEnum::play: |
| 440 | + case WCTypeEnum::broadcast: |
| 441 | + case WCTypeEnum::televisionBroadcast: |
| 442 | + case WCTypeEnum::radioBroadcast: |
| 443 | + case WCTypeEnum::internetBroadcast: |
| 444 | + case WCTypeEnum::object: |
| 445 | + case WCTypeEnum::star: |
| 446 | + case WCTypeEnum::gravestone: |
| 447 | + case WCTypeEnum::monument: |
| 448 | + case WCTypeEnum::realProperty: |
| 449 | +*/ |
| 450 | + } |
| 451 | + } |
| 452 | + |
| 453 | + |
| 454 | + protected function bookPart( WCCitation $citation, WCCitationTypeEnum $citationType, $segmentSeparator ) { |
| 455 | + # publisher-place: publisher |
| 456 | + $placePublisher = new WCGroupSegment( |
| 457 | + array( |
| 458 | + new WCTextSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$place ), |
| 459 | + new WCNamesSegment( $citation, $this->important, WCScopeEnum::$work, WCNameTypeEnum::$publisher, $this->first, WCCitationLengthEnum::$long, False ), |
| 460 | + ), ': ' |
| 461 | + ); |
| 462 | + $year = new WCDateSegment( $citation, $this->important, WCScopeEnum::$work, WCPropertyEnum::$date, new WCDateParts( WCDateParts::year ), new WCDateOrder( WCDateOrder::littleEndian ), new WCDateForm( WCDateForm::numeric ), new WCDateRange( WCDateRange::range ) ); |
| 463 | + |
| 464 | + switch ( $citationType->key ) { |
| 465 | + case WCCitationTypeEnum::biblio: # publisher-place: publisher, year. |
| 466 | + $placePublisherDate = new WCGroupSegment( |
| 467 | + array( |
| 468 | + $placePublisher, |
| 469 | + $year, |
| 470 | + ), ', ' |
| 471 | + ); |
| 472 | + break; |
| 473 | + case WCCitationTypeEnum::authorDate: # publisher-place: publisher |
| 474 | + $placePublisherDate = $placePublisher; |
| 475 | + break; |
| 476 | + default: # note, inline -- (publisher-place: publisher, year), page |
| 477 | + $placePublisherDate = new WCGroupSegment( |
| 478 | + array( |
| 479 | + new WCGroupSegment( |
| 480 | + array( |
| 481 | + $placePublisher, |
| 482 | + $year, |
| 483 | + ), ', ', '(', ')' |
| 484 | + ), |
| 485 | + new WCLocatorSegment( $citation, $this->important, WCPropertyEnum::$page ), |
| 486 | + ), ', ' |
| 487 | + ); |
| 488 | + } |
| 489 | + return new WCGroupSegment( |
| 490 | + array( |
| 491 | + $placePublisherDate, |
| 492 | + $this->urlPart( $citation, $citationType, $segmentSeparator ), |
| 493 | + ), $segmentSeparator |
| 494 | + ); |
| 495 | + } |
| 496 | + |
| 497 | + |
| 498 | + protected function urlPart( WCCitation $citation, WCCitationTypeEnum $citationType, $segmentSeparator ) { |
| 499 | + $url = new WCTextSegment( $citation, $this->optional, WCScopeEnum::$work, WCPropertyEnum::$url ); |
| 500 | + return new WCConditionalSegment( |
| 501 | + $url->exists(), |
| 502 | + new WCGroupSegment( |
| 503 | + array( |
| 504 | + new WCDateSegment( $citation, $this->optional, WCScopeEnum::$work, WCPropertyEnum::$accessed, new WCDateParts( WCDateParts::yearMonthDay ), new WCDateOrder( WCDateOrder::middleEndian ), new WCDateForm( WCDateForm::long ), new WCDateRange( WCDateRange::range ) ), |
| 505 | + $url, |
| 506 | + ), $segmentSeparator |
| 507 | + ) |
| 508 | + ); |
| 509 | + } |
| 510 | + |
| 511 | + |
| 512 | +} |
Property changes on: trunk/extensions/WikiCitation/styles/WCChicagoStyle.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 513 | + native |
Property changes on: trunk/extensions/WikiCitation/styles |
___________________________________________________________________ |
Added: bugtraq:number |
2 | 514 | + true |
Index: trunk/extensions/WikiCitation/WikiCitation.php |
— | — | @@ -0,0 +1,171 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * The extension implements a parser function to create and use citations |
| 7 | + * in various styling standards, such as the Chicago Manual of Style, MLA, APA, |
| 8 | + * Bluebook, etc. |
| 9 | + * A citation has the following Backus-Naur form: |
| 10 | + * @code |
| 11 | + * <citation> ::= "{{#cite:" <data> "}}" |
| 12 | + * <data> ::= <flags> "|" <parameters> |
| 13 | + * | <parameters> |
| 14 | + * <flags> ::= <flag> |
| 15 | + * | <flag> "|" <flags> |
| 16 | + * <parameters> ::= <parameter> |
| 17 | + * | <parameter> "|" <parameters> |
| 18 | + * @endcode |
| 19 | + * The extension also implements the following tag extension (in English): |
| 20 | + * @code |
| 21 | + * <biblio style="..." type="..."></biblio> |
| 22 | + * @endcode |
| 23 | + * where the style and type attributes define the citation style (e.g. |
| 24 | + * Chicago Manual of style) and type (e.g., author-date). Citations within |
| 25 | + * this biblio tag will be sorted alphabetically. |
| 26 | + * For more detailed documentation, see the extension's MediaWiki entry at |
| 27 | + * http://www.mediawiki.org/wiki/Extension:WikiCitation |
| 28 | + * |
| 29 | + * @defgroup WikiCitation |
| 30 | + * @author 'COGDEN' and others |
| 31 | + * @copyright Copyright (c) 2011 by authors |
| 32 | + * @license http://www.gnu.org/copyright/gpl.html |
| 33 | + * This program is free software; you can redistribute it and/or modify |
| 34 | + * it under the terms of the GNU General Public License as published by |
| 35 | + * the Free Software Foundation, either version 2 of the License, or |
| 36 | + * (at your option) any later version. |
| 37 | + * This program is distributed in the hope that it will be useful, |
| 38 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 39 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 40 | + * GNU General Public License for more details. |
| 41 | + * You should have received a copy of the GNU General Public License along |
| 42 | + * with this program; if not, write to the Free Software Foundation, Inc., |
| 43 | + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
| 44 | + * See http://www.gnu.org/copyright/gpl.html |
| 45 | + */ |
| 46 | + |
| 47 | +/** |
| 48 | + * Setup file for WikiCitation extension. |
| 49 | + * |
| 50 | + * @file |
| 51 | + */ |
| 52 | + |
| 53 | + |
| 54 | +if ( !defined( 'MEDIAWIKI' ) ) { |
| 55 | + echo( "Not a valid entry point.\n" ); |
| 56 | + die( 1 ); |
| 57 | +} |
| 58 | + |
| 59 | + |
| 60 | +$wgExtensionCredits[ 'parserhook' ][] = array( |
| 61 | + 'path' => __FILE__, |
| 62 | + 'name' => 'WikiCitation', |
| 63 | + 'author' => array( 'COGDEN' ), |
| 64 | + 'url' => 'http://www.mediawiki.org/wiki/Extension:WikiCitation', |
| 65 | + 'descriptionmsg' => 'wc-description', |
| 66 | + 'version' => '0.8.1' |
| 67 | +); |
| 68 | + |
| 69 | + |
| 70 | +/** |
| 71 | + * Global settings |
| 72 | + */ |
| 73 | +$wikiCitationValidateArguments = False; |
| 74 | + |
| 75 | +$mDir = dirname(__FILE__); |
| 76 | + |
| 77 | +/** |
| 78 | + * Array for defining allowable referencing styles, and setting a default. |
| 79 | + * |
| 80 | + * Array of recognized children of WCCitation, keyed to magic words used to |
| 81 | + * invoke that style. For example, the magic word 'wcChicago' |
| 82 | + * ('Chicago' in English) is keyed to the class 'WCChicagoCitation' |
| 83 | + * |
| 84 | + * To disallow particular styles, comment them out or remove them from this |
| 85 | + * list. |
| 86 | + * @var |
| 87 | + */ |
| 88 | +$wgWCCitationStyles = array( |
| 89 | + 'wc_default' => 'WCChicagoStyle', # default style is defined here |
| 90 | + 'wc_Chicago' => 'WCChicagoStyle', |
| 91 | + 'wc_Bluebook' => 'WCBluebookStyle', |
| 92 | +); |
| 93 | + |
| 94 | +# Styles |
| 95 | +$wgAutoloadClasses['WCChicagoStyle'] = $mDir . '/styles/WCChicagoStyle.php'; |
| 96 | +$wgAutoloadClasses['WCBluebookStyle'] = $mDir . '/styles/WCBluebookStyle.php'; |
| 97 | + |
| 98 | + |
| 99 | +/** |
| 100 | + * Localization files |
| 101 | + */ |
| 102 | +$wgExtensionMessagesFiles['WikiCitation'] = $mDir . '/WikiCitation.i18n.php'; |
| 103 | +$wgExtensionMessagesFiles['WikiCitationMagic'] = $mDir . '/WikiCitation.i18n.magic.php'; |
| 104 | + |
| 105 | +/** |
| 106 | + * Autoload classes |
| 107 | + */ |
| 108 | +# main directory |
| 109 | +$wgAutoloadClasses['WikiCitation'] = $mDir . '/WikiCitation.body.php'; |
| 110 | + |
| 111 | +# includes |
| 112 | +$wgAutoloadClasses['WCArgumentReader'] = $mDir . '/includes/WCArgumentReader.php'; |
| 113 | +$wgAutoloadClasses['WCArticle'] = $mDir . '/includes/WCArticle.php'; |
| 114 | +$wgAutoloadClasses['WCBibliography'] = $mDir . '/includes/WCBibliography.php'; |
| 115 | +$wgAutoloadClasses['WCCitation'] = $mDir . '/includes/WCCitation.php'; |
| 116 | + $wgAutoloadClasses['WCCitationPosition'] = $mDir . '/includes/WCCitation.php'; |
| 117 | +$wgAutoloadClasses['WCEnum'] = $mDir . '/includes/WCEnum.php'; |
| 118 | +$wgAutoloadClasses['WCException'] = $mDir . '/includes/WCException.php'; |
| 119 | +$wgAutoloadClasses['WCNote'] = $mDir . '/includes/WCNote.php'; |
| 120 | +$wgAutoloadClasses['WCReference'] = $mDir . '/includes/WCReference.php'; |
| 121 | +$wgAutoloadClasses['WCReferenceStore'] = $mDir . '/includes/WCReferenceStore.php'; |
| 122 | +$wgAutoloadClasses['WCSection'] = $mDir . '/includes/WCSection.php'; |
| 123 | +$wgAutoloadClasses['WCStyle'] = $mDir . '/includes/WCStyle.php'; |
| 124 | + |
| 125 | +# data |
| 126 | +$wgAutoloadClasses['WCData'] = $mDir . '/includes/data/WCData.php'; |
| 127 | +$wgAutoloadClasses['WCDate'] = $mDir . '/includes/data/WCDate.php'; |
| 128 | +$wgAutoloadClasses['WCLocator'] = $mDir . '/includes/data/WCLocator.php'; |
| 129 | +$wgAutoloadClasses['WCName'] = $mDir . '/includes/data/WCName.php'; |
| 130 | +$wgAutoloadClasses['WCNames'] = $mDir . '/includes/data/WCNames.php'; |
| 131 | +$wgAutoloadClasses['WCTypeData'] = $mDir . '/includes/data/WCTypeData.php'; |
| 132 | +$wgAutoloadClasses['WCText'] = $mDir . '/includes/data/WCText.php'; |
| 133 | +$wgAutoloadClasses['WCTitle'] = $mDir . '/includes/data/WCTitle.php'; |
| 134 | +$wgAutoloadClasses['WCTitleFormat'] = $mDir . '/includes/data/WCTitle.php'; |
| 135 | + |
| 136 | +# parameters |
| 137 | +$wgAutoloadClasses['WCAttributeEnum'] = $mDir . '/includes/parameters/WCAttributeEnum.php'; |
| 138 | +$wgAutoloadClasses['WCCitationLengthEnum'] = $mDir . '/includes/parameters/WCCitationLengthEnum.php'; |
| 139 | +$wgAutoloadClasses['WCCitationTypeEnum'] = $mDir . '/includes/parameters/WCCitationTypeEnum.php'; |
| 140 | +$wgAutoloadClasses['WCDateTermsEnum'] = $mDir . '/includes/parameters/WCDateTermsEnum.php'; |
| 141 | +$wgAutoloadClasses['WCNamePartEnum'] = $mDir . '/includes/parameters/WCNamePartEnum.php'; |
| 142 | +$wgAutoloadClasses['WCNameTypeEnum'] = $mDir . '/includes/parameters/WCNameTypeEnum.php'; |
| 143 | +$wgAutoloadClasses['WCParameterEnum'] = $mDir . '/includes/parameters/WCParameterEnum.php'; |
| 144 | +$wgAutoloadClasses['WCPropertyEnum'] = $mDir . '/includes/parameters/WCPropertyEnum.php'; |
| 145 | +$wgAutoloadClasses['WCScopeEnum'] = $mDir . '/includes/parameters/WCScopeEnum.php'; |
| 146 | +$wgAutoloadClasses['WCSourceTypeEnum'] = $mDir . '/includes/parameters/WCSourceTypeEnum.php'; |
| 147 | + |
| 148 | +# segments |
| 149 | +$wgAutoloadClasses['WCAlternativeSegment'] = $mDir . '/includes/segments/WCAlternativeSegment.php'; |
| 150 | +$wgAutoloadClasses['WCConditionalSegment'] = $mDir . '/includes/segments/WCConditionalSegment.php'; |
| 151 | +$wgAutoloadClasses['WCDataSegment'] = $mDir . '/includes/segments/WCDataSegment.php'; |
| 152 | +$wgAutoloadClasses['WCDateSegment'] = $mDir . '/includes/segments/WCDateSegment.php'; |
| 153 | +$wgAutoloadClasses['WCGroupSegment'] = $mDir . '/includes/segments/WCGroupSegment.php'; |
| 154 | +$wgAutoloadClasses['WCLabelFormEnum'] = $mDir . '/includes/segments/WCLabelSegment.php'; |
| 155 | +$wgAutoloadClasses['WCLabelSegment'] = $mDir . '/includes/segments/WCLabelSegment.php'; |
| 156 | +$wgAutoloadClasses['WCLiteralSegment'] = $mDir . '/includes/segments/WCLiteralSegment.php'; |
| 157 | +$wgAutoloadClasses['WCLocatorSegment'] = $mDir . '/includes/segments/WCLocatorSegment.php'; |
| 158 | +$wgAutoloadClasses['WCNamesSegment'] = $mDir . '/includes/segments/WCNamesSegment.php'; |
| 159 | +$wgAutoloadClasses['WCSegment'] = $mDir . '/includes/segments/WCSegment.php'; |
| 160 | +$wgAutoloadClasses['WCTextSegment'] = $mDir . '/includes/segments/WCTextSegment.php'; |
| 161 | +$wgAutoloadClasses['WCTitleSegment'] = $mDir . '/includes/segments/WCTitleSegment.php'; |
| 162 | +$wgAutoloadClasses['WCWrapperSegment'] = $mDir . '/includes/segments/WCWrapperSegment.php'; |
| 163 | + |
| 164 | +# Set up parser hooks |
| 165 | +$wgHooks[ 'ParserFirstCallInit' ][] = 'WikiCitation::onParserFirstCallInit'; |
| 166 | +$wgHooks[ 'ParserClearState' ][] = 'WikiCitation::onParserClearState'; |
| 167 | +$wgHooks[ 'ParserBeforeTidy' ][] = 'WikiCitation::onParserBeforeTidy'; |
| 168 | + |
| 169 | +# Location of the CSS style sheet for this extension |
| 170 | +$wgWCStyleSheet = $wgScriptPath . '/extensions/WikiCitation/WikiCitation.css'; |
| 171 | + |
| 172 | +#$wgParserTestFiles[] = $mDir . "/WikiCitationTests.txt"; |
Property changes on: trunk/extensions/WikiCitation/WikiCitation.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 173 | + native |
Index: trunk/extensions/WikiCitation/WikiCitation.css |
— | — | @@ -0,0 +1,93 @@ |
| 2 | +/** |
| 3 | + * CSS for the WikiCitation extension. |
| 4 | + * |
| 5 | + * @ingroup WikiCitation |
| 6 | + * @file |
| 7 | + */ |
| 8 | + |
| 9 | +/** |
| 10 | + * CSS definitions for citations. |
| 11 | + * these terms are defined as constants in the class WCStyle |
| 12 | + */ |
| 13 | + |
| 14 | +.citation .error, |
| 15 | +.citation.error { |
| 16 | + font-size: smaller; |
| 17 | + font-weight: bold; |
| 18 | + color: red; |
| 19 | +} |
| 20 | + |
| 21 | +.citation cite, |
| 22 | +.citation cite.quoted { |
| 23 | + font-style: normal; |
| 24 | +} |
| 25 | + |
| 26 | +.citation cite.italic { |
| 27 | + font-style: italic; |
| 28 | +} |
| 29 | + |
| 30 | +.citation .name { |
| 31 | +} |
| 32 | + |
| 33 | +.citation .name .surname { |
| 34 | +} |
| 35 | + |
| 36 | +.citation .name .sortorder { |
| 37 | +} |
| 38 | + |
| 39 | +/* CSS3. Breaks long urls, etc., rather than overflowing box */ |
| 40 | +.citation { |
| 41 | + word-wrap: break-word; |
| 42 | +} |
| 43 | + |
| 44 | +/* Hides test that should be shown in interactive media, but not in print */ |
| 45 | +@media screen, handheld { |
| 46 | + .citation *.printonly { |
| 47 | + display: none; |
| 48 | + } |
| 49 | +} |
| 50 | + |
| 51 | +sup.notesuperscript { |
| 52 | + vertical-align: super; |
| 53 | + font-size: .83em; |
| 54 | + white-space: nowrap; |
| 55 | + font-weight: normal; |
| 56 | + font-style: normal; |
| 57 | +} |
| 58 | + |
| 59 | +sup.notesuperscript a:visited { |
| 60 | + color: inherit; |
| 61 | +} |
| 62 | + |
| 63 | +sup.notesuperscript a:hover, |
| 64 | +sup.notesuperscript:target { /* target is CSS3 */ |
| 65 | + background-color: #DEF; |
| 66 | + text-decoration: none; |
| 67 | +} |
| 68 | + |
| 69 | +ol.endnotes { |
| 70 | + list-style-type: none; |
| 71 | + padding-left: 0em; |
| 72 | + margin-left: 0em; |
| 73 | +} |
| 74 | + |
| 75 | +ol.endnotes li { |
| 76 | + padding-left: 0em; |
| 77 | + margin-left: 0em; |
| 78 | + text-indent: 2em; |
| 79 | +} |
| 80 | + |
| 81 | +/* CSS3. Highlight clicked reference in blue to help navigation */ |
| 82 | +ol.endnotes li:target { |
| 83 | + background-color: #DEF; |
| 84 | +} |
| 85 | + |
| 86 | +ol.endnotes li a.notenumber:visited { |
| 87 | + color: inherit; |
| 88 | +} |
| 89 | + |
| 90 | +/* Hanging indent for bibliography entries */ |
| 91 | +ul.bibliography li { |
| 92 | + text-indent: -2em; |
| 93 | + padding-left: 2em; |
| 94 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/WikiCitation/WikiCitation.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 95 | + native |
Index: trunk/extensions/WikiCitation/includes/WCStyle.php |
— | — | @@ -0,0 +1,506 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | +class WCSegmentImportance extends WCEnum { |
| 11 | + const mandatory = 0; # The segment must be present, and if not, will show a visible blank. |
| 12 | + const important = 1; # The segment should be present, but will be omitted if it cannot be inferred. |
| 13 | + const optional = 2; # The segment is optional. If not present, it will not be inferred. |
| 14 | + const __default = self::mandatory; |
| 15 | +} |
| 16 | + |
| 17 | + |
| 18 | +class WCTextCaseEnum extends WCEnum { |
| 19 | + const normal = 0; |
| 20 | + const lowercase = 1; |
| 21 | + const uppercase = 2; |
| 22 | + const capitalizeFirst = 3; |
| 23 | + const capitalizeAll = 4; |
| 24 | + const title = 5; |
| 25 | + const __default = self::normal; |
| 26 | +} |
| 27 | + |
| 28 | + |
| 29 | +/** |
| 30 | + * An abstract class providing some of the functionality of its |
| 31 | + * child referencing styles. |
| 32 | + * |
| 33 | + * @abstract |
| 34 | + */ |
| 35 | +abstract class WCStyle { |
| 36 | + |
| 37 | + /** |
| 38 | + * Constants |
| 39 | + */ |
| 40 | + const citationHTML = 'citation'; # HTML class for a citation as a whole |
| 41 | + const errorHTML = 'error'; # class for validation errors in citation template |
| 42 | + const italicTitleHTML = 'italic'; # class for italic titles |
| 43 | + const quotedTitleHTML = 'quoted'; # class for quoted titles |
| 44 | + const nameHTML = 'name'; # class for names |
| 45 | + const surnameHTML = 'surname'; # class for surnames |
| 46 | + const surnameSortOrderHTML = 'sortorder'; # class for surnames in sort order |
| 47 | + |
| 48 | + /** |
| 49 | + * General style variables. |
| 50 | + */ |
| 51 | + # HTML class (must be redefined by children) |
| 52 | + public $styleHTML = ''; # class representing the citation style--children should redefine |
| 53 | + |
| 54 | + # citation separators and punctuation |
| 55 | + public $segmentMissing; # blank to indicate missing segment |
| 56 | + public $rangeDelimiter; # delimiter for ranges |
| 57 | + |
| 58 | + # Labels |
| 59 | + public $nameLabels, $propertyLabels, $circaLabels; |
| 60 | + |
| 61 | + /** |
| 62 | + * Title style variables. |
| 63 | + */ |
| 64 | + # switch |
| 65 | + public $punctuationInQuotes = False; # whether punctuation such as commas or periods is inside quotes, or outside |
| 66 | + public $replaceAmpersands = False; # whether ampersand ("&") is replaced with "and" |
| 67 | + public $eraWithoutPunctuation = False; # whether the era is written as AD, BC, BCE, etc. rather than A.D., etc. |
| 68 | + public $eraNoSpace = False; # whether there is a space between the year and the era |
| 69 | + public $eraBeforeYear = False; # whether the era appears before or after the year |
| 70 | + |
| 71 | + |
| 72 | + # citation separators and punctuation |
| 73 | + public $iExQuote; # initial exterior quote symbol |
| 74 | + public $fExQuote; # final exterior quote symbol |
| 75 | + public $iInQuote; # initial interior quote symbol |
| 76 | + public $fInQuote; # final interior quote symbol |
| 77 | + |
| 78 | + /** |
| 79 | + * Date style variables. |
| 80 | + */ |
| 81 | + # flags |
| 82 | + public $stripMonthPeriods; # boolean; e.g. Jan or Feb |
| 83 | + |
| 84 | + # citation text, separators, and punctuation |
| 85 | + public $ad, $adNoPunct; # AD |
| 86 | + public $ce, $ceNoPunct; # CE |
| 87 | + public $bc, $bcNoPunct; # BC |
| 88 | + public $bce, $bceNoPunct; # BCE |
| 89 | + |
| 90 | + # literal text |
| 91 | + public $personalCommunication; |
| 92 | + |
| 93 | + /** |
| 94 | + * Name style variables |
| 95 | + */ |
| 96 | + # name formatting flag |
| 97 | + public $demoteNonDroppingParticle; |
| 98 | + |
| 99 | + # formatting strings: |
| 100 | + public $nameWhitespace; # whitespace between name name parts |
| 101 | + public $sortOrderDelimiter; # punctuation between name name parts in name-sort mode |
| 102 | + public $missingName; # blank to represent a missing name |
| 103 | + public $sortOrderSurnameDelimiter; # punctuation after surname in name-sort mode |
| 104 | + public $nameSuffixDelimiter; # delimiter before name suffix |
| 105 | + |
| 106 | + /** |
| 107 | + * Names style variables |
| 108 | + */ |
| 109 | + # name formatting flags |
| 110 | + public $etAlMin; # when names exceeds this value, 'et al.' is used... |
| 111 | + public $etAlUseFirst; # ...and the number of names is dropped to this number. |
| 112 | + public $etAlSubsequentMin; # same as $etAlMin, except applies in later cites referencing earlier cites |
| 113 | + public $etAlSubsequentUseFirst; # same as $etAlUseFirst, except applies in later cites referencing earlier cites |
| 114 | + |
| 115 | + # name formatting delimiters and punctuation: |
| 116 | + public $namesDelimiter; # the normal punctuation between names |
| 117 | + public $etAlDelimiter; # the punctuation before "et al." or equivalent |
| 118 | + public $and2; # the delimiter between two names if there are only two |
| 119 | + public $and3; # the last delimiter for three or more names |
| 120 | + public $etAl; # "and others" |
| 121 | + |
| 122 | + /** |
| 123 | + * Convenience variables |
| 124 | + */ |
| 125 | + protected $mandatory, $important, $optional; |
| 126 | + protected $normalCase, $lowercase, $uppercase, $capitalizeFirst, $capitalizeAll, $titleCase; |
| 127 | + protected $labelFormNone, $labelFormLong, $labelFormVerb, $labelFormShort, $labelFormVerbShort, $labelFormSymbol; |
| 128 | + protected $singular, $plural; |
| 129 | + protected $contextual, $alwaysPlural, $neverPlural; |
| 130 | + protected $before, $after; |
| 131 | + |
| 132 | + |
| 133 | + /** |
| 134 | + * Constructor. |
| 135 | + */ |
| 136 | + public function __construct() { |
| 137 | + |
| 138 | + # Convenience variables |
| 139 | + $this->mandatory = new WCSegmentImportance( WCSegmentImportance::mandatory ); |
| 140 | + $this->important = new WCSegmentImportance( WCSegmentImportance::important ); |
| 141 | + $this->optional = new WCSegmentImportance( WCSegmentImportance::optional ); |
| 142 | + $this->first = new WCCitationPosition( WCCitationPosition::first ); |
| 143 | + $this->subsequent = new WCCitationPosition( WCCitationPosition::subsequent ); |
| 144 | + $this->normalCase = new WCTextCaseEnum( WCTextCaseEnum::normal ); |
| 145 | + $this->lowercase = new WCTextCaseEnum( WCTextCaseEnum::lowercase ); |
| 146 | + $this->uppercase = new WCTextCaseEnum( WCTextCaseEnum::uppercase ); |
| 147 | + $this->capitalizeFirst = new WCTextCaseEnum( WCTextCaseEnum::capitalizeFirst ); |
| 148 | + $this->capitalizeAll = new WCTextCaseEnum( WCTextCaseEnum::capitalizeAll ); |
| 149 | + $this->titleCase = new WCTextCaseEnum( WCTextCaseEnum::title ); |
| 150 | + $this->labelFormNone = new WCLabelFormEnum( WCLabelFormEnum::none ); |
| 151 | + $this->labelFormLong = new WCLabelFormEnum( WCLabelFormEnum::long ); |
| 152 | + $this->labelFormVerb = new WCLabelFormEnum( WCLabelFormEnum::verb ); |
| 153 | + $this->labelFormShort = new WCLabelFormEnum( WCLabelFormEnum::short ); |
| 154 | + $this->labelFormVerbShort = new WCLabelFormEnum( WCLabelFormEnum::verbShort ); |
| 155 | + $this->labelFormSymbol = new WCLabelFormEnum( WCLabelFormEnum::symbol ); |
| 156 | + $this->singular = new WCPluralEnum( WCPluralEnum::singular ); |
| 157 | + $this->plural = new WCPluralEnum( WCPluralEnum::plural ); |
| 158 | + $this->contextual = new WCLabelPluralEnum( WCLabelPluralEnum::contextual ); |
| 159 | + $this->alwaysPlural = new WCLabelPluralEnum( WCLabelPluralEnum::always ); |
| 160 | + $this->neverPlural = new WCLabelPluralEnum( WCLabelPluralEnum::never ); |
| 161 | + $this->before = new WCRelativePositionEnum( WCRelativePositionEnum::before ); |
| 162 | + $this->after = new WCRelativePositionEnum( WCRelativePositionEnum::after ); |
| 163 | + |
| 164 | + |
| 165 | + # General style variables. |
| 166 | + $this->biblioSegSep = wfMsg( 'wc-biblio-segment-separator' ); |
| 167 | + $this->noteSegSep = wfMsg( 'wc-note-segment-separator' ); |
| 168 | + $this->inlineSegSep = wfMsg( 'wc-inline-segment-separator' ); |
| 169 | + $this->biblioEndPunct = wfMsg( 'wc-biblio-segment-end-punct' ); |
| 170 | + $this->noteEndPunct = wfMsg( 'wc-note-segment-end-punct' ); |
| 171 | + $this->segmentMissing = wfMsg( 'wc-segment-missing' ); |
| 172 | + $this->rangeDelimiter = wfMsg( 'wc-range-delimiter' ); |
| 173 | + |
| 174 | + # Labels. |
| 175 | + $this->nameLabels = array(); |
| 176 | + foreach( array( |
| 177 | + WCNameTypeEnum::author => 'author', |
| 178 | + WCNameTypeEnum::publisher => 'publisher', |
| 179 | + WCNameTypeEnum::editorTranslator => 'editor-translator', |
| 180 | + WCNameTypeEnum::editor => 'editor', |
| 181 | + WCNameTypeEnum::translator => 'translator', |
| 182 | + WCNameTypeEnum::interviewer => 'interviewer', |
| 183 | + WCNameTypeEnum::recipient => 'recipient', |
| 184 | + WCNameTypeEnum::composer => 'composer', |
| 185 | + ) as $key => $name ) { |
| 186 | + foreach ( array( |
| 187 | + WCLabelFormEnum::long => 'long', |
| 188 | + WCLabelFormEnum::verb => 'verb', |
| 189 | + WCLabelFormEnum::short => 'short', |
| 190 | + WCLabelFormEnum::verbShort => 'verb-short', |
| 191 | + WCLabelFormEnum::symbol => 'symbol', |
| 192 | + ) as $form => $formText ) { |
| 193 | + foreach ( array( |
| 194 | + WCPluralEnum::singular => 'singular', |
| 195 | + WCPluralEnum::plural => 'plural', |
| 196 | + ) as $num => $numText ) { |
| 197 | + $this->nameLabels[ $key ][ $form ][ $num ] = wfMsg( 'wc-' . $name . '-' . $formText . '-' . $numText ); |
| 198 | + } |
| 199 | + } |
| 200 | + } |
| 201 | + $this->propertyLabels = array(); |
| 202 | + foreach( array( |
| 203 | + WCPropertyEnum::page => 'page', |
| 204 | + WCPropertyEnum::section => 'section', |
| 205 | + WCPropertyEnum::paragraph => 'paragraph', |
| 206 | + WCPropertyEnum::volume => 'volume', |
| 207 | + WCPropertyEnum::issue => 'issue', |
| 208 | + ) as $key => $name ) { |
| 209 | + foreach ( array( |
| 210 | + WCLabelFormEnum::long => 'long', |
| 211 | + WCLabelFormEnum::verb => 'verb', |
| 212 | + WCLabelFormEnum::short => 'short', |
| 213 | + WCLabelFormEnum::verbShort => 'verb-short', |
| 214 | + WCLabelFormEnum::symbol => 'symbol', |
| 215 | + ) as $form => $formText ) { |
| 216 | + foreach ( array( |
| 217 | + WCPluralEnum::singular => 'singular', |
| 218 | + WCPluralEnum::plural => 'plural', |
| 219 | + ) as $num => $numText ) { |
| 220 | + $this->propertyLabels[ $key ][ $form ][ $num ] = wfMsg( 'wc-' . $name . '-' . $formText . '-' . $numText ); |
| 221 | + } |
| 222 | + } |
| 223 | + } |
| 224 | + $this->circaLabels = array(); |
| 225 | + foreach ( array( |
| 226 | + WCLabelFormEnum::long => 'long', |
| 227 | + WCLabelFormEnum::verb => 'verb', |
| 228 | + WCLabelFormEnum::short => 'short', |
| 229 | + WCLabelFormEnum::verbShort => 'verb-short', |
| 230 | + WCLabelFormEnum::symbol => 'symbol', |
| 231 | + ) as $form => $formText ) { |
| 232 | + foreach ( array( |
| 233 | + WCPluralEnum::singular => 'singular', |
| 234 | + WCPluralEnum::plural => 'plural', |
| 235 | + ) as $num => $numText ) { |
| 236 | + $this->dateTermLabels[ $key ][ $form ][ $num ] = wfMsg( 'wc-circa-' . $formText . '-' . $numText ); |
| 237 | + } |
| 238 | + } |
| 239 | + |
| 240 | + # Title style variables. |
| 241 | + $this->iExQuote = wfMsg( 'wc-initial-exterior-quote' ); |
| 242 | + $this->fExQuote = wfMsg( 'wc-final-exterior-quote' ); |
| 243 | + $this->iInQuote = wfMsg( 'wc-initial-interior-quote' ); |
| 244 | + $this->fInQuote = wfMsg( 'wc-final-interior-quote' ); |
| 245 | + |
| 246 | + # Date style variables. |
| 247 | + $this->stripMonthPeriods = False; |
| 248 | + $this->monthDayYear = True; # Whether month-day-year is preferred over day-month-year |
| 249 | + $this->ad = wfMsg( 'wc-ad' ); |
| 250 | + $this->adNoPunct = wfMsg( 'wc-ad-no-punct' ); |
| 251 | + $this->ce = wfMsg( 'wc-ce' ); |
| 252 | + $this->ceNoPunct = wfMsg( 'wc-ce-no-punct' ); |
| 253 | + $this->bc = wfMsg( 'wc-bc' ); |
| 254 | + $this->bcNoPunct = wfMsg( 'wc-bc-no-punct' ); |
| 255 | + $this->bce = wfMsg( 'wc-bce' ); |
| 256 | + $this->bceNoPunct = wfMsg( 'wc-bce-no-punct' ); |
| 257 | + |
| 258 | + $this->spring = wfMsg( 'wc_spring' ); |
| 259 | + $this->summer = wfMsg( 'wc_summer' ); |
| 260 | + $this->autumn = wfMsg( 'wc_autumn' ); |
| 261 | + $this->winter = wfMsg( 'wc_winter' ); |
| 262 | + $this->year = wfMsg( 'wc_year' ); |
| 263 | + $this->month = wfMsg( 'wc_month' ); |
| 264 | + $this->day = wfMsg( 'wc_day' ); |
| 265 | + |
| 266 | + # Literal text |
| 267 | + $this->personalCommunitation = wfMsg( 'wc-personal-communication' ); |
| 268 | + |
| 269 | + # Name style variables. |
| 270 | + $this->demoteNonDroppingParticle = False; |
| 271 | + $this->nameWhitespace = wfMsg( 'wc-name-whitespace' ); |
| 272 | + $this->sortOrderDelimiter = wfMsg( 'wc-name-sort-order-delimiter' ); |
| 273 | + $this->missingName = wfMsg( 'wc-name-missing' ); |
| 274 | + $this->sortOrderSurnameDelimiter = wfMsg( 'wc-surname-delimiter' ); |
| 275 | + $this->nameSuffixDelimiter = wfMsg( 'wc-name-suffix-delimiter' ); |
| 276 | + |
| 277 | + # Names style variables. |
| 278 | + $this->etAlMin = 3; |
| 279 | + $this->etAlUseFirst = 1; |
| 280 | + $this->etAlSubsequentMin = 3; |
| 281 | + $this->etAlSubsequentUseFirst = 1; |
| 282 | + $this->namesDelimiter = wfMsg( 'wc-names-delim' ); |
| 283 | + $this->etAlDelimiter = wfMsg( 'wc-names-et-al-delim' ); |
| 284 | + $this->and2 = wfMsg( 'wc-names-and-2' ); |
| 285 | + $this->and3 = wfMsg( 'wc-names-and-3' ); |
| 286 | + $this->etAl = wfMsg( 'wc-names-and-others' ); |
| 287 | + } |
| 288 | + |
| 289 | + |
| 290 | + /** |
| 291 | + * Composes a short citation for in-text use. |
| 292 | + * The resulting citation should omit closing punctuation, and be suitable |
| 293 | + * for inclusion as part of a larger sentence. |
| 294 | + * @abstract |
| 295 | + * @return string |
| 296 | + */ |
| 297 | + abstract public function renderShortInlineCitation( WCCitation $citation ); |
| 298 | + |
| 299 | + |
| 300 | + /** |
| 301 | + * Composes a short citation for use in a footnote or endnote. |
| 302 | + * The resulting citation should include closing sentence punctuation. |
| 303 | + * @abstract |
| 304 | + * @return string |
| 305 | + */ |
| 306 | + abstract public function renderShortNoteCitation( WCCitation $citation ); |
| 307 | + |
| 308 | + |
| 309 | + /** |
| 310 | + * Composes a short citation for use in an author-date system. |
| 311 | + * The resulting citation should omit closing sentence punctuation. |
| 312 | + * @abstract |
| 313 | + * @return string |
| 314 | + */ |
| 315 | + abstract public function renderShortAuthorDateCitation( WCCitation $citation ); |
| 316 | + |
| 317 | + |
| 318 | + /** |
| 319 | + * Composes a long inline citation. |
| 320 | + * This citation should omit ending punctuation, and be suitable for |
| 321 | + * inclusion in inline text as part of a larger sentence. |
| 322 | + * @abstract |
| 323 | + * @return string |
| 324 | + */ |
| 325 | + abstract public function renderLongInlineCitation( WCCitation $citation ); |
| 326 | + |
| 327 | + |
| 328 | + /** |
| 329 | + * Composes a long citation for a bibliography |
| 330 | + * @abstract |
| 331 | + * @return string |
| 332 | + */ |
| 333 | + abstract public function renderLongBiblioCitation( WCCitation $citation ); |
| 334 | + |
| 335 | + |
| 336 | + /** |
| 337 | + * Composes a long note citation |
| 338 | + * @abstract |
| 339 | + * @return string |
| 340 | + */ |
| 341 | + abstract public function renderLongNoteCitation( WCCitation $citation ); |
| 342 | + |
| 343 | + |
| 344 | + /** |
| 345 | + * Composes a long author-date citation |
| 346 | + * @abstract |
| 347 | + * @return string |
| 348 | + */ |
| 349 | + abstract public function renderLongAuthorDateCitation( WCCitation $citation ); |
| 350 | + |
| 351 | + |
| 352 | + /** |
| 353 | + * Create a wikilink. If no article, the function returns the $title. |
| 354 | + * |
| 355 | + * @param string $article = the wikipedia article name |
| 356 | + * @param string $text = text for the link |
| 357 | + * @param string $classes = the HTML classes. |
| 358 | + * @return string $text if no $article, otherwise wrap $text in anchor |
| 359 | + */ |
| 360 | + public static function makeWikiLink( $article, $text, $classes = '' ) { |
| 361 | + if ( $article ) { |
| 362 | + $title = Title::newFromText( $article ); |
| 363 | + $attribs = array( 'class' => $classes ); |
| 364 | + global $wgVersion; |
| 365 | + if ( version_compare( $wgVersion, '1.18', '<' ) ) { |
| 366 | + global $wgUser; |
| 367 | + return $wgUser->getSkin()->link( $title, $text, $attribs ); |
| 368 | + } else { |
| 369 | + return Linker::link( $title, $text, $attribs ); |
| 370 | + } |
| 371 | + } elseif ( $classes ) { |
| 372 | + return self::wrapHTMLSpan( $text, $classes ); |
| 373 | + } else { |
| 374 | + return $text; |
| 375 | + } |
| 376 | + } |
| 377 | + |
| 378 | + |
| 379 | + /** |
| 380 | + * Wrap text in an HTML span element. |
| 381 | + * @param string $text |
| 382 | + * @param string $htmlClasses |
| 383 | + * @return string |
| 384 | + */ |
| 385 | + public static function wrapHTMLSpan( $text, $htmlClasses ) { |
| 386 | + return '<span class="' . $htmlClasses . '">' . $text . '</span>'; |
| 387 | + } |
| 388 | + |
| 389 | + |
| 390 | + /** |
| 391 | + * Stylize text as a quotation. |
| 392 | + * |
| 393 | + * Eventually, literal quoting might be replaced by html <q> tags, which |
| 394 | + * are already localized and are more accessible. When browser |
| 395 | + * compatibility increases, this function will simply wrap the text in |
| 396 | + * <q>..</q> tags. |
| 397 | + * |
| 398 | + * @param string $text |
| 399 | + * @return string |
| 400 | + */ |
| 401 | + public function quote( $text ) { |
| 402 | + return $this->iExQuote . $text . $this->fExQuote; |
| 403 | + } |
| 404 | + |
| 405 | + /** |
| 406 | + * Perform any text transformations of a title that a style may require. |
| 407 | + * @param string $title |
| 408 | + * @return string |
| 409 | + */ |
| 410 | + public function transformTitle( $title ) { |
| 411 | + if ( $this->replaceAmpersands ) { |
| 412 | + $title = str_replace( ' & ', ' and ', $title ); |
| 413 | + } |
| 414 | + #$title = $wgContLang->ucwords( $title ); |
| 415 | + /* |
| 416 | + * The following are not capitalized: |
| 417 | + * both definite and indefinite articles |
| 418 | + * prepositions |
| 419 | + * coordinating conjunctions |
| 420 | + * to when used in infinitives |
| 421 | + * In foreign languages, capitalization follows foreign practice. |
| 422 | + * After hypen, capitalize if it is a noun, proper adjective, or it has |
| 423 | + * equal force with the first word. |
| 424 | + */ |
| 425 | + return $title; |
| 426 | + } |
| 427 | + |
| 428 | + |
| 429 | + /** |
| 430 | + * Convert semantic quotes to localized character-based quotes. |
| 431 | + * When old browsers die, at some point this method will not be necessary, |
| 432 | + * because the browser should do this conversion itself. |
| 433 | + * |
| 434 | + * @param string $text |
| 435 | + * @param boolean $internal |
| 436 | + * @return string |
| 437 | + */ |
| 438 | + public function convertSemanticToCharacterQuotes( $text, $internal = False ) { |
| 439 | + if( ! $text ) return ''; |
| 440 | + |
| 441 | + $openPos = mb_stripos( $text, '<q>'); |
| 442 | + $closePos = mb_stripos( $text, '</q>'); |
| 443 | + if ( is_int( $openPos ) ) { |
| 444 | + if ( is_int( $closePos ) && $closePos < $openPos ) { |
| 445 | + # Next quote is a close quote. |
| 446 | + $head = mb_substr( $text, 0, $closePos ); |
| 447 | + $tail = mb_substr( $text, $closePos + 4 ); |
| 448 | + $quote = $internal ? $this->fExQuote : $this->fInQuote; |
| 449 | + return $head . $quote . $this->convertSemanticToCharacterQuotes( $tail, ! $internal ); |
| 450 | + } else { |
| 451 | + # Next quote is an open quote. |
| 452 | + $head = mb_substr( $text, 0, $openPos ); |
| 453 | + $tail = mb_substr( $text, $openPos + 3 ); |
| 454 | + $quote = $internal ? $this->iInQuote : $this->iExQuote; |
| 455 | + return $head . $quote . $this->convertSemanticToCharacterQuotes( $tail, ! $internal ); |
| 456 | + } |
| 457 | + } elseif ( is_int( $closePos ) ) { |
| 458 | + # Next quote is a close quote. |
| 459 | + $head = mb_substr( $text, 0, $closePos ); |
| 460 | + $tail = mb_substr( $text, $closePos + 4 ); |
| 461 | + $quote = $internal ? $this->fExQuote : $this->fInQuote; |
| 462 | + return $head . $quote . $this->convertSemanticToCharacterQuotes( $tail, ! $internal ); |
| 463 | + } else { |
| 464 | + # No more quotes. |
| 465 | + return $text; |
| 466 | + } |
| 467 | + } |
| 468 | + |
| 469 | + |
| 470 | + public function capitalize( $text, WCTextCaseEnum $case ) { |
| 471 | + switch ( $case->key ) { |
| 472 | + case WCTextCaseEnum::normal: |
| 473 | + return $text; |
| 474 | + |
| 475 | + case WCTextCaseEnum::lowercase: |
| 476 | + return mb_strtolower( $text ); |
| 477 | + |
| 478 | + case WCTextCaseEnum::uppercase: |
| 479 | + return mb_strtoupper( $text ); |
| 480 | + |
| 481 | + case WCTextCaseEnum::capitalizeFirst: |
| 482 | + return mb_strtoupper( mb_substr( $text, 0, 1 ) ) . mb_substr( $text, 1 ); |
| 483 | + |
| 484 | + case WCTextCaseEnum::capitalizeAll: # capitalize every first letter |
| 485 | + $arr = preg_split('/u', $text, -1, PREG_SPLIT_NO_EMPTY); |
| 486 | + $result = ''; |
| 487 | + $mode = false; |
| 488 | + foreach ($arr as $char) { |
| 489 | + $res = preg_match( '/\p{Mn}|\p{Me}|\p{Cf}|\p{Lm}|\p{Sk}|\p{Lu}|\p{Ll}|\p{Lt}|\p{Sk}|\p{Cs}/uS', $char ) == 1; |
| 490 | + if ($mode) { |
| 491 | + if (!$res) |
| 492 | + $mode = false; |
| 493 | + } elseif ($res) { |
| 494 | + $mode = true; |
| 495 | + $char = mb_strtoupper( $char ); |
| 496 | + } |
| 497 | + $result .= $char; |
| 498 | + } |
| 499 | + return $result; |
| 500 | + |
| 501 | + case WCTextCaseEnum::title: |
| 502 | + # This is not implemented yet. |
| 503 | + return mb_strtoupper( mb_substr( $text, 0, 1 ) ) . mb_substr( $text, 1 ); |
| 504 | + } |
| 505 | + } |
| 506 | + |
| 507 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/WikiCitation/includes/WCStyle.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 508 | + native |
Index: trunk/extensions/WikiCitation/includes/WCArticle.php |
— | — | @@ -0,0 +1,286 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Represents a page with citations. |
| 13 | + */ |
| 14 | +class WCArticle implements Countable { |
| 15 | + |
| 16 | + /** |
| 17 | + * Constants |
| 18 | + */ |
| 19 | + const defaultStyleID = 'wc_default'; # magic word for default citation style: |
| 20 | + const noteMarkerHTML = 'notemarker'; # HTML class for the note marker |
| 21 | + const endnotesHTML = 'endnotes'; # HTML class for endnotes list |
| 22 | + const noteNumberHTML = 'notenumber'; # HTML class for the note number |
| 23 | + |
| 24 | + public static $defaultStyle; |
| 25 | + |
| 26 | + /** |
| 27 | + * Style objects. |
| 28 | + * These are created as needed, and then kept in memory. |
| 29 | + * @var array Array in the form of string class name => WCStyle object. |
| 30 | + */ |
| 31 | + protected static $styleObjects = array(); |
| 32 | + |
| 33 | + /** |
| 34 | + * Database of unique references. |
| 35 | + * @var WCReferenceStore |
| 36 | + */ |
| 37 | + protected $referenceStore; |
| 38 | + |
| 39 | + /** |
| 40 | + * Arrays keyed to the citation key. |
| 41 | + * These represent a master database of all citations in the article. |
| 42 | + * @var array |
| 43 | + */ |
| 44 | + public $citations = array(); |
| 45 | + public $styles = array(); |
| 46 | + public $citationTypes = array(), $citationLengths = array(); |
| 47 | + |
| 48 | + protected $currentDefaultStyle; |
| 49 | + |
| 50 | + protected $bibliography; |
| 51 | + |
| 52 | + protected $bibliographyLevel = 0, $noteLevel = 0; |
| 53 | + |
| 54 | + /** |
| 55 | + * Stack containing note text and markers |
| 56 | + * @var array = ( level => ( note number => note text ) ) |
| 57 | + */ |
| 58 | + protected $sectionStack; |
| 59 | + |
| 60 | + protected $sectionStackPointer = 0; |
| 61 | + |
| 62 | + /** |
| 63 | + * Keeps a running count fo the number of $citations. |
| 64 | + * @var int |
| 65 | + */ |
| 66 | + protected $citationCount = 0; |
| 67 | + |
| 68 | + |
| 69 | + /** |
| 70 | + * Static initializer. |
| 71 | + */ |
| 72 | + public static function init() { |
| 73 | + global $wgWCCitationStyles; |
| 74 | + $defaultStyleName = $wgWCCitationStyles[ self::defaultStyleID ]; |
| 75 | + self::$defaultStyle = self::getStyle( $defaultStyleName ); |
| 76 | + } |
| 77 | + |
| 78 | + |
| 79 | + /** |
| 80 | + * Construct article. |
| 81 | + * @global type $wgWCCitationStyles |
| 82 | + */ |
| 83 | + public function __construct() { |
| 84 | + $this->currentDefaultStyle = self::$defaultStyle; |
| 85 | + # Create an initial section, representing the entire article. |
| 86 | + $this->sectionStack[0] = new WCSection( self::$defaultStyle, WCCitationTypeEnum::$inline ); |
| 87 | + $this->referenceStore = new WCReferenceStore(); |
| 88 | + } |
| 89 | + |
| 90 | + |
| 91 | + /** |
| 92 | + * Creates a citation object for each citation parser function. |
| 93 | + * |
| 94 | + * Reads flags and parameters from WCArgumentReader object, |
| 95 | + * then creates an appropriate child of class WCStyle based on the |
| 96 | + * first parameter after the colon, then returns the citation as text. |
| 97 | + * @remark Note that this $parser is guaranteed to be the same parser that |
| 98 | + * initialized the object. |
| 99 | + * |
| 100 | + * @param WCArgumentReader $argumentReader |
| 101 | + * @return string Unique marker for citation. |
| 102 | + */ |
| 103 | + public function parseCitation( WCArgumentReader $argumentReader ) { |
| 104 | + |
| 105 | + # Use the explicit citation style if defined, or use last style. |
| 106 | + $styleClassName = $argumentReader->getStyleClassName(); |
| 107 | + if ( $styleClassName ) { |
| 108 | + # Store citation style in a running database of style object singlets. |
| 109 | + $this->currentDefaultStyle = self::getStyle($styleClassName); |
| 110 | + } |
| 111 | + |
| 112 | + # A citation function, with no data, may exist merely to define the citation style. |
| 113 | + if ( $argumentReader->isEmpty() ) { |
| 114 | + ++$this->citationCount; |
| 115 | + return ''; |
| 116 | + } |
| 117 | + |
| 118 | + $reference = new WCReference(); |
| 119 | + $citation = new WCCitation( $reference ); |
| 120 | + $citation->readArguments( $argumentReader ); |
| 121 | + $reference->finalize(); |
| 122 | + |
| 123 | + # Store reference in database that checks for uniqueness. |
| 124 | + # $citation->reference will be reloaded later, after all citations are read. |
| 125 | + $citation->distance = $this->referenceStore->addUniqueReference( $this->citationCount, $reference ); |
| 126 | + |
| 127 | + # Is this a citation explicitly inserted in bibliography tags? |
| 128 | + # If so, then we will not be leaving behind a marker. |
| 129 | + if ( $this->bibliographyLevel > 0 ) { |
| 130 | + ++$this->citationCount; |
| 131 | + return ''; # Only a single marker is left behind per bibliography. |
| 132 | + } |
| 133 | + |
| 134 | + # Determine whether the citation is in a note, or inline. |
| 135 | + $section = $this->sectionStack[ $this->sectionStackPointer ]; |
| 136 | + if ( $this->noteLevel > 0 ) { |
| 137 | + $section->addNoteCite( $this->citationCount, $citation ); |
| 138 | + } else { |
| 139 | + $section->addInlineCite( $this->citationCount, $citation ); |
| 140 | + } |
| 141 | + |
| 142 | + # Store citation and leave behind a random marker for later replacement by the citation: |
| 143 | + $this->citations[ $this->citationCount++ ] = $citation; |
| 144 | + return $citation->marker; |
| 145 | + |
| 146 | + } |
| 147 | + |
| 148 | + |
| 149 | + /** |
| 150 | + * Begin a new endnote section. |
| 151 | + * Citation style and type may be inherited from enclosing section, if undefined. |
| 152 | + * @param array $args = HTML attributes |
| 153 | + */ |
| 154 | + public function startSection( array $args ) { |
| 155 | + $superSection = $this->sectionStack[ $this->sectionStackPointer ]; |
| 156 | + $this->sectionStack[ ++$this->sectionStackPointer ] = |
| 157 | + WCSection::getSection( $args, $superSection->citationStyle, $superSection->citationType ); |
| 158 | + } |
| 159 | + |
| 160 | + |
| 161 | + /** |
| 162 | + * End the existing endnote section. |
| 163 | + */ |
| 164 | + public function endSection() { |
| 165 | + --$this->sectionStackPointer; |
| 166 | + } |
| 167 | + |
| 168 | + |
| 169 | + public function startNote( array $args ) { |
| 170 | + ++$this->noteLevel; |
| 171 | + # If a note tag is nested, ignore it but keep track of nesting level. |
| 172 | + if ( $this->noteLevel > 1 || $this->bibliographyLevel > 0 ) { |
| 173 | + return; |
| 174 | + } |
| 175 | + $this->sectionStack[ $this->sectionStackPointer ]->startNote( $args ); |
| 176 | + } |
| 177 | + |
| 178 | + |
| 179 | + /** |
| 180 | + * Parse endnote text and save. Leave behind a marker for later replacement. |
| 181 | + * @param string $text Parsed text of the endnote. |
| 182 | + * @return string Marker to later be replaced with subscripted note mark. |
| 183 | + */ |
| 184 | + public function finishNote( $text ) { |
| 185 | + # Do not insert footnote if nested, or within biblio tags |
| 186 | + if ( --$this->noteLevel > 0 || $this->bibliographyLevel > 0) { |
| 187 | + return $text; |
| 188 | + } |
| 189 | + return $this->sectionStack[ $this->sectionStackPointer ]->finishNote( $text ); |
| 190 | + } |
| 191 | + |
| 192 | + |
| 193 | + public function markEndnotes() { |
| 194 | + return $this->sectionStack[ $this->sectionStackPointer ]->addEndnotes(); |
| 195 | + } |
| 196 | + |
| 197 | + |
| 198 | + public function startBibliography( array $args ) { |
| 199 | + ++$this->bibliographyLevel; |
| 200 | + # If a bibliography already exists, or is nested, ignore it, but keep track of nesting level. |
| 201 | + if ( isset( $this->bibliography ) || $this->bibliographyLevel > 1 ) { |
| 202 | + return; |
| 203 | + } |
| 204 | + $this->bibliography = WCBibliography::getBibliography( $args, $this->currentDefaultStyle ); |
| 205 | + } |
| 206 | + |
| 207 | + |
| 208 | + public function endBibliography() { |
| 209 | + # If the bibliography end tag is nested, ignore it. Otherwise, leave marker. |
| 210 | + if ( --$this->bibliographyLevel > 0 ) { |
| 211 | + return ''; |
| 212 | + } else { |
| 213 | + return $this->bibliography->getMarker(); |
| 214 | + } |
| 215 | + } |
| 216 | + |
| 217 | + |
| 218 | + /** |
| 219 | + * Renders and inserts citations and other material, replacing all markers. |
| 220 | + * |
| 221 | + * @global type $wgWCCitationStyles |
| 222 | + * @param string $text = the current parsed text of the article |
| 223 | + */ |
| 224 | + public function render( &$text ) { |
| 225 | + |
| 226 | + # Update references, which might have changed due to consolidation, from referenceStore. |
| 227 | + foreach( $this->citations as $key => $citation ) { |
| 228 | + $citation->reference = $this->referenceStore->getReference($key); |
| 229 | + } |
| 230 | + |
| 231 | + # Render note marks, free-standing citations, and endnotes. |
| 232 | + $this->sectionStack[ $this->sectionStackPointer ]->render( |
| 233 | + $text, |
| 234 | + $this->citations, |
| 235 | + (boolean) $this->bibliography |
| 236 | + ); |
| 237 | + |
| 238 | + # Render bibliography. |
| 239 | + if ( $this->bibliography ) { |
| 240 | + $this->bibliography->render( $text, $this->referenceStore ); |
| 241 | + } |
| 242 | + } |
| 243 | + |
| 244 | + |
| 245 | + /** |
| 246 | + * Given a style name, return the style object singlet. |
| 247 | + * @param string $styleClassName = Style class name (e.g., "WCChicagoStyle") |
| 248 | + * @return WCStyle |
| 249 | + */ |
| 250 | + public static function getStyle( $styleClassName ) { |
| 251 | + $styleObject = & self::$styleObjects[ $styleClassName ]; |
| 252 | + if ( is_null( $styleObject ) ) { |
| 253 | + $styleObject = new $styleClassName(); |
| 254 | + } |
| 255 | + return $styleObject; |
| 256 | + } |
| 257 | + |
| 258 | + |
| 259 | + /** |
| 260 | + * Clear page of citations. |
| 261 | + * @param PPFrame_DOM $frame |
| 262 | + * @param array $args |
| 263 | + */ |
| 264 | + public function clear() { |
| 265 | + $this->citations = array(); |
| 266 | + $this->citationCount = $this->bibliographyLevel = 0; |
| 267 | + $this->sectionStackPointer = $this->noteLevel = 0; |
| 268 | + $this->currentDefaultStyle = self::$defaultStyle; |
| 269 | + $this->sectionStack[0] = new WCSection( self::$defaultStyle, WCCitationTypeEnum::$inline ); |
| 270 | + $this->referenceStore = new WCReferenceStore(); |
| 271 | + } |
| 272 | + |
| 273 | + |
| 274 | + /** |
| 275 | + * Implements the count() function in the Countable interface (SPL). |
| 276 | + * @return int |
| 277 | + */ |
| 278 | + public function count() { |
| 279 | + return $this->citationCount; |
| 280 | + } |
| 281 | + |
| 282 | +} |
| 283 | + |
| 284 | +/** |
| 285 | + * Static initializer. |
| 286 | + */ |
| 287 | +WCArticle::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/WCArticle.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 288 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCCitationLengthEnum.php |
— | — | @@ -0,0 +1,105 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * The length of the citation, either short of long. Short citations are used |
| 13 | + * after the initial full cite. |
| 14 | + */ |
| 15 | +class WCCitationLengthEnum extends WCParameterEnum { |
| 16 | + const long = 0; |
| 17 | + const short = 1; |
| 18 | + const __default = self::long; |
| 19 | + |
| 20 | + public static $long; |
| 21 | + public static $short; |
| 22 | + |
| 23 | + public static $magicWordKeys = array( |
| 24 | + self::long => 'wc_long', |
| 25 | + self::short => 'wc_short' |
| 26 | + ); |
| 27 | + public static $substitutes = array(); |
| 28 | + public static $magicWordArray; |
| 29 | + public static $flipMagicWordKeys = array(); |
| 30 | + |
| 31 | + public static function init() { |
| 32 | + parent::init( self::$magicWordKeys, self::$substitutes, |
| 33 | + self::$magicWordArray, self::$flipMagicWordKeys ); |
| 34 | + self::$long = new self( self::long ); |
| 35 | + self::$short = new self( self::short ); |
| 36 | + } |
| 37 | + |
| 38 | + /** |
| 39 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 40 | + */ |
| 41 | + public function __construct( $key = self::__default ) { |
| 42 | + parent::__construct( $key ); |
| 43 | + $subs = &self::$substitutes[ $this->key ]; |
| 44 | + if ( $subs ) { |
| 45 | + $this->substituteArray = $subs; |
| 46 | + } |
| 47 | + } |
| 48 | + /** |
| 49 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 50 | + */ |
| 51 | + public static function match( $parameterText ) { |
| 52 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 53 | + if ( $id ) { |
| 54 | + return new self( self::$flipMagicWordKeys[ $id ] ); |
| 55 | + } else { |
| 56 | + return Null; |
| 57 | + } |
| 58 | + } |
| 59 | + /** |
| 60 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 61 | + */ |
| 62 | + public static function matchVariable( $parameterText ) { |
| 63 | + list( $id, $var ) = self::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 64 | + if ( $id ) { |
| 65 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $var ); |
| 66 | + } else { |
| 67 | + return Null; |
| 68 | + } |
| 69 | + } |
| 70 | + /** |
| 71 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 72 | + */ |
| 73 | + public static function matchPrefix( $parameterText ) { |
| 74 | + $id = self::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 75 | + if ( $id ) { |
| 76 | + # Remove any initial punctuation or spaces |
| 77 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 78 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 79 | + } else { |
| 80 | + return array( Null, $parameterText ); |
| 81 | + } |
| 82 | + } |
| 83 | + /** |
| 84 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 85 | + */ |
| 86 | + public static function matchPartAndNumber( $parameterText ) { |
| 87 | + # Extract number and remove number, white spaces and punctuation. |
| 88 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 89 | + $numString = $matches[0]; |
| 90 | + $num = (int) $numString; |
| 91 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 92 | + } else { |
| 93 | + $num = 1; |
| 94 | + } |
| 95 | + # Match what remains. |
| 96 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 97 | + if ( $id ) { |
| 98 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $num ); |
| 99 | + } else { |
| 100 | + return array( Null, $num ); |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + |
| 105 | +} |
| 106 | +WCCitationLengthEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCCitationLengthEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 107 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCCitationTypeEnum.php |
— | — | @@ -0,0 +1,114 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * The type of the citation, either note, biblio, or inline. Note citations |
| 13 | + * are found in footnotes and endnotes. Biblio citations are found in |
| 14 | + * bibliographies. Inline citations are found in the main text. |
| 15 | + */ |
| 16 | +class WCCitationTypeEnum extends WCParameterEnum { |
| 17 | + const inline = 0; |
| 18 | + const note = 1; |
| 19 | + const biblio = 2; |
| 20 | + const authorDate = 3; |
| 21 | + const __default = 0; |
| 22 | + |
| 23 | + public static $inline; |
| 24 | + public static $note; |
| 25 | + public static $biblio; |
| 26 | + public static $authorDate; |
| 27 | + |
| 28 | + public static $magicWordKeys = array( |
| 29 | + self::inline => 'wc_inline', |
| 30 | + self::note => 'wc_note', |
| 31 | + self::biblio => 'wc_bibliography', |
| 32 | + self::authorDate => 'wc_author_date', |
| 33 | + ); |
| 34 | + public static $substitutes = array(); |
| 35 | + public static $magicWordArray; |
| 36 | + public static $flipMagicWordKeys = array(); |
| 37 | + |
| 38 | + public static function init() { |
| 39 | + parent::init( self::$magicWordKeys, self::$substitutes, |
| 40 | + self::$magicWordArray, self::$flipMagicWordKeys ); |
| 41 | + self::$inline = new self( self::inline ); |
| 42 | + self::$note = new self( self::note ); |
| 43 | + self::$biblio = new self( self::biblio ); |
| 44 | + self::$authorDate = new self( self::authorDate ); |
| 45 | + } |
| 46 | + |
| 47 | + /** |
| 48 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 49 | + */ |
| 50 | + public function __construct( $key = self::__default ) { |
| 51 | + parent::__construct( $key ); |
| 52 | + $subs = &self::$substitutes[ $this->key ]; |
| 53 | + if ( $subs ) { |
| 54 | + $this->substituteArray = $subs; |
| 55 | + } |
| 56 | + } |
| 57 | + /** |
| 58 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 59 | + */ |
| 60 | + public static function match( $parameterText ) { |
| 61 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 62 | + if ( $id ) { |
| 63 | + return new self( self::$flipMagicWordKeys[ $id ] ); |
| 64 | + } else { |
| 65 | + return Null; |
| 66 | + } |
| 67 | + } |
| 68 | + /** |
| 69 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 70 | + */ |
| 71 | + public static function matchVariable( $parameterText ) { |
| 72 | + list( $id, $var ) = self::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 73 | + if ( $id ) { |
| 74 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $var ); |
| 75 | + } else { |
| 76 | + return Null; |
| 77 | + } |
| 78 | + } |
| 79 | + /** |
| 80 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 81 | + */ |
| 82 | + public static function matchPrefix( $parameterText ) { |
| 83 | + $id = self::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 84 | + if ( $id ) { |
| 85 | + # Remove any initial punctuation or spaces |
| 86 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 87 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 88 | + } else { |
| 89 | + return array( Null, $parameterText ); |
| 90 | + } |
| 91 | + } |
| 92 | + /** |
| 93 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 94 | + */ |
| 95 | + public static function matchPartAndNumber( $parameterText ) { |
| 96 | + # Extract number and remove number, white spaces and punctuation. |
| 97 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 98 | + $numString = $matches[0]; |
| 99 | + $num = (int) $numString; |
| 100 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 101 | + } else { |
| 102 | + $num = 1; |
| 103 | + } |
| 104 | + # Match what remains. |
| 105 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 106 | + if ( $id ) { |
| 107 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $num ); |
| 108 | + } else { |
| 109 | + return array( Null, $num ); |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + |
| 114 | +} |
| 115 | +WCCitationTypeEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCCitationTypeEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 116 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCParameterEnum.php |
— | — | @@ -0,0 +1,207 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * A WCEnum with each enumerated value keyed to a magic word. |
| 13 | + * Each enumerated value may be traversible among zero or more substitute |
| 14 | + * enumerated values. |
| 15 | + */ |
| 16 | +abstract class WCParameterEnum extends WCEnum implements Iterator { |
| 17 | + |
| 18 | + /** |
| 19 | + * Array of magic word keys. |
| 20 | + * @var array |
| 21 | + */ |
| 22 | + public static $magicWordKeys = array(); |
| 23 | + |
| 24 | + /** |
| 25 | + * Array of substitute parameters. |
| 26 | + * This array contains fallback elements. If the editor has not supplied |
| 27 | + * the information, and it is needed, the scopes will be tried in the order |
| 28 | + * of the array. |
| 29 | + * @var array |
| 30 | + */ |
| 31 | + public static $substitutes = array(); |
| 32 | + |
| 33 | + /** |
| 34 | + * MagicWordArray object. |
| 35 | + * Must be initalized statically by ::init(). |
| 36 | + * @var MagicWordArray |
| 37 | + */ |
| 38 | + public static $magicWordArray; |
| 39 | + |
| 40 | + /** |
| 41 | + * A flipped version of $magicWordKeys. |
| 42 | + * Must be initalized statically by ::init(). |
| 43 | + * @var array |
| 44 | + */ |
| 45 | + public static $flipMagicWordKeys; |
| 46 | + |
| 47 | + /** |
| 48 | + * An array of substitute enumerated values for $this->value. |
| 49 | + * Initialized by the constructor. |
| 50 | + * @var array |
| 51 | + */ |
| 52 | + protected $substituteArray; |
| 53 | + |
| 54 | + /** |
| 55 | + * Static initializer. |
| 56 | + * Delete extra parameters and convert to "static::" keyword when moving to PHP 3.3. |
| 57 | + */ |
| 58 | + public static function init( array $magicWordKeys, array $substitutes, |
| 59 | + &$magicWordArray, array &$flipMagicWordKeys ) { |
| 60 | + /*static::*/$magicWordArray = new MagicWordArray( /*static::*/$magicWordKeys ); |
| 61 | + /*static::*/$flipMagicWordKeys = array_flip( /*static::*/$magicWordKeys ); |
| 62 | + } |
| 63 | + |
| 64 | + public function __construct( $key = self::__default ) { |
| 65 | + parent::__construct( $key ); |
| 66 | + /* Uncomment the following when moving to PHP 3.3: |
| 67 | + $subs = &static::$substitutes[ $this->key ]; |
| 68 | + if ( $subs ) { |
| 69 | + $this->substituteArray = $subs; |
| 70 | + }*/ |
| 71 | + } |
| 72 | + |
| 73 | + /** |
| 74 | + * Use these functions, with late static binding, when moving to PHP 3.3. |
| 75 | + */ |
| 76 | + public static function match( $parameterText ) { |
| 77 | +/* $id = static::$magicWordArray->matchStartToEnd( $parameterText ); |
| 78 | + if ( $id ) { |
| 79 | + return new self( static::$flipMagicWordKeys[ $id ] ); |
| 80 | + } else { |
| 81 | + return Null; |
| 82 | + } |
| 83 | +*/ } |
| 84 | + |
| 85 | + public static function matchVariable( $parameterText ) { |
| 86 | +/* list( $id, $var ) = static::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 87 | + if ( $id ) { |
| 88 | + return array( new self( static::$flipMagicWordKeys[ $id ] ), $var ); |
| 89 | + } else { |
| 90 | + return Null; |
| 91 | + } |
| 92 | +*/ } |
| 93 | + |
| 94 | + /** |
| 95 | + * Match to a magic word prefix. |
| 96 | + * Returns the remainder in the second element of the array. |
| 97 | + * @param string $parameterText |
| 98 | + * @return array Array of ( enum key of the prefix, remainder string) |
| 99 | + */ |
| 100 | + public static function matchPrefix( $parameterText ) { |
| 101 | +/* $id = static::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 102 | + if ( $id ) { |
| 103 | + # Remove any initial punctuation or spaces |
| 104 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 105 | + return array( new self( static::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 106 | + } else { |
| 107 | + return array( Null, $parameterText ); |
| 108 | + } |
| 109 | +*/ } |
| 110 | + |
| 111 | + |
| 112 | + public static function matchPartAndNumber( $parameterText ) { |
| 113 | +/* # Extract number and remove number, white spaces and punctuation. |
| 114 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 115 | + $numString = $matches[0]; |
| 116 | + $num = (int) $numString; |
| 117 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 118 | + } else { |
| 119 | + $num = 1; |
| 120 | + } |
| 121 | + # Match what remains. |
| 122 | + $id = static::$magicWordArray->matchStartToEnd( $parameterText ); |
| 123 | + if ( $id ) { |
| 124 | + return array( new self( static::$flipMagicWordKeys[ $id ] ), $num ); |
| 125 | + } else { |
| 126 | + return array( Null, $num ); |
| 127 | + } |
| 128 | +*/ } |
| 129 | + |
| 130 | + |
| 131 | +/* public function __toString() { |
| 132 | + $magicWordID = static::$magicWordKeys[ $this->key ]; |
| 133 | + return MagicWord::get( $magicWordID )->getSynonym( 0 ); |
| 134 | + } |
| 135 | +*/ |
| 136 | + /** |
| 137 | + * Get the magic word key for this enumerated parameter. |
| 138 | + * |
| 139 | + public function getMagicWordKey() { |
| 140 | + return static::$magicWordKeys[ $this->key ]; |
| 141 | + }*/ |
| 142 | + |
| 143 | + /** |
| 144 | + * Implements Iterator interface method. |
| 145 | + * @return type |
| 146 | + */ |
| 147 | + public function key() { |
| 148 | + return key( $this->substituteArray ); |
| 149 | + } |
| 150 | + |
| 151 | + /** |
| 152 | + * Implements Iterator interface method. |
| 153 | + * @return type |
| 154 | + */ |
| 155 | + public function current() { |
| 156 | + return current( $this->substituteArray ); |
| 157 | + } |
| 158 | + |
| 159 | + /** |
| 160 | + * Implements Iterator interface method. |
| 161 | + * @return type |
| 162 | + */ |
| 163 | + public function next() { |
| 164 | + return next( $this->substituteArray ); |
| 165 | + } |
| 166 | + |
| 167 | + /** |
| 168 | + * Implements Iterator interface method. |
| 169 | + * @return type |
| 170 | + */ |
| 171 | + public function valid() { |
| 172 | + return ! ( current( $this->substituteArray ) === False ); |
| 173 | + } |
| 174 | + |
| 175 | + /** |
| 176 | + * Implements Iterator interface method. |
| 177 | + * @return type |
| 178 | + */ |
| 179 | + public function rewind() { |
| 180 | + return reset( $this->substituteArray ); |
| 181 | + } |
| 182 | + |
| 183 | + /** |
| 184 | + * Tests if a string is a localized version of a magic word. |
| 185 | + * |
| 186 | + * As of this coding, MagicWord.php has no MagicWord::matchStartToEnd() |
| 187 | + * function yet to do this simple task efficiently. |
| 188 | + * |
| 189 | + * @param string $text = the text to be tested |
| 190 | + * @param string $magicWordID = the magic word ID |
| 191 | + * @return boolean |
| 192 | + */ |
| 193 | + final protected static function isMagicWord( $text, $magicWordID ) { |
| 194 | + $magicWordObject = MagicWord::get( $magicWordID ); |
| 195 | + $synonyms = $magicWordObject->getSynonyms(); |
| 196 | + foreach( $synonyms as $synonym ) { |
| 197 | + if ( !$magicWordObject->isCaseSensitive() ) { |
| 198 | + $synonym = mb_strtolower( $synonym ); |
| 199 | + $text = mb_strtolower( $text ); |
| 200 | + } |
| 201 | + if ( $synonym === $text ) { |
| 202 | + return True; |
| 203 | + } |
| 204 | + } |
| 205 | + return False; |
| 206 | + } |
| 207 | + |
| 208 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCParameterEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 209 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCNameTypeEnum.php |
— | — | @@ -0,0 +1,134 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCNameTypeEnum extends WCParameterEnum { |
| 12 | + const author = 0; |
| 13 | + const editorTranslator = 1; # This goes before editor and translator, because otherwise, the search would stop when it reaches either of the shorter terms. |
| 14 | + const editor = 2; |
| 15 | + const translator = 3; |
| 16 | + const publisher = 4; |
| 17 | + const interviewer = 5; |
| 18 | + const recipient = 6; |
| 19 | + const composer = 7; |
| 20 | + const __default = self::author; |
| 21 | + |
| 22 | + public static $author; |
| 23 | + public static $editorTranslator; |
| 24 | + public static $editor; |
| 25 | + public static $translator; |
| 26 | + public static $publisher; |
| 27 | + public static $interviewer; |
| 28 | + public static $recipient; |
| 29 | + public static $composer; |
| 30 | + |
| 31 | + public static $magicWordKeys = array( |
| 32 | + self::author => 'wc_author', |
| 33 | + self::editorTranslator => 'wc_editor_translator', |
| 34 | + self::editor => 'wc_editor', |
| 35 | + self::translator => 'wc_translator', |
| 36 | + self::publisher => 'wc_publisher', |
| 37 | + self::interviewer => 'wc_interviewer', |
| 38 | + self::recipient => 'wc_recipient', |
| 39 | + self::composer => 'wc_composer' |
| 40 | + ); |
| 41 | + public static $substitutes = array( |
| 42 | + self::author => array( self::author, self::editorTranslator, self::editor, self::translator, self::interviewer, self::composer, self::recipient, self::publisher ), |
| 43 | + self::editorTranslator => array( self::editorTranslator, self::editor, self::translator ), |
| 44 | + self::editor => array( self::editor ), |
| 45 | + self::translator => array( self::translator ), |
| 46 | + self::publisher => array( self::publisher ), |
| 47 | + self::interviewer => array( self::interviewer, self::author ), |
| 48 | + self::recipient => array( self::recipient, self::author ), |
| 49 | + self::composer => array( self::composer, self::author ) |
| 50 | + ); |
| 51 | + public static $magicWordArray; |
| 52 | + public static $flipMagicWordKeys = array(); |
| 53 | + |
| 54 | + public static function init() { |
| 55 | + parent::init( self::$magicWordKeys, self::$substitutes, |
| 56 | + self::$magicWordArray, self::$flipMagicWordKeys ); |
| 57 | + self::$author = new self( self::author ); |
| 58 | + self::$editorTranslator = new self( self::editorTranslator ); |
| 59 | + self::$editor = new self( self::editor ); |
| 60 | + self::$translator = new self( self::translator ); |
| 61 | + self::$publisher = new self( self::publisher ); |
| 62 | + self::$interviewer = new self( self::interviewer ); |
| 63 | + self::$recipient = new self( self::recipient ); |
| 64 | + self::$composer = new self( self::composer ); |
| 65 | + } |
| 66 | + |
| 67 | + /** |
| 68 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 69 | + */ |
| 70 | + public function __construct( $key = self::__default ) { |
| 71 | + parent::__construct( $key ); |
| 72 | + $subs = &self::$substitutes[ $this->key ]; |
| 73 | + if ( $subs ) { |
| 74 | + $this->substituteArray = $subs; |
| 75 | + } |
| 76 | + } |
| 77 | + /** |
| 78 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 79 | + */ |
| 80 | + public static function match( $parameterText ) { |
| 81 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 82 | + if ( $id ) { |
| 83 | + return new self( self::$flipMagicWordKeys[ $id ] ); |
| 84 | + } else { |
| 85 | + return Null; |
| 86 | + } |
| 87 | + } |
| 88 | + /** |
| 89 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 90 | + */ |
| 91 | + public static function matchVariable( $parameterText ) { |
| 92 | + list( $id, $var ) = self::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 93 | + if ( $id ) { |
| 94 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $var ); |
| 95 | + } else { |
| 96 | + return Null; |
| 97 | + } |
| 98 | + } |
| 99 | + /** |
| 100 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 101 | + */ |
| 102 | + public static function matchPrefix( $parameterText ) { |
| 103 | + $id = self::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 104 | + if ( $id ) { |
| 105 | + # Remove any initial punctuation or spaces |
| 106 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 107 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 108 | + } else { |
| 109 | + return array( Null, $parameterText ); |
| 110 | + } |
| 111 | + } |
| 112 | + /** |
| 113 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 114 | + */ |
| 115 | + public static function matchPartAndNumber( $parameterText ) { |
| 116 | + # Extract number and remove number, white spaces and punctuation. |
| 117 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 118 | + $numString = $matches[0]; |
| 119 | + $num = (int) $numString; |
| 120 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 121 | + } else { |
| 122 | + $num = 1; |
| 123 | + } |
| 124 | + # Match what remains. |
| 125 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 126 | + if ( $id ) { |
| 127 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $num ); |
| 128 | + } else { |
| 129 | + return array( Null, $num ); |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + |
| 134 | +} |
| 135 | +WCNameTypeEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCNameTypeEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 136 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCSourceTypeEnum.php |
— | — | @@ -0,0 +1,403 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCSourceTypeEnum extends WCParameterEnum { |
| 12 | + const general = 0; |
| 13 | + const book = 1; |
| 14 | + const dictionary = 2; |
| 15 | + const encyclopedia = 3; |
| 16 | + const periodical = 4; |
| 17 | + const magazine = 5; |
| 18 | + const newspaper = 6; |
| 19 | + const journal = 7; |
| 20 | + const entry = 8; |
| 21 | + const article = 9; |
| 22 | + const chapter = 10; |
| 23 | + const review = 11; |
| 24 | + const paper = 12; |
| 25 | + const manuscript = 13; |
| 26 | + const musicalScore = 14; |
| 27 | + const pamphlet = 15; |
| 28 | + const conferencePaper = 16; |
| 29 | + const thesis = 17; |
| 30 | + const report = 18; |
| 31 | + const poem = 19; |
| 32 | + const song = 20; |
| 33 | + const enactment = 21; |
| 34 | + const bill = 22; |
| 35 | + const statute = 23; |
| 36 | + const treaty = 24; |
| 37 | + const rule = 25; |
| 38 | + const regulation = 26; |
| 39 | + const legalDocument = 27; |
| 40 | + const patent = 28; |
| 41 | + const deed = 29; |
| 42 | + const governmentGrant = 30; |
| 43 | + const filing = 31; |
| 44 | + const patentApplication = 32; |
| 45 | + const regulatoryFiling = 33; |
| 46 | + const litigation = 34; |
| 47 | + const legalOpinion = 35; |
| 48 | + const legalCase = 36; |
| 49 | + const graphic = 37; |
| 50 | + const photograph = 38; |
| 51 | + const map = 39; |
| 52 | + const statement = 40; |
| 53 | + const pressRelease = 41; |
| 54 | + const interview = 42; |
| 55 | + const speech = 43; |
| 56 | + const personalCommunication = 44; |
| 57 | + const internetResource = 45; |
| 58 | + const webpage = 46; |
| 59 | + const post = 47; |
| 60 | + const production = 48; |
| 61 | + const motionPicture = 49; |
| 62 | + const recording = 50; |
| 63 | + const play = 51; |
| 64 | + const broadcast = 52; |
| 65 | + const televisionBroadcast = 53; |
| 66 | + const radioBroadcast = 54; |
| 67 | + const internetBroadcast = 55; |
| 68 | + const object = 56; |
| 69 | + const star = 57; |
| 70 | + const gravestone = 58; |
| 71 | + const monument = 59; |
| 72 | + const realProperty = 60; |
| 73 | + const __default = self::general; |
| 74 | + |
| 75 | + |
| 76 | + public static $general; |
| 77 | + public static $book; |
| 78 | + public static $dictionary; |
| 79 | + public static $encyclopedia; |
| 80 | + public static $periodical; |
| 81 | + public static $magazine; |
| 82 | + public static $newspaper; |
| 83 | + public static $journal; |
| 84 | + public static $entry; |
| 85 | + public static $article; |
| 86 | + public static $chapter; |
| 87 | + public static $review; |
| 88 | + public static $paper; |
| 89 | + public static $manuscript; |
| 90 | + public static $musicalScore; |
| 91 | + public static $pamphlet; |
| 92 | + public static $conferencePaper; |
| 93 | + public static $thesis; |
| 94 | + public static $report; |
| 95 | + public static $poem; |
| 96 | + public static $song; |
| 97 | + public static $enactment; |
| 98 | + public static $bill; |
| 99 | + public static $statute; |
| 100 | + public static $treaty; |
| 101 | + public static $rule; |
| 102 | + public static $regulation; |
| 103 | + public static $legalDocument; |
| 104 | + public static $patent; |
| 105 | + public static $deed; |
| 106 | + public static $governmentGrant; |
| 107 | + public static $filing; |
| 108 | + public static $patentApplication; |
| 109 | + public static $regulatoryFiling; |
| 110 | + public static $litigation; |
| 111 | + public static $legalOpinion; |
| 112 | + public static $legalCase; |
| 113 | + public static $graphic; |
| 114 | + public static $photograph; |
| 115 | + public static $map; |
| 116 | + public static $statement; |
| 117 | + public static $pressRelease; |
| 118 | + public static $interview; |
| 119 | + public static $speech; |
| 120 | + public static $personalCommunication; |
| 121 | + public static $internetResource; |
| 122 | + public static $webpage; |
| 123 | + public static $post; |
| 124 | + public static $production; |
| 125 | + public static $motionPicture; |
| 126 | + public static $recording; |
| 127 | + public static $play; |
| 128 | + public static $broadcast; |
| 129 | + public static $televisionBroadcast; |
| 130 | + public static $radioBroadcast; |
| 131 | + public static $internetBroadcast; |
| 132 | + public static $object; |
| 133 | + public static $star; |
| 134 | + public static $gravestone; |
| 135 | + public static $monument; |
| 136 | + public static $realProperty; |
| 137 | + |
| 138 | + |
| 139 | + public static $magicWordKeys = array( |
| 140 | + self::general => 'wc_general', |
| 141 | + self::book => 'wc_book', |
| 142 | + self::dictionary => 'wc_dictionary', |
| 143 | + self::encyclopedia => 'wc_encyclopedia', |
| 144 | + self::periodical => 'wc_periodical', |
| 145 | + self::magazine => 'wc_magazine', |
| 146 | + self::newspaper => 'wc_newspaper', |
| 147 | + self::journal => 'wc_journal', |
| 148 | + self::entry => 'wc_entry', |
| 149 | + self::article => 'wc_article', |
| 150 | + self::chapter => 'wc_chapter', |
| 151 | + self::review => 'wc_review', |
| 152 | + self::paper => 'wc_paper', |
| 153 | + self::manuscript => 'wc_manuscript', |
| 154 | + self::musicalScore => 'wc_musical_score', |
| 155 | + self::pamphlet => 'wc_pamphlet', |
| 156 | + self::conferencePaper => 'wc_conference_paper', |
| 157 | + self::thesis => 'wc_thesis', |
| 158 | + self::report => 'wc_report', |
| 159 | + self::poem => 'wc_poem', |
| 160 | + self::song => 'wc_song', |
| 161 | + self::enactment => 'wc_enactment', |
| 162 | + self::bill => 'wc_bill', |
| 163 | + self::statute => 'wc_statute', |
| 164 | + self::treaty => 'wc_treaty', |
| 165 | + self::rule => 'wc_rule', |
| 166 | + self::regulation => 'wc_regulation', |
| 167 | + self::legalDocument => 'wc_legal_document', |
| 168 | + self::patent => 'wc_patent', |
| 169 | + self::deed => 'wc_deed', |
| 170 | + self::governmentGrant => 'wc_government_grant', |
| 171 | + self::filing => 'wc_filing', |
| 172 | + self::patentApplication => 'wc_patent_application', |
| 173 | + self::regulatoryFiling => 'wc_regulatory_filing', |
| 174 | + self::litigation => 'wc_litigation', |
| 175 | + self::legalOpinion => 'wc_legal_opinion', |
| 176 | + self::legalCase => 'wc_legal_case', |
| 177 | + self::graphic => 'wc_graphic', |
| 178 | + self::photograph => 'wc_photograph', |
| 179 | + self::map => 'wc_map', |
| 180 | + self::statement => 'wc_statement', |
| 181 | + self::pressRelease => 'wc_press_release', |
| 182 | + self::interview => 'wc_interview', |
| 183 | + self::speech => 'wc_speech', |
| 184 | + self::personalCommunication => 'wc_personal_communication', |
| 185 | + self::internetResource => 'wc_internet_resource', |
| 186 | + self::webpage => 'wc_web_page', |
| 187 | + self::post => 'wc_post', |
| 188 | + self::production => 'wc_production', |
| 189 | + self::motionPicture => 'wc_motion_picture', |
| 190 | + self::recording => 'wc_recording', |
| 191 | + self::play => 'wc_play', |
| 192 | + self::broadcast => 'wc_broadcast', |
| 193 | + self::televisionBroadcast => 'wc_television_broadcast', |
| 194 | + self::radioBroadcast => 'wc_radio_broadcast', |
| 195 | + self::internetBroadcast => 'wc_internet_broadcast', |
| 196 | + self::object => 'wc_object', |
| 197 | + self::star => 'wc_star', |
| 198 | + self::gravestone => 'wc_gravestone', |
| 199 | + self::monument => 'wc_monument', |
| 200 | + self::realProperty => 'wc_real_property', |
| 201 | + ); |
| 202 | + |
| 203 | + public static $substitutes = array ( |
| 204 | + self::general => array( self::general ), |
| 205 | + self::book => array( self::book, self::general ), |
| 206 | + self::dictionary => array( self::dictionary, self::encyclopedia, self::book ), |
| 207 | + self::encyclopedia => array( self::encyclopedia, self::dictionary, self::book ), |
| 208 | + self::periodical => array( self::periodical, self::journal, self::general ), |
| 209 | + self::magazine => array( self::magazine, self::journal, self::periodical, self::general ), |
| 210 | + self::newspaper => array( self::newspaper, self::journal, self::periodical, self::general ), |
| 211 | + self::journal => array( self::journal, self::periodical, self::general ), |
| 212 | + self::entry => array( self::entry, self::general ), |
| 213 | + self::article => array( self::article, self::entry ), |
| 214 | + self::chapter => array( self::chapter, self::entry ), |
| 215 | + self::review => array( self::review, self::article, self::entry ), |
| 216 | + self::paper => array( self::paper, self::general ), |
| 217 | + self::manuscript => array( self::manuscript, self::paper, self::general ), |
| 218 | + self::musicalScore => array( self::musicalScore, self::paper, self::general ), |
| 219 | + self::pamphlet => array( self::pamphlet, self::paper, self::general ), |
| 220 | + self::conferencePaper => array( self::conferencePaper, self::paper, self::general ), |
| 221 | + self::thesis => array( self::thesis, self::paper, self::general ), |
| 222 | + self::report => array( self::report, self::paper, self::general ), |
| 223 | + self::poem => array( self::poem, self::paper, self::general ), |
| 224 | + self::song => array( self::song, self::paper, self::general ), |
| 225 | + self::enactment => array( self::enactment, self::general ), |
| 226 | + self::bill => array( self::bill, self::enactment, self::general ), |
| 227 | + self::statute => array( self::statute, self::enactment, self::general ), |
| 228 | + self::treaty => array( self::treaty, self::statute, self::enactment, self::general ), |
| 229 | + self::rule => array( self::rule, self::regulation, self::statute, self::enactment, self::general ), |
| 230 | + self::regulation => array( self::regulation, self::statute, self::enactment, self::general ), |
| 231 | + self::legalDocument => array( self::legalDocument, self::paper, self::general ), |
| 232 | + self::patent => array( self::patent, self::legalDocument, self::paper, self::general ), |
| 233 | + self::deed => array( self::deed, self::legalDocument, self::paper, self::general ), |
| 234 | + self::governmentGrant => array( self::governmentGrant, self::legalDocument, self::paper, self::general ), |
| 235 | + self::filing => array( self::filing, self::legalDocument, self::paper, self::general ), |
| 236 | + self::patentApplication => array( self::patentApplication, self::filing, self::legalDocument, self::paper, self::general ), |
| 237 | + self::regulatoryFiling => array( self::regulatoryFiling, self::filing, self::legalDocument, self::paper, self::general ), |
| 238 | + self::litigation => array( self::litigation, self::general ), |
| 239 | + self::legalOpinion => array( self::legalOpinion, self::legalCase, self::litigation, self::general ), |
| 240 | + self::legalCase => array( self::legalCase, self::litigation, self::general ), |
| 241 | + self::graphic => array( self::graphic, self::paper, self::general ), |
| 242 | + self::photograph => array( self::photograph, self::graphic, self::paper, self::general ), |
| 243 | + self::map => array( self::map, self::graphic, self::paper, self::general ), |
| 244 | + self::statement => array( self::statement, self::paper, self::general ), |
| 245 | + self::pressRelease => array( self::pressRelease, self::statement, self::paper, self::general ), |
| 246 | + self::interview => array( self::interview, self::statement, self::paper, self::general ), |
| 247 | + self::speech => array( self::speech, self::statement, self::paper, self::general ), |
| 248 | + self::personalCommunication => array( self::personalCommunication, self::statement, self::paper, self::general ), |
| 249 | + self::internetResource => array( self::internetResource, self::general ), |
| 250 | + self::webpage => array( self::webpage, self::internetResource, self::general ), |
| 251 | + self::post => array( self::post, self::internetResource, self::general ), |
| 252 | + self::production => array( self::production, self::general ), |
| 253 | + self::motionPicture => array( self::motionPicture, self::production, self::general ), |
| 254 | + self::recording => array( self::recording, self::production, self::general ), |
| 255 | + self::play => array( self::play, self::production, self::general ), |
| 256 | + self::broadcast => array( self::broadcast, self::production, self::general ), |
| 257 | + self::televisionBroadcast => array( self::televisionBroadcast, self::broadcast, self::production, self::general ), |
| 258 | + self::radioBroadcast => array( self::radioBroadcast, self::broadcast, self::production, self::general ), |
| 259 | + self::internetBroadcast => array( self::internetBroadcast, self::broadcast, self::production, self::webpage, self::general ), |
| 260 | + self::object => array( self::object, self::general ), |
| 261 | + self::star => array( self::star, self::object, self::general ), |
| 262 | + self::gravestone => array( self::gravestone, self::object, self::general ), |
| 263 | + self::monument => array( self::monument, self::object, self::general ), |
| 264 | + self::realProperty => array( self::realProperty, self::object, self::general ) |
| 265 | + ); |
| 266 | + |
| 267 | + public static $magicWordArray; |
| 268 | + public static $flipMagicWordKeys = array(); |
| 269 | + |
| 270 | + public static function init() { |
| 271 | + parent::init( self::$magicWordKeys, self::$substitutes, |
| 272 | + self::$magicWordArray, self::$flipMagicWordKeys ); |
| 273 | + self::$general = new self( self::general ); |
| 274 | + self::$book = new self( self::book ); |
| 275 | + self::$dictionary = new self( self::dictionary ); |
| 276 | + self::$encyclopedia = new self( self::encyclopedia ); |
| 277 | + self::$periodical = new self( self::periodical ); |
| 278 | + self::$magazine = new self( self::magazine ); |
| 279 | + self::$newspaper = new self( self::newspaper ); |
| 280 | + self::$journal = new self( self::journal ); |
| 281 | + self::$entry = new self( self::entry ); |
| 282 | + self::$article = new self( self::article ); |
| 283 | + self::$chapter = new self( self::chapter ); |
| 284 | + self::$review = new self( self::review ); |
| 285 | + self::$paper = new self( self::paper ); |
| 286 | + self::$manuscript = new self( self::manuscript ); |
| 287 | + self::$musicalScore = new self( self::musicalScore ); |
| 288 | + self::$pamphlet = new self( self::pamphlet ); |
| 289 | + self::$conferencePaper = new self( self::conferencePaper ); |
| 290 | + self::$thesis = new self( self::thesis ); |
| 291 | + self::$report = new self( self::report ); |
| 292 | + self::$poem = new self( self::poem ); |
| 293 | + self::$song = new self( self::song ); |
| 294 | + self::$enactment = new self( self::enactment ); |
| 295 | + self::$bill = new self( self::bill ); |
| 296 | + self::$statute = new self( self::statute ); |
| 297 | + self::$treaty = new self( self::treaty ); |
| 298 | + self::$rule = new self( self::rule ); |
| 299 | + self::$regulation = new self( self::regulation ); |
| 300 | + self::$legalDocument = new self( self::legalDocument ); |
| 301 | + self::$patent = new self( self::patent ); |
| 302 | + self::$deed = new self( self::deed ); |
| 303 | + self::$governmentGrant = new self( self::governmentGrant ); |
| 304 | + self::$filing = new self( self::filing ); |
| 305 | + self::$patentApplication = new self( self::patentApplication ); |
| 306 | + self::$regulatoryFiling = new self( self::regulatoryFiling ); |
| 307 | + self::$litigation = new self( self::litigation ); |
| 308 | + self::$legalOpinion = new self( self::legalOpinion ); |
| 309 | + self::$legalCase = new self( self::legalCase ); |
| 310 | + self::$graphic = new self( self::graphic ); |
| 311 | + self::$photograph = new self( self::photograph ); |
| 312 | + self::$map = new self( self::map ); |
| 313 | + self::$statement = new self( self::statement ); |
| 314 | + self::$pressRelease = new self( self::pressRelease ); |
| 315 | + self::$interview = new self( self::interview ); |
| 316 | + self::$speech = new self( self::speech ); |
| 317 | + self::$personalCommunication = new self( self::personalCommunication ); |
| 318 | + self::$internetResource = new self( self::internetResource ); |
| 319 | + self::$webpage = new self( self::webpage ); |
| 320 | + self::$post = new self( self::post ); |
| 321 | + self::$production = new self( self::production ); |
| 322 | + self::$motionPicture = new self( self::motionPicture ); |
| 323 | + self::$recording = new self( self::recording ); |
| 324 | + self::$play = new self( self::play ); |
| 325 | + self::$broadcast = new self( self::broadcast ); |
| 326 | + self::$televisionBroadcast = new self( self::televisionBroadcast ); |
| 327 | + self::$radioBroadcast = new self( self::radioBroadcast ); |
| 328 | + self::$internetBroadcast = new self( self::internetBroadcast ); |
| 329 | + self::$object = new self( self::object ); |
| 330 | + self::$star = new self( self::star ); |
| 331 | + self::$gravestone = new self( self::gravestone ); |
| 332 | + self::$monument = new self( self::monument ); |
| 333 | + self::$realProperty = new self( self::realProperty ); |
| 334 | + } |
| 335 | + |
| 336 | + /** |
| 337 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 338 | + */ |
| 339 | + public function __construct( $key = self::__default ) { |
| 340 | + parent::__construct( $key ); |
| 341 | + $subs = &self::$substitutes[ $this->key ]; |
| 342 | + if ( $subs ) { |
| 343 | + $this->substituteArray = $subs; |
| 344 | + } |
| 345 | + } |
| 346 | + /** |
| 347 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 348 | + */ |
| 349 | + public static function match( $parameterText ) { |
| 350 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 351 | + if ( $id ) { |
| 352 | + return new self( self::$flipMagicWordKeys[ $id ] ); |
| 353 | + } else { |
| 354 | + return Null; |
| 355 | + } |
| 356 | + } |
| 357 | + /** |
| 358 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 359 | + */ |
| 360 | + public static function matchVariable( $parameterText ) { |
| 361 | + list( $id, $var ) = self::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 362 | + if ( $id ) { |
| 363 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $var ); |
| 364 | + } else { |
| 365 | + return Null; |
| 366 | + } |
| 367 | + } |
| 368 | + /** |
| 369 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 370 | + */ |
| 371 | + public static function matchPrefix( $parameterText ) { |
| 372 | + $id = self::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 373 | + if ( $id ) { |
| 374 | + # Remove any initial punctuation or spaces |
| 375 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 376 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 377 | + } else { |
| 378 | + return array( Null, $parameterText ); |
| 379 | + } |
| 380 | + } |
| 381 | + /** |
| 382 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 383 | + */ |
| 384 | + public static function matchPartAndNumber( $parameterText ) { |
| 385 | + # Extract number and remove number, white spaces and punctuation. |
| 386 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 387 | + $numString = $matches[0]; |
| 388 | + $num = (int) $numString; |
| 389 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 390 | + } else { |
| 391 | + $num = 1; |
| 392 | + } |
| 393 | + # Match what remains. |
| 394 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 395 | + if ( $id ) { |
| 396 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $num ); |
| 397 | + } else { |
| 398 | + return array( Null, $num ); |
| 399 | + } |
| 400 | + } |
| 401 | + |
| 402 | + |
| 403 | +} |
| 404 | +WCSourceTypeEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCSourceTypeEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 405 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCAttributeEnum.php |
— | — | @@ -0,0 +1,48 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCAttributeEnum extends WCEnum { |
| 12 | + const text = 0; |
| 13 | + const title = 1; |
| 14 | + const date = 2; |
| 15 | + const parameter = 3; |
| 16 | + const name = 4; |
| 17 | + const names = 5; |
| 18 | + const locator = 6; |
| 19 | + const __default = self::text; |
| 20 | + |
| 21 | + public static $text; |
| 22 | + public static $title; |
| 23 | + public static $date; |
| 24 | + public static $parameter; |
| 25 | + public static $name; |
| 26 | + public static $names; |
| 27 | + public static $locator; |
| 28 | + |
| 29 | + public static $attribute = array( |
| 30 | + self::text => 'WCText', |
| 31 | + self::title => 'WCTitle', |
| 32 | + self::date => 'WCDate', |
| 33 | + self::parameter => 'WCTypeData', |
| 34 | + self::name => 'WCName', |
| 35 | + self::names => 'WCNames', |
| 36 | + self::locator => 'WCLocator', |
| 37 | + ); |
| 38 | + |
| 39 | + public static function init() { |
| 40 | + self::$text = new self( self::text ); |
| 41 | + self::$title = new self( self::title ); |
| 42 | + self::$date = new self( self::date ); |
| 43 | + self::$parameter = new self( self::parameter ); |
| 44 | + self::$name = new self( self::name ); |
| 45 | + self::$names = new self( self::names ); |
| 46 | + self::$locator = new self( self::locator ); |
| 47 | + } |
| 48 | +} |
| 49 | +WCAttributeEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCAttributeEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 50 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCPropertyEnum.php |
— | — | @@ -0,0 +1,383 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCPropertyEnum extends WCParameterEnum { |
| 12 | + const title = 0; |
| 13 | + const shortTitle = 1; |
| 14 | + const place = 2; |
| 15 | + const edition = 3; |
| 16 | + const firstPage = 4; |
| 17 | + const version = 5; |
| 18 | + const number = 6; |
| 19 | + const archive = 7; |
| 20 | + const jurisdiction = 10; |
| 21 | + const keyword = 11; |
| 22 | + |
| 23 | + const page = 12; |
| 24 | + const pageRange = 13; |
| 25 | + const volume = 14; |
| 26 | + const issue = 15; |
| 27 | + const opus = 16; |
| 28 | + const bookLoc = 17; # i.e., biblical "book," book III of Lord of the Rings, etc. |
| 29 | + const part = 18; |
| 30 | + const chapterLoc = 19; |
| 31 | + const folio = 20; |
| 32 | + const column = 21; |
| 33 | + const table = 22; |
| 34 | + const figure = 23; |
| 35 | + const section = 24; |
| 36 | + const paragraph = 25; |
| 37 | + const noteLoc = 26; |
| 38 | + const footnote = 27; |
| 39 | + const endnote = 28; |
| 40 | + const verse = 29; |
| 41 | + const line = 30; |
| 42 | + const locator = 31; |
| 43 | + |
| 44 | + const type = 32; |
| 45 | + |
| 46 | + const link = 33; |
| 47 | + const url = 34; |
| 48 | + |
| 49 | + const callNumber = 35; |
| 50 | + const doi = 36; |
| 51 | + const isbn = 37; |
| 52 | + |
| 53 | + const date = 38; |
| 54 | + const accessed = 39; |
| 55 | + const issued = 40; |
| 56 | + const filed = 41; |
| 57 | + |
| 58 | + const __default = self::title; |
| 59 | + |
| 60 | + |
| 61 | + public static $title; |
| 62 | + public static $shortTitle; |
| 63 | + public static $place; |
| 64 | + public static $edition; |
| 65 | + public static $firstPage; |
| 66 | + public static $version; |
| 67 | + public static $number; |
| 68 | + public static $archive; |
| 69 | + public static $jurisdiction; |
| 70 | + public static $keyword; |
| 71 | + |
| 72 | + public static $page; |
| 73 | + public static $pageRange; |
| 74 | + public static $volume; |
| 75 | + public static $issue; |
| 76 | + public static $opus; |
| 77 | + public static $bookLoc; # i.e., biblical "book," book III of Lord of the Rings, etc. |
| 78 | + public static $part; |
| 79 | + public static $chapterLoc; |
| 80 | + public static $folio; |
| 81 | + public static $column; |
| 82 | + public static $table; |
| 83 | + public static $figure; |
| 84 | + public static $section; |
| 85 | + public static $paragraph; |
| 86 | + public static $noteLoc; |
| 87 | + public static $footnote; |
| 88 | + public static $endnote; |
| 89 | + public static $verse; |
| 90 | + public static $line; |
| 91 | + public static $locator; |
| 92 | + |
| 93 | + public static $type; |
| 94 | + |
| 95 | + public static $link; |
| 96 | + public static $url; |
| 97 | + |
| 98 | + public static $callNumber; |
| 99 | + public static $doi; |
| 100 | + public static $isbn; |
| 101 | + |
| 102 | + public static $date; |
| 103 | + public static $accessed; |
| 104 | + public static $issued; |
| 105 | + public static $filed; |
| 106 | + |
| 107 | + |
| 108 | + public static $magicWordKeys = array( |
| 109 | + self::title => 'wc_title', |
| 110 | + self::shortTitle => 'wc_short_title', |
| 111 | + self::place => 'wc_place', |
| 112 | + self::edition => 'wc_edition', |
| 113 | + self::firstPage => 'wc_first_page', |
| 114 | + self::version => 'wc_version', |
| 115 | + self::number => 'wc_number', |
| 116 | + self::archive => 'wc_archive', |
| 117 | + self::jurisdiction => 'wc_jurisdiction', |
| 118 | + self::keyword => 'wc_keyword', |
| 119 | + |
| 120 | + self::page => 'wc_page', |
| 121 | + self::pageRange => 'wc_page_range', |
| 122 | + self::volume => 'wc_volume', |
| 123 | + self::issue => 'wc_issue', |
| 124 | + self::opus => 'wc_opus', |
| 125 | + self::bookLoc => 'wc_book_loc', # i.e., biblical "book," book III of Lord of the Rings, etc. |
| 126 | + self::part => 'wc_part', |
| 127 | + self::chapterLoc => 'wc_chapter_loc', |
| 128 | + self::folio => 'wc_folio', |
| 129 | + self::column => 'wc_column', |
| 130 | + self::table => 'wc_table', |
| 131 | + self::figure => 'wc_figure', |
| 132 | + self::section => 'wc_section', |
| 133 | + self::paragraph => 'wc_paragraph', |
| 134 | + self::noteLoc => 'wc_note_loc', |
| 135 | + self::footnote => 'wc_footnote', |
| 136 | + self::endnote => 'wc_endnote', |
| 137 | + self::verse => 'wc_verse', |
| 138 | + self::line => 'wc_line', |
| 139 | + self::locator => 'wc_locator', |
| 140 | + |
| 141 | + self::type => 'wc_type', |
| 142 | + |
| 143 | + self::link => 'wc_link', |
| 144 | + self::url => 'wc_URL', |
| 145 | + |
| 146 | + self::callNumber => 'wc_call_number', |
| 147 | + self::doi => 'wc_DOI', |
| 148 | + self::isbn => 'wc_ISBN', |
| 149 | + |
| 150 | + self::date => 'wc_date', |
| 151 | + self::accessed => 'wc_accessed', |
| 152 | + self::issued => 'wc_issued', |
| 153 | + self::filed => 'wc_filed', |
| 154 | + ); |
| 155 | + |
| 156 | + public static $substitutes = array( |
| 157 | + self::title => array( self::title, self::shortTitle ), |
| 158 | + self::shortTitle => array( self::shortTitle, self::title ), |
| 159 | + self::place => array( self::place ), |
| 160 | + self::edition => array( self::edition ), |
| 161 | + self::firstPage => array( self::firstPage ), |
| 162 | + self::version => array( self::version ), |
| 163 | + self::number => array( self::number ), |
| 164 | + self::archive => array( self::archive ), |
| 165 | + self::jurisdiction => array( self::jurisdiction ), |
| 166 | + self::keyword => array( self::keyword ), |
| 167 | + |
| 168 | + self::page => array( self::page, self::locator, self::pageRange ), |
| 169 | + self::pageRange => array( self::pageRange, self::page ), |
| 170 | + self::volume => array( self::volume ), |
| 171 | + self::issue => array( self::issue ), |
| 172 | + self::opus => array( self::opus ), |
| 173 | + self::bookLoc => array( self::bookLoc ), |
| 174 | + self::part => array( self::part ), |
| 175 | + self::chapterLoc => array( self::chapterLoc ), |
| 176 | + self::folio => array( self::folio, self::page ), |
| 177 | + self::column => array( self::column ), |
| 178 | + self::table => array( self::table ), |
| 179 | + self::figure => array( self::figure ), |
| 180 | + self::section => array( self::section ), |
| 181 | + self::paragraph => array( self::paragraph ), |
| 182 | + self::noteLoc => array( self::noteLoc, self::footnote, self::endnote ), |
| 183 | + self::footnote => array( self::footnote, self::noteLoc ), |
| 184 | + self::endnote => array( self::endnote, self::noteLoc ), |
| 185 | + self::verse => array( self::verse ), |
| 186 | + self::line => array( self::line ), |
| 187 | + self::locator => array( self::locator, self::page ), |
| 188 | + |
| 189 | + self::type => array( self::type ), |
| 190 | + |
| 191 | + self::link => array( self::link ), |
| 192 | + self::url => array( self::url ), |
| 193 | + |
| 194 | + self::callNumber => array( self::callNumber ), |
| 195 | + self::doi => array( self::doi ), |
| 196 | + self::isbn => array( self::isbn ), |
| 197 | + |
| 198 | + self::date => array( self::date, self::issued, self::filed, self::accessed ), |
| 199 | + self::accessed => array( self::accessed, self::date ), |
| 200 | + self::issued => array( self::issued, self::date ), |
| 201 | + self::filed => array( self::filed, self::date ), |
| 202 | + ); |
| 203 | + |
| 204 | + public static $attributeClasses = array( |
| 205 | + self::title => WCAttributeEnum::title, |
| 206 | + self::shortTitle => WCAttributeEnum::title, |
| 207 | + self::place => WCAttributeEnum::text, |
| 208 | + self::edition => WCAttributeEnum::text, |
| 209 | + self::firstPage => WCAttributeEnum::locator, |
| 210 | + self::version => WCAttributeEnum::text, |
| 211 | + self::number => WCAttributeEnum::text, |
| 212 | + self::archive => WCAttributeEnum::text, |
| 213 | + self::jurisdiction => WCAttributeEnum::text, |
| 214 | + self::keyword => WCAttributeEnum::text, |
| 215 | + |
| 216 | + self::page => WCAttributeEnum::locator, |
| 217 | + self::pageRange => WCAttributeEnum::locator, |
| 218 | + self::volume => WCAttributeEnum::locator, |
| 219 | + self::issue => WCAttributeEnum::locator, |
| 220 | + self::opus => WCAttributeEnum::locator, |
| 221 | + self::bookLoc => WCAttributeEnum::locator, |
| 222 | + self::part => WCAttributeEnum::locator, |
| 223 | + self::chapterLoc => WCAttributeEnum::locator, |
| 224 | + self::folio => WCAttributeEnum::locator, |
| 225 | + self::column => WCAttributeEnum::locator, |
| 226 | + self::table => WCAttributeEnum::locator, |
| 227 | + self::figure => WCAttributeEnum::locator, |
| 228 | + self::section => WCAttributeEnum::locator, |
| 229 | + self::paragraph => WCAttributeEnum::locator, |
| 230 | + self::noteLoc => WCAttributeEnum::locator, |
| 231 | + self::footnote => WCAttributeEnum::locator, |
| 232 | + self::endnote => WCAttributeEnum::locator, |
| 233 | + self::verse => WCAttributeEnum::locator, |
| 234 | + self::line => WCAttributeEnum::locator, |
| 235 | + self::locator => WCAttributeEnum::locator, |
| 236 | + |
| 237 | + self::type => WCAttributeEnum::parameter, |
| 238 | + |
| 239 | + self::link => WCAttributeEnum::text, |
| 240 | + self::url => WCAttributeEnum::text, |
| 241 | + |
| 242 | + self::callNumber => WCAttributeEnum::text, |
| 243 | + self::doi => WCAttributeEnum::text, |
| 244 | + self::isbn => WCAttributeEnum::text, |
| 245 | + |
| 246 | + self::date => WCAttributeEnum::date, |
| 247 | + self::accessed => WCAttributeEnum::date, |
| 248 | + self::issued => WCAttributeEnum::date, |
| 249 | + self::filed => WCAttributeEnum::date, |
| 250 | + ); |
| 251 | + |
| 252 | + public static $magicWordArray; |
| 253 | + public static $flipMagicWordKeys = array(); |
| 254 | + |
| 255 | + protected $attributeEnum; |
| 256 | + |
| 257 | + public static function init() { |
| 258 | + parent::init( self::$magicWordKeys, self::$substitutes, |
| 259 | + self::$magicWordArray, self::$flipMagicWordKeys ); |
| 260 | + self::$title = new self( self::title ); |
| 261 | + self::$shortTitle = new self( self::shortTitle ); |
| 262 | + self::$place = new self( self::place ); |
| 263 | + self::$edition = new self( self::edition ); |
| 264 | + self::$firstPage = new self( self::firstPage ); |
| 265 | + self::$version = new self( self::version ); |
| 266 | + self::$number = new self( self::number ); |
| 267 | + self::$archive = new self( self::archive ); |
| 268 | + self::$jurisdiction = new self( self::jurisdiction ); |
| 269 | + self::$keyword = new self( self::keyword ); |
| 270 | + |
| 271 | + self::$page = new self( self::page ); |
| 272 | + self::$pageRange = new self( self::pageRange ); |
| 273 | + self::$volume = new self( self::volume ); |
| 274 | + self::$issue = new self( self::issue ); |
| 275 | + self::$opus = new self( self::opus ); |
| 276 | + self::$bookLoc = new self( self::bookLoc ); |
| 277 | + self::$part = new self( self::part ); |
| 278 | + self::$chapterLoc = new self( self::chapterLoc ); |
| 279 | + self::$folio = new self( self::folio ); |
| 280 | + self::$column = new self( self::column ); |
| 281 | + self::$table = new self( self::table ); |
| 282 | + self::$figure = new self( self::figure ); |
| 283 | + self::$section = new self( self::section ); |
| 284 | + self::$paragraph = new self( self::paragraph ); |
| 285 | + self::$noteLoc = new self( self::noteLoc ); |
| 286 | + self::$footnote = new self( self::footnote ); |
| 287 | + self::$endnote = new self( self::endnote ); |
| 288 | + self::$verse = new self( self::verse ); |
| 289 | + self::$line = new self( self::line ); |
| 290 | + self::$locator = new self( self::locator ); |
| 291 | + |
| 292 | + self::$type = new self( self::type ); |
| 293 | + |
| 294 | + self::$link = new self( self::link ); |
| 295 | + self::$url = new self( self::url ); |
| 296 | + |
| 297 | + self::$callNumber = new self( self::callNumber ); |
| 298 | + self::$doi = new self( self::doi ); |
| 299 | + self::$isbn = new self( self::isbn ); |
| 300 | + |
| 301 | + self::$date = new self( self::date ); |
| 302 | + self::$accessed = new self( self::accessed ); |
| 303 | + self::$issued = new self( self::issued ); |
| 304 | + self::$filed = new self( self::filed ); |
| 305 | + } |
| 306 | + |
| 307 | + /** |
| 308 | + * Identity the appropriate WCAttributeEnum for this property. |
| 309 | + * |
| 310 | + * @return WCAttributeEnum |
| 311 | + */ |
| 312 | + public function getAttribute() { |
| 313 | + return new WCAttributeEnum( self::$attributeClasses[ $this->key ] ); |
| 314 | + } |
| 315 | + |
| 316 | + /** |
| 317 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 318 | + */ |
| 319 | + public function __construct( $key = self::__default ) { |
| 320 | + parent::__construct( $key ); |
| 321 | + $subs = &self::$substitutes[ $this->key ]; |
| 322 | + if ( $subs ) { |
| 323 | + $this->substituteArray = $subs; |
| 324 | + } |
| 325 | + } |
| 326 | + /** |
| 327 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 328 | + */ |
| 329 | + public static function match( $parameterText ) { |
| 330 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 331 | + if ( $id ) { |
| 332 | + return new self( self::$flipMagicWordKeys[ $id ] ); |
| 333 | + } else { |
| 334 | + return Null; |
| 335 | + } |
| 336 | + } |
| 337 | + /** |
| 338 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 339 | + */ |
| 340 | + public static function matchVariable( $parameterText ) { |
| 341 | + list( $id, $var ) = self::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 342 | + if ( $id ) { |
| 343 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $var ); |
| 344 | + } else { |
| 345 | + return Null; |
| 346 | + } |
| 347 | + } |
| 348 | + /** |
| 349 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 350 | + */ |
| 351 | + public static function matchPrefix( $parameterText ) { |
| 352 | + $id = self::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 353 | + if ( $id ) { |
| 354 | + # Remove any initial punctuation or spaces |
| 355 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 356 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 357 | + } else { |
| 358 | + return array( Null, $parameterText ); |
| 359 | + } |
| 360 | + } |
| 361 | + /** |
| 362 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 363 | + */ |
| 364 | + public static function matchPartAndNumber( $parameterText ) { |
| 365 | + # Extract number and remove number, white spaces and punctuation. |
| 366 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 367 | + $numString = $matches[0]; |
| 368 | + $num = (int) $numString; |
| 369 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 370 | + } else { |
| 371 | + $num = 1; |
| 372 | + } |
| 373 | + # Match what remains. |
| 374 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 375 | + if ( $id ) { |
| 376 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $num ); |
| 377 | + } else { |
| 378 | + return array( Null, $num ); |
| 379 | + } |
| 380 | + } |
| 381 | + |
| 382 | + |
| 383 | +} |
| 384 | +WCPropertyEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCPropertyEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 385 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCNamePartEnum.php |
— | — | @@ -0,0 +1,122 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCNamePartEnum extends WCParameterEnum { |
| 12 | + const literal = 0; |
| 13 | + const surname = 1; |
| 14 | + const given = 2; |
| 15 | + const nameLink = 3; |
| 16 | + const suffix = 4; |
| 17 | + const droppingParticle = 5; |
| 18 | + const nonDroppingParticle = 6; |
| 19 | + const __default = self::literal; |
| 20 | + |
| 21 | + public static $literal; |
| 22 | + public static $surname; |
| 23 | + public static $given; |
| 24 | + public static $nameLink; |
| 25 | + public static $suffix; |
| 26 | + public static $droppingParticle; |
| 27 | + public static $nonDroppingParticle; |
| 28 | + |
| 29 | + |
| 30 | + public static $magicWordKeys = array( |
| 31 | + self::surname => 'wc_surname', |
| 32 | + self::given => 'wc_given', |
| 33 | + self::literal => 'wc_literalname', |
| 34 | + self::nameLink => 'wc_namelink', |
| 35 | + self::suffix => 'wc_suffix', |
| 36 | + self::droppingParticle => 'wc_droppingparticle', |
| 37 | + self::nonDroppingParticle => 'wc_nondroppingparticle', |
| 38 | + ); |
| 39 | + public static $substitutes = array(); |
| 40 | + public static $magicWordArray; |
| 41 | + public static $flipMagicWordKeys = array(); |
| 42 | + |
| 43 | + public static function init() { |
| 44 | + parent::init( self::$magicWordKeys, self::$substitutes, |
| 45 | + self::$magicWordArray, self::$flipMagicWordKeys ); |
| 46 | + self::$surname = new self( self::surname ); |
| 47 | + self::$given = new self( self::given ); |
| 48 | + self::$literal = new self( self::literal ); |
| 49 | + self::$nameLink = new self( self::nameLink ); |
| 50 | + self::$suffix = new self( self::suffix ); |
| 51 | + self::$droppingParticle = new self( self::droppingParticle ); |
| 52 | + self::$nonDroppingParticle = new self( self::nonDroppingParticle ); |
| 53 | + } |
| 54 | + |
| 55 | + /** |
| 56 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 57 | + */ |
| 58 | + public function __construct( $key = self::__default ) { |
| 59 | + parent::__construct( $key ); |
| 60 | + $subs = &self::$substitutes[ $this->key ]; |
| 61 | + if ( $subs ) { |
| 62 | + $this->substituteArray = $subs; |
| 63 | + } |
| 64 | + } |
| 65 | + /** |
| 66 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 67 | + */ |
| 68 | + public static function match( $parameterText ) { |
| 69 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 70 | + if ( $id ) { |
| 71 | + return new self( self::$flipMagicWordKeys[ $id ] ); |
| 72 | + } else { |
| 73 | + return Null; |
| 74 | + } |
| 75 | + } |
| 76 | + /** |
| 77 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 78 | + */ |
| 79 | + public static function matchVariable( $parameterText ) { |
| 80 | + list( $id, $var ) = self::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 81 | + if ( $id ) { |
| 82 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $var ); |
| 83 | + } else { |
| 84 | + return Null; |
| 85 | + } |
| 86 | + } |
| 87 | + /** |
| 88 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 89 | + */ |
| 90 | + public static function matchPrefix( $parameterText ) { |
| 91 | + $id = self::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 92 | + if ( $id ) { |
| 93 | + # Remove any initial punctuation or spaces |
| 94 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 95 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 96 | + } else { |
| 97 | + return array( Null, $parameterText ); |
| 98 | + } |
| 99 | + } |
| 100 | + /** |
| 101 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 102 | + */ |
| 103 | + public static function matchPartAndNumber( $parameterText ) { |
| 104 | + # Extract number and remove number, white spaces and punctuation. |
| 105 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 106 | + $numString = $matches[0]; |
| 107 | + $num = (int) $numString; |
| 108 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 109 | + } else { |
| 110 | + $num = 1; |
| 111 | + } |
| 112 | + # Match what remains. |
| 113 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 114 | + if ( $id ) { |
| 115 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $num ); |
| 116 | + } else { |
| 117 | + return array( Null, $num ); |
| 118 | + } |
| 119 | + } |
| 120 | + |
| 121 | + |
| 122 | +} |
| 123 | +WCNamePartEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCNamePartEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 124 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCDateTermsEnum.php |
— | — | @@ -0,0 +1,145 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Magic word enumerations |
| 13 | + */ |
| 14 | +class WCDateTermsEnum extends WCParameterEnum { |
| 15 | + const nothing = 0; |
| 16 | + const spring = 1; |
| 17 | + const summer = 2; |
| 18 | + const autumn = 3; |
| 19 | + const winter = 4; |
| 20 | + const AD = 5; |
| 21 | + const BC = 6; |
| 22 | + const yearTerm = 7; |
| 23 | + const monthTerm = 8; |
| 24 | + const dayTerm = 9; |
| 25 | + const circa = 10; |
| 26 | + const number = 11; |
| 27 | + const namedMonth = 12; |
| 28 | + |
| 29 | + public static $nothing; |
| 30 | + public static $spring; |
| 31 | + public static $summer; |
| 32 | + public static $autumn; |
| 33 | + public static $winter; |
| 34 | + public static $AD; |
| 35 | + public static $BC; |
| 36 | + public static $yearTerm; |
| 37 | + public static $monthTerm; |
| 38 | + public static $dayTerm; |
| 39 | + public static $circa; |
| 40 | + public static $number; |
| 41 | + public static $namedMonth; |
| 42 | + |
| 43 | + public static $magicWordKeys = array( |
| 44 | + self::spring => 'wc_spring', |
| 45 | + self::summer => 'wc_summer', |
| 46 | + self::autumn => 'wc_autumn', |
| 47 | + self::winter => 'wc_winter', |
| 48 | + self::AD => 'wc_ad_magic_word', |
| 49 | + self::BC => 'wc_bc_magic_word', |
| 50 | + self::yearTerm => 'wc_year', |
| 51 | + self::monthTerm => 'wc_month', |
| 52 | + self::dayTerm => 'wc_day', |
| 53 | + self::circa => 'wc_circa', |
| 54 | +# self::rangeDelimeter => 'wc_range', |
| 55 | + ); |
| 56 | + public static $substitutes = array(); |
| 57 | + public static $magicWordArray; |
| 58 | + public static $flipMagicWordKeys = array(); |
| 59 | + |
| 60 | + public static function init() { |
| 61 | + parent::init( self::$magicWordKeys, self::$substitutes, |
| 62 | + self::$magicWordArray, self::$flipMagicWordKeys ); |
| 63 | + self::$nothing = new self( self::nothing ); |
| 64 | + self::$spring = new self( self::spring ); |
| 65 | + self::$summer = new self( self::summer ); |
| 66 | + self::$autumn = new self( self::autumn ); |
| 67 | + self::$winter = new self( self::winter ); |
| 68 | + self::$AD = new self( self::AD ); |
| 69 | + self::$BC = new self( self::BC ); |
| 70 | + self::$yearTerm = new self( self::yearTerm ); |
| 71 | + self::$monthTerm = new self( self::monthTerm ); |
| 72 | + self::$dayTerm = new self( self::dayTerm ); |
| 73 | + self::$circa = new self( self::circa ); |
| 74 | + self::$number = new self( self::number ); |
| 75 | + self::$namedMonth = new self( self::namedMonth ); |
| 76 | + } |
| 77 | + |
| 78 | + /** |
| 79 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 80 | + */ |
| 81 | + public function __construct( $key = self::__default ) { |
| 82 | + parent::__construct( $key ); |
| 83 | + $subs = &self::$substitutes[ $this->key ]; |
| 84 | + if ( $subs ) { |
| 85 | + $this->substituteArray = $subs; |
| 86 | + } |
| 87 | + } |
| 88 | + /** |
| 89 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 90 | + */ |
| 91 | + public static function match( $parameterText ) { |
| 92 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 93 | + if ( $id ) { |
| 94 | + return new self( self::$flipMagicWordKeys[ $id ] ); |
| 95 | + } else { |
| 96 | + return Null; |
| 97 | + } |
| 98 | + } |
| 99 | + /** |
| 100 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 101 | + */ |
| 102 | + public static function matchVariable( $parameterText ) { |
| 103 | + list( $id, $var ) = self::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 104 | + if ( $id ) { |
| 105 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $var ); |
| 106 | + } else { |
| 107 | + return Null; |
| 108 | + } |
| 109 | + } |
| 110 | + /** |
| 111 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 112 | + */ |
| 113 | + public static function matchPrefix( $parameterText ) { |
| 114 | + $id = self::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 115 | + if ( $id ) { |
| 116 | + # Remove any initial punctuation or spaces |
| 117 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 118 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 119 | + } else { |
| 120 | + return array( Null, $parameterText ); |
| 121 | + } |
| 122 | + } |
| 123 | + /** |
| 124 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 125 | + */ |
| 126 | + public static function matchPartAndNumber( $parameterText ) { |
| 127 | + # Extract number and remove number, white spaces and punctuation. |
| 128 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 129 | + $numString = $matches[0]; |
| 130 | + $num = (int) $numString; |
| 131 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 132 | + } else { |
| 133 | + $num = 1; |
| 134 | + } |
| 135 | + # Match what remains. |
| 136 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 137 | + if ( $id ) { |
| 138 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $num ); |
| 139 | + } else { |
| 140 | + return array( Null, $num ); |
| 141 | + } |
| 142 | + } |
| 143 | + |
| 144 | + |
| 145 | +} |
| 146 | +WCDateTermsEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCDateTermsEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 147 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCSeasonEnum.php |
— | — | @@ -0,0 +1,112 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Magic word enumerations |
| 13 | + */ |
| 14 | +class WCSeasonEnum extends WCParameterEnum { |
| 15 | + const spring = 0; |
| 16 | + const summer = 1; |
| 17 | + const autumn = 2; |
| 18 | + const winter = 3; |
| 19 | + const __default = self::spring; |
| 20 | + |
| 21 | + public static $spring; |
| 22 | + public static $summer; |
| 23 | + public static $autumn; |
| 24 | + public static $winter; |
| 25 | + |
| 26 | + public static $magicWordKeys = array( |
| 27 | + self::spring => 'wc_spring', |
| 28 | + self::summer => 'wc_summer', |
| 29 | + self::autumn => 'wc_autumn', |
| 30 | + self::winter => 'wc_winter', |
| 31 | + ); |
| 32 | + public static $substitutes = array(); |
| 33 | + public static $magicWordArray; |
| 34 | + public static $flipMagicWordKeys = array(); |
| 35 | + |
| 36 | + public static function init() { |
| 37 | + parent::init( self::$magicWordKeys, self::$substitutes, |
| 38 | + self::$magicWordArray, self::$flipmagicWordKeys ); |
| 39 | + self::$spring = new self( self::spring ); |
| 40 | + self::$summer = new self( self::summer ); |
| 41 | + self::$autumn = new self( self::autumn ); |
| 42 | + self::$winter = new self( self::winter ); |
| 43 | + } |
| 44 | + |
| 45 | + /** |
| 46 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 47 | + */ |
| 48 | + public function __construct( $key = self::__default ) { |
| 49 | + parent::__construct( $key ); |
| 50 | + $subs = &self::$substitutes[ $this->key ]; |
| 51 | + if ( $subs ) { |
| 52 | + $this->substituteArray = $subs; |
| 53 | + } |
| 54 | + } |
| 55 | + /** |
| 56 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 57 | + */ |
| 58 | + public static function match( $parameterText ) { |
| 59 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 60 | + if ( $id ) { |
| 61 | + return new self( self::$flipMagicWordKeys[ $id ] ); |
| 62 | + } else { |
| 63 | + return Null; |
| 64 | + } |
| 65 | + } |
| 66 | + /** |
| 67 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 68 | + */ |
| 69 | + public static function matchVariable( $parameterText ) { |
| 70 | + list( $id, $var ) = self::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 71 | + if ( $id ) { |
| 72 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $var ); |
| 73 | + } else { |
| 74 | + return Null; |
| 75 | + } |
| 76 | + } |
| 77 | + /** |
| 78 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 79 | + */ |
| 80 | + public static function matchPrefix( $parameterText ) { |
| 81 | + $id = self::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 82 | + if ( $id ) { |
| 83 | + # Remove any initial punctuation or spaces |
| 84 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 85 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 86 | + } else { |
| 87 | + return array( Null, $parameterText ); |
| 88 | + } |
| 89 | + } |
| 90 | + /** |
| 91 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 92 | + */ |
| 93 | + public static function matchPartAndNumber( $parameterText ) { |
| 94 | + # Extract number and remove number, white spaces and punctuation. |
| 95 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 96 | + $numString = $matches[0]; |
| 97 | + $num = (int) $numString; |
| 98 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 99 | + } else { |
| 100 | + $num = 1; |
| 101 | + } |
| 102 | + # Match what remains. |
| 103 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 104 | + if ( $id ) { |
| 105 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $num ); |
| 106 | + } else { |
| 107 | + return array( Null, $num ); |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + |
| 112 | +} |
| 113 | +WCSeasonEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCSeasonEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 114 | + native |
Index: trunk/extensions/WikiCitation/includes/parameters/WCScopeEnum.php |
— | — | @@ -0,0 +1,119 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCScopeEnum extends WCParameterEnum { |
| 12 | + const work = 0; |
| 13 | + const container = 1; |
| 14 | + const series = 2; |
| 15 | + const original = 3; |
| 16 | + const subject = 4; |
| 17 | + const __default = self::work; |
| 18 | + |
| 19 | + public static $work; |
| 20 | + public static $container; |
| 21 | + public static $series; |
| 22 | + public static $original; |
| 23 | + public static $subject; |
| 24 | + |
| 25 | + public static $magicWordKeys = array( |
| 26 | + self::work => 'wc_work', |
| 27 | + self::container => 'wc_container', |
| 28 | + self::series => 'wc_series', |
| 29 | + self::original => 'wc_original', |
| 30 | + self::subject => 'wc_subject' |
| 31 | + ); |
| 32 | + public static $substitutes = array ( |
| 33 | + self::work => array( self::work, self::original, self::subject ), |
| 34 | + self::container => array( self::container, self::series ), |
| 35 | + self::series => array( self::series, self::container ), |
| 36 | + self::original => array( self::original ), |
| 37 | + self::subject => array( self::subject ) |
| 38 | + ); |
| 39 | + public static $magicWordArray; |
| 40 | + public static $flipMagicWordKeys = array(); |
| 41 | + |
| 42 | + public static function init() { |
| 43 | + parent::init( self::$magicWordKeys, self::$substitutes, |
| 44 | + self::$magicWordArray, self::$flipMagicWordKeys ); |
| 45 | + self::$work = new self( self::work ); |
| 46 | + self::$container = new self( self::container ); |
| 47 | + self::$series = new self( self::series ); |
| 48 | + self::$original = new self( self::original ); |
| 49 | + self::$subject = new self( self::subject ); |
| 50 | + } |
| 51 | + |
| 52 | + /** |
| 53 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 54 | + */ |
| 55 | + public function __construct( $key = self::__default ) { |
| 56 | + parent::__construct( $key ); |
| 57 | + $subs = &self::$substitutes[ $this->key ]; |
| 58 | + if ( $subs ) { |
| 59 | + $this->substituteArray = $subs; |
| 60 | + } |
| 61 | + } |
| 62 | + /** |
| 63 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 64 | + */ |
| 65 | + public static function match( $parameterText ) { |
| 66 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 67 | + if ( $id ) { |
| 68 | + return new self( self::$flipMagicWordKeys[ $id ] ); |
| 69 | + } else { |
| 70 | + return Null; |
| 71 | + } |
| 72 | + } |
| 73 | + /** |
| 74 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 75 | + */ |
| 76 | + public static function matchVariable( $parameterText ) { |
| 77 | + list( $id, $var ) = self::$magicWordArray->matchVariableStartToEnd( $parameterText ); |
| 78 | + if ( $id ) { |
| 79 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $var ); |
| 80 | + } else { |
| 81 | + return Null; |
| 82 | + } |
| 83 | + } |
| 84 | + /** |
| 85 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 86 | + */ |
| 87 | + public static function matchPrefix( $parameterText ) { |
| 88 | + $id = self::$magicWordArray->matchStartAndRemove( $parameterText ); |
| 89 | + if ( $id ) { |
| 90 | + # Remove any initial punctuation or spaces |
| 91 | + $parameterText = preg_replace( '/^[\p{P}\p{Z}\p{C}]+/u', '', $parameterText ); |
| 92 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $parameterText ); |
| 93 | + } else { |
| 94 | + return array( Null, $parameterText ); |
| 95 | + } |
| 96 | + } |
| 97 | + /** |
| 98 | + * Delete when moving to PHP 3.3 and use late static binding in WCParameterEnum. |
| 99 | + */ |
| 100 | + public static function matchPartAndNumber( $parameterText ) { |
| 101 | + # Extract number and remove number, white spaces and punctuation. |
| 102 | + if ( preg_match( '/\d+/u', $parameterText, $matches ) ) { |
| 103 | + $numString = $matches[0]; |
| 104 | + $num = (int) $numString; |
| 105 | + $parameterText = preg_replace( '/' . $numString . '|[\p{P}\p{Z}\p{C}]+/uS', '', $parameterText ); |
| 106 | + } else { |
| 107 | + $num = 1; |
| 108 | + } |
| 109 | + # Match what remains. |
| 110 | + $id = self::$magicWordArray->matchStartToEnd( $parameterText ); |
| 111 | + if ( $id ) { |
| 112 | + return array( new self( self::$flipMagicWordKeys[ $id ] ), $num ); |
| 113 | + } else { |
| 114 | + return array( Null, $num ); |
| 115 | + } |
| 116 | + } |
| 117 | + |
| 118 | + |
| 119 | +} |
| 120 | +WCScopeEnum::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/parameters/WCScopeEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 121 | + native |
Property changes on: trunk/extensions/WikiCitation/includes/parameters |
___________________________________________________________________ |
Added: bugtraq:number |
2 | 122 | + true |
Index: trunk/extensions/WikiCitation/includes/WCEnum.php |
— | — | @@ -0,0 +1,46 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * An enum class. |
| 13 | + */ |
| 14 | +abstract class WCEnum /* extends SplEnum {PHP 5.3} */ { |
| 15 | + |
| 16 | + /** |
| 17 | + * Default value if none is specified. |
| 18 | + */ |
| 19 | + const __default = 0; |
| 20 | + |
| 21 | + |
| 22 | + /** |
| 23 | + * An integer key. |
| 24 | + * @var integer |
| 25 | + */ |
| 26 | + public $key; |
| 27 | + |
| 28 | + |
| 29 | + /** |
| 30 | + * Constructor. |
| 31 | + * Takes a unique integer key, which should be defined as a class constant. |
| 32 | + * @param integer $key |
| 33 | + */ |
| 34 | + public function __construct( $key = self::__default ) { |
| 35 | + $this->key = $key; |
| 36 | + } |
| 37 | + |
| 38 | + |
| 39 | + /** |
| 40 | + * The string value, unless overridden, is the name of the constant. |
| 41 | + * @return string |
| 42 | + */ |
| 43 | + public function __toString() { |
| 44 | + $object = new ReflectionClass( $this ); |
| 45 | + return array_search( $this->key, $object->getConstants() ); |
| 46 | + } |
| 47 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/WCEnum.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 48 | + native |
Index: trunk/extensions/WikiCitation/includes/WCSection.php |
— | — | @@ -0,0 +1,209 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCSection { |
| 12 | + |
| 13 | + public $citationStyle, $citationType; |
| 14 | + |
| 15 | + protected static $citeStyleAttributeWords, $typeAttributeWords; |
| 16 | + |
| 17 | + protected $cites = array(); |
| 18 | + |
| 19 | + protected $notes = array(); |
| 20 | + |
| 21 | + protected $noteCount = 1; |
| 22 | + |
| 23 | + protected $endnoteMarker; |
| 24 | + |
| 25 | + protected $subsection; |
| 26 | + |
| 27 | + protected $styleHTML; |
| 28 | + |
| 29 | + |
| 30 | + /** |
| 31 | + * Static initializer. |
| 32 | + */ |
| 33 | + public static function init() { |
| 34 | + $citeStyleMW = MagicWord::get( 'wc_citestyle_attrib' ); |
| 35 | + self::$citeStyleAttributeWords = $citeStyleMW->getSynonyms(); |
| 36 | + $typeMW = MagicWord::get( 'wc_type_attrib' ); |
| 37 | + self::$typeAttributeWords = $typeMW->getSynonyms(); |
| 38 | + } |
| 39 | + |
| 40 | + |
| 41 | + /** |
| 42 | + * Get a new WCSection object based on HTML arguments. |
| 43 | + * @param array $args = "citeStyle" or "type" (or equivalent foreign words) |
| 44 | + * @param WCStyle $defaultStyle |
| 45 | + * @param WCCitationTypeEnum $defaultType |
| 46 | + * @return WCSection |
| 47 | + */ |
| 48 | + public static function getSection( array $args, $defaultStyle, $defaultType ) { |
| 49 | + foreach( $args as $attrib => $value ) { |
| 50 | + if ( in_array( $attrib, self::$citeStyleAttributeWords ) ) { |
| 51 | + $styleClassName = WCArgumentReader::matchStyleClassName( $value ); |
| 52 | + } elseif ( in_array( $attrib, self::$typeAttributeWords ) ) { |
| 53 | + $citationTypeID = WCCitationTypeEnum::match( $value ); |
| 54 | + if ( isset( $citationTypeID ) ) { |
| 55 | + $citationType = new WCCitationTypeEnum( $citationTypeID ); |
| 56 | + } |
| 57 | + } elseif ( $args[ 'style' ] ) { |
| 58 | + $this->styleHTML = ' style="' . $args[ 'style' ] . '"'; |
| 59 | + } elseif ( $args[ 'id' ] ) { |
| 60 | + $this->styleHTML = ' id="' . $args[ 'id' ] . '"'; |
| 61 | + } |
| 62 | + } |
| 63 | + if ( isset( $styleClassName ) ) { |
| 64 | + # See if a specific style object has already been defined, and if so, use it. |
| 65 | + $styleObject = WCArticle::getStyle( $styleClassName ); |
| 66 | + } else { |
| 67 | + # Use default citation style. |
| 68 | + $styleObject = $defaultStyle; |
| 69 | + } |
| 70 | + if ( isset( $citationType ) ) { |
| 71 | + return new WCSection( $styleObject, $citationType ); |
| 72 | + } else { |
| 73 | + return new WCSection( $styleObject, $defaultType ); |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + /** |
| 78 | + * Constructor. |
| 79 | + * WCSection objects will normally be created through WCSection::getSection(...). |
| 80 | + * @param WCStyle $style |
| 81 | + * @param WCCitationTypeEnum $type |
| 82 | + */ |
| 83 | + public function __construct( WCStyle $style, WCCitationTypeEnum $type ) { |
| 84 | + $this->citationStyle = $style; |
| 85 | + $this->citationType = $type; |
| 86 | + } |
| 87 | + |
| 88 | + |
| 89 | + /** |
| 90 | + * Add an inline citation (not within an endnote). |
| 91 | + * @param integer $key |
| 92 | + * @param integer $distance |
| 93 | + */ |
| 94 | + public function addInlineCite( $key, $citation ) { |
| 95 | + $this->cites[] = $key; |
| 96 | + # If citation length was not explicitly defined, it will be: |
| 97 | + # long if the first citation in the section to that reference, short otherwise |
| 98 | + if ( is_null ( $citation->citationLength) ) { |
| 99 | + $citation->citationLength = |
| 100 | + $citation->distance === 0 ? WCCitationLengthEnum::$long : WCCitationLengthEnum::$short; |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + |
| 105 | + /** |
| 106 | + * Create a new footnote. |
| 107 | + * @param array $args |
| 108 | + */ |
| 109 | + public function startNote( array $args ) { |
| 110 | + $this->notes[ $this->noteCount ] = WCNote::getNote( $args, $this->citationStyle ); |
| 111 | + } |
| 112 | + |
| 113 | + |
| 114 | + /** |
| 115 | + * Add a citation within an endnote. |
| 116 | + * @param int $key |
| 117 | + * @param boolean $isNew |
| 118 | + * @param WCArticle $article |
| 119 | + */ |
| 120 | + public function addNoteCite( $key, WCCitation $citation ) { |
| 121 | + $this->notes[ $this->noteCount ]->addNoteCite( $key, $citation ); |
| 122 | + } |
| 123 | + |
| 124 | + |
| 125 | + /** |
| 126 | + * Store the text of the current footnote and return a marker for the subscript number. |
| 127 | + * @param string $text |
| 128 | + * @return string |
| 129 | + */ |
| 130 | + public function finishNote( $text ) { |
| 131 | + return $this->notes[ $this->noteCount ]->getSuperscript( $text, $this->noteCount++ ); |
| 132 | + } |
| 133 | + |
| 134 | + |
| 135 | + /** |
| 136 | + * Parse endmotes and Add an endnote citation. |
| 137 | + * @return string |
| 138 | + */ |
| 139 | + public function addEndnotes() { |
| 140 | + $marker = 'EwC-' . mt_rand(); |
| 141 | + $this->endnoteMarker = $marker; |
| 142 | + return $marker; |
| 143 | + } |
| 144 | + |
| 145 | + |
| 146 | + /** |
| 147 | + * Render a section: replace markers for citations, endnote numbers, and endnotes. |
| 148 | + * @param unknown_type $text |
| 149 | + * @param array ( int => WCCitation ) |
| 150 | + * @param boolean bibliographyExists |
| 151 | + */ |
| 152 | + public function render( &$text, $citations, $bibliographyExists ) { |
| 153 | + |
| 154 | + /** |
| 155 | + * Replace inline citation markers. |
| 156 | + */ |
| 157 | + if ( $this->cites ) { |
| 158 | + $currentStyle = $this->citationStyle; |
| 159 | + $currentType = $this->citationType; |
| 160 | + $textCitations = $markers = array(); |
| 161 | + foreach( $this->cites as $key ) { |
| 162 | + $citation = $citations[ $key ]; |
| 163 | + |
| 164 | + # If an explicit style has been defined for $key, use it; otherwise, use the previous style. |
| 165 | + if ( isset( $citation->style ) ) { |
| 166 | + $currentStyle = $citation->style; |
| 167 | + } else { |
| 168 | + $citation->style = $currentStyle; |
| 169 | + } |
| 170 | + if ( isset( $citation->citationType ) ) { |
| 171 | + $currentType = $citation->citationType; |
| 172 | + } else { |
| 173 | + $citation->citationType = $currentType; |
| 174 | + } |
| 175 | + |
| 176 | + list( $textCitation, ) = $citation->render(); |
| 177 | + $pos = strpos( $text, $citation->marker ); |
| 178 | + if ( $pos !== false ) { |
| 179 | + $text = substr_replace( $text, $textCitation, $pos, strlen( $citation->marker ) ); |
| 180 | + } |
| 181 | + } |
| 182 | + } |
| 183 | + |
| 184 | + /** |
| 185 | + * Replace endnote marker with rendered endnotes. |
| 186 | + */ |
| 187 | + if ( $this->endnoteMarker ) { |
| 188 | + if ( $this->notes ) { |
| 189 | + $endnoteText = '<ol class="endnotes"' . $this->styleHTML . '>' . PHP_EOL; |
| 190 | + foreach( $this->notes as $key => $note ) { |
| 191 | + $endnoteText .= $note->render( $bibliographyExists ); |
| 192 | + } |
| 193 | + $endnoteText .= '</ol>'; |
| 194 | + } else { |
| 195 | + $endnoteText = ''; |
| 196 | + } |
| 197 | + $pos = strpos( $text, $this->endnoteMarker ); |
| 198 | + if ( $pos !== false ) { |
| 199 | + $text = substr_replace( $text, $endnoteText, $pos, strlen( $this->endnoteMarker ) ); |
| 200 | + } |
| 201 | + } |
| 202 | + } |
| 203 | + |
| 204 | +} |
| 205 | + |
| 206 | + |
| 207 | +/** |
| 208 | + * Static initializer. |
| 209 | + */ |
| 210 | +WCBibliography::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/WCSection.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 211 | + native |
Index: trunk/extensions/WikiCitation/includes/WCArgumentReader.php |
— | — | @@ -0,0 +1,249 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Part of WikiCitation extension for Mediawiki. |
| 6 | + * |
| 7 | + * @ingroup WikiCitation |
| 8 | + * @file |
| 9 | + */ |
| 10 | + |
| 11 | +/** |
| 12 | + * Factory function, which parses the raw parser function arguments upon construction. |
| 13 | + * Class createWCStyle instantiates an appropriate child class based on the first |
| 14 | + * parameter after the colon. |
| 15 | + */ |
| 16 | +class WCArgumentReader { |
| 17 | + |
| 18 | + /** |
| 19 | + * citation type |
| 20 | + * |
| 21 | + * note, biblio, or inline |
| 22 | + * @var WCCitationTypeEnum |
| 23 | + */ |
| 24 | + public $citationType; |
| 25 | + |
| 26 | + /** |
| 27 | + * Citation length |
| 28 | + * |
| 29 | + * long or short |
| 30 | + * @var WCCitationLengthEnum |
| 31 | + */ |
| 32 | + public $citationLength; |
| 33 | + |
| 34 | + /** |
| 35 | + * Array of flag values. |
| 36 | + * @var array |
| 37 | + */ |
| 38 | + public $flags = array(); |
| 39 | + /** |
| 40 | + * Array of parameters values keyed to parameter names. |
| 41 | + * @var array |
| 42 | + */ |
| 43 | + public $parameters = array(); |
| 44 | + |
| 45 | + # The name of the style class (e.g., WCChicagoStyle) |
| 46 | + private $styleClassName; |
| 47 | + |
| 48 | + # private data |
| 49 | + private $parser; |
| 50 | + private $frame; |
| 51 | + private $args; |
| 52 | + private static $styleMagicWords; |
| 53 | + |
| 54 | + /** |
| 55 | + * Static initializer. |
| 56 | + */ |
| 57 | + public static function init() { |
| 58 | + global $wgWCCitationStyles; |
| 59 | + $citationStyleList = array_keys( $wgWCCitationStyles ); |
| 60 | + self::$styleMagicWords = new MagicWordArray( $citationStyleList ); |
| 61 | + } |
| 62 | + |
| 63 | + /** |
| 64 | + * Constructor. Parses the arguments, recognizes the citation style, |
| 65 | + * and stores flags and parameters internally. |
| 66 | + * @param PPFrame_DOM $frame |
| 67 | + * @param array $args |
| 68 | + */ |
| 69 | + public function __construct(Parser $parser, PPFrame_DOM $frame, array $args) { |
| 70 | + $this->parser = $parser; |
| 71 | + $this->frame = $frame; |
| 72 | + $this->args = $args; |
| 73 | + |
| 74 | + $this->parseArguments(); |
| 75 | + } |
| 76 | + |
| 77 | + /** |
| 78 | + * Get the name of the style class. |
| 79 | + * @return string|boolean |
| 80 | + */ |
| 81 | + public function getStyleClassName() { |
| 82 | + return $this->styleClassName; |
| 83 | + } |
| 84 | + |
| 85 | + |
| 86 | + public function isEmpty() { |
| 87 | + return empty( $this->parameters ); |
| 88 | + } |
| 89 | + |
| 90 | + |
| 91 | + public function getCitationType() { |
| 92 | + return $this->citationType; |
| 93 | + } |
| 94 | + |
| 95 | + |
| 96 | + public function getCitationLength() { |
| 97 | + return $this->citationLength; |
| 98 | + } |
| 99 | + |
| 100 | + |
| 101 | + /** |
| 102 | + * Parse options from $this->mArgs. |
| 103 | + * Sets $this->citationStyle, $this->flags, and $this->parameters |
| 104 | + * @internal |
| 105 | + */ |
| 106 | + private function parseArguments() { |
| 107 | + |
| 108 | + /** |
| 109 | + * Parameter after the colon designates an explicit citation style. |
| 110 | + * $this->arg[0] is a string, while the other arguments are of type |
| 111 | + * PPNode_DOM. It is expanded anyway, in case the Parser class is |
| 112 | + * revised in the future. See documentation for |
| 113 | + * Parser::setFunctionHook(). |
| 114 | + * @var |
| 115 | + */ |
| 116 | + $firstArg = reset( $this->args ); |
| 117 | + $style = trim( $this->frame->expand( $firstArg ) ); |
| 118 | + $this->styleClassName = $this->matchStyleClassName( $style ); |
| 119 | + |
| 120 | + # Check args for initial flags after the colon, but prior to any named parameters. |
| 121 | + while (( $arg = next( $this->args ) ) !== False) { |
| 122 | + list( $var, $value ) = $this->parseArgument( $arg ); |
| 123 | + if ($var) { |
| 124 | + $this->parameters[$var] = $value; |
| 125 | + break; |
| 126 | + } |
| 127 | + $this->flags[] = $value; |
| 128 | + } |
| 129 | + |
| 130 | + # Match the flags and set defaults. |
| 131 | + $this->matchFlags(); |
| 132 | + |
| 133 | + # From now on, only look for named parameters. |
| 134 | + while (( $arg = next( $this->args ) ) !== False) { |
| 135 | + list( $var, $value ) = $this->parseArgument($arg); |
| 136 | + if (!$var) { |
| 137 | + continue; |
| 138 | + } |
| 139 | + $this->parameters[$var] = $value; |
| 140 | + } |
| 141 | + } |
| 142 | + |
| 143 | + /** |
| 144 | + * Parses an argument to extract a variable and/or a value |
| 145 | + * |
| 146 | + * @internal |
| 147 | + * @param PPNode_DOM $arg Argument |
| 148 | + * @return array a tuple of the variable (if exists) its corresponding value |
| 149 | + */ |
| 150 | + protected function parseArgument( PPNode_DOM $arg ) { |
| 151 | + /* if ( $arg instanceof PPNode_DOM ) { # See below: */ |
| 152 | + $bits = $arg->splitArg(); |
| 153 | + $index = $bits['index']; |
| 154 | + if ($index === '') { |
| 155 | + # Found |
| 156 | + $var = trim($this->frame->expand($bits['name'])); |
| 157 | + $value = trim($this->frame->expand($bits['value'])); |
| 158 | + } else { # Not found |
| 159 | + $var = Null; |
| 160 | + $value = trim($this->frame->expand($arg)); |
| 161 | + } |
| 162 | + /* This commented-out code would be required if $this->arg[0] |
| 163 | + * were passed to this function, since that argument is pre-expanded |
| 164 | + * and not a PPNode_DOM object, at least in the version of MediaWiki |
| 165 | + * when this was written. |
| 166 | + } else { |
| 167 | + $parts = array_map('trim', explode( '=', $arg, 2 ) ); |
| 168 | + if ( count( $parts ) == 2 ) { |
| 169 | + # Found "=" |
| 170 | + $var = $parts[ 0 ]; |
| 171 | + $value = $parts[ 1 ]; |
| 172 | + } else { |
| 173 | + # Not found |
| 174 | + $var = NULL; |
| 175 | + $value = $arg; |
| 176 | + } |
| 177 | + } |
| 178 | + */ |
| 179 | + return array( $var, $value ); |
| 180 | + } |
| 181 | + |
| 182 | + |
| 183 | + protected static function matchStyleClassName( $styleText ) { |
| 184 | + if ( $styleText ) { |
| 185 | + $styleID = self::$styleMagicWords->matchStartToEnd( $styleText ); |
| 186 | + if ( $styleID === False && $wikiCitationValidateArguments ) { |
| 187 | + throw new WCException( 'wc-style-not-recognized', $styleText ); |
| 188 | + } |
| 189 | + global $wgWCCitationStyles; |
| 190 | + return $wgWCCitationStyles[ $styleID ]; |
| 191 | + } else { |
| 192 | + return Null; |
| 193 | + } |
| 194 | + } |
| 195 | + |
| 196 | + |
| 197 | + /** |
| 198 | + * Recognize and process the flags. |
| 199 | + * |
| 200 | + * @global type $wikiCitationValidateArguments |
| 201 | + */ |
| 202 | + protected function matchFlags() { |
| 203 | + global $wikiCitationValidateArguments; |
| 204 | + foreach( $this->flags as $flag ) { |
| 205 | + # Match flag for citation type. |
| 206 | + $citationType = WCCitationTypeEnum::match( $flag ); |
| 207 | + if ( $citationType ) { |
| 208 | + $this->citationType = $citationType; |
| 209 | + continue; |
| 210 | + } |
| 211 | + # Match flag for citation length. |
| 212 | + $citationLength = WCCitationLengthEnum::match( $flag ); |
| 213 | + if ( $citationLength ) { |
| 214 | + $this->citationLength = $citationLength; |
| 215 | + continue; |
| 216 | + } |
| 217 | + # If the function encounters an unknown flag, an error is thrown. |
| 218 | + if ( $wikiCitationValidateArguments ) { |
| 219 | + throw new WCException( 'wc-flag-unknown', $flag ); |
| 220 | + } |
| 221 | + } |
| 222 | + |
| 223 | + # Throw exception for explicit "short bibliography" citation. |
| 224 | + if ( isset( $this->citationLength ) |
| 225 | + && isset( $this->citationLength ) |
| 226 | + && $this->citationLength->key == WCCitationLengthEnum::short |
| 227 | + && $this->citationType->key == WCCitationTypeEnum::biblio |
| 228 | + && $wikiCitationValidateArguments ) |
| 229 | + { |
| 230 | + if ( $wikiCitationValidateArguments) { |
| 231 | + throw new WCException( |
| 232 | + 'wc-incompatible-flags', |
| 233 | + new WCCitationLengthEnum( WCCitationLengthEnum::short ), |
| 234 | + new WCCitationTypeEnum( WCCitationTypeEnum::biblio ) |
| 235 | + ); |
| 236 | + } else { |
| 237 | + $this->citationLength->key = WCCitationLengthEnum::long; |
| 238 | + } |
| 239 | + } |
| 240 | + |
| 241 | + } |
| 242 | + |
| 243 | + |
| 244 | +} |
| 245 | + |
| 246 | + |
| 247 | +/** |
| 248 | + * Static initializer. |
| 249 | + */ |
| 250 | +WCArgumentReader::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/WCArgumentReader.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 251 | + native |
Index: trunk/extensions/WikiCitation/includes/WCNote.php |
— | — | @@ -0,0 +1,153 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCNote { |
| 12 | + |
| 13 | + public $citationStyle, $citationType; |
| 14 | + |
| 15 | + public $marker; |
| 16 | + |
| 17 | + public $number; |
| 18 | + |
| 19 | + protected $cites = array(); |
| 20 | + |
| 21 | + protected static $citeStyleAttributeWords, $typeAttributeWords; |
| 22 | + |
| 23 | + protected $style, $type; |
| 24 | + |
| 25 | + protected $text; |
| 26 | + |
| 27 | + /** |
| 28 | + * Static initializer. |
| 29 | + */ |
| 30 | + public static function init() { |
| 31 | + $citeStyleMW = MagicWord::get( 'wc_citestyle_attrib' ); |
| 32 | + self::$citeStyleAttributeWords = $citeStyleMW->getSynonyms(); |
| 33 | + $typeMW = MagicWord::get( 'wc_type_attrib' ); |
| 34 | + self::$typeAttributeWords = $typeMW->getSynonyms(); |
| 35 | + } |
| 36 | + |
| 37 | + /** |
| 38 | + * Get a new WCNote object based on HTML arguments. |
| 39 | + * @param array $args = "citeStyle" or "type" (or equivalent foreign words) |
| 40 | + * @param WCStyle $defaultStyle |
| 41 | + * @param WCCitationTypeEnum $defaultType |
| 42 | + * @return WCSection |
| 43 | + */ |
| 44 | + public static function getNote( array $args, $defaultStyle ) { |
| 45 | + foreach( $args as $attrib => $value ) { |
| 46 | + if ( in_array( $attrib, self::$citeStyleAttributeWords ) ) { |
| 47 | + $styleClassName = WCArgumentReader::matchStyleClassName( $value ); |
| 48 | + } elseif ( in_array( $attrib, self::$typeAttributeWords ) ) { |
| 49 | + $citationTypeID = WCCitationTypeEnum::match( $value ); |
| 50 | + if ( isset( $citationTypeID ) ) { |
| 51 | + $citationType = new WCCitationTypeEnum( $citationTypeID ); |
| 52 | + } |
| 53 | + } elseif ( $args[ 'style' ] ) { |
| 54 | + $this->styleHTML = ' style="' . $args[ 'style' ] . '"'; |
| 55 | + } elseif ( $args[ 'id' ] ) { |
| 56 | + $this->styleHTML = ' id="' . $args[ 'id' ] . '"'; |
| 57 | + } |
| 58 | + } |
| 59 | + if ( isset( $styleClassName ) ) { |
| 60 | + # See if a specific style object has already been defined, and if so, use it. |
| 61 | + $styleObject = WCArticle::getStyle( $styleClassName ); |
| 62 | + } else { |
| 63 | + # Use default citation style. |
| 64 | + $styleObject = $defaultStyle; |
| 65 | + } |
| 66 | + if ( isset( $citationType ) ) { |
| 67 | + return new WCNote( $styleObject, $citationType ); |
| 68 | + } else { |
| 69 | + return new WCNote( $styleObject, WCCitationTypeEnum::$note ); |
| 70 | + } |
| 71 | + } |
| 72 | + |
| 73 | + public function __construct( WCStyle $style, WCCitationTypeEnum $type ) { |
| 74 | + $this->citationStyle = $style; |
| 75 | + $this->citationType = $type; |
| 76 | + # Leave behind a marker, later to be replaced by the subscript. |
| 77 | + $this->marker = 'NwC-' . mt_rand(); |
| 78 | + } |
| 79 | + |
| 80 | + |
| 81 | + public function getSuperscript( $text, $number ) { |
| 82 | + # Store the text, to be inserted in endnote list during $this->render(). |
| 83 | + $this->text = $text; |
| 84 | + $this->number = $number; |
| 85 | + # Leave behind a marker, later to be replaced by the subscript. |
| 86 | + return '<sup id="t' . $this->marker . '" class="notesuperscript"><a href="#n' . |
| 87 | + $this->marker . '">' . $number . '</a></sup>'; |
| 88 | + } |
| 89 | + |
| 90 | + |
| 91 | + /** |
| 92 | + * Add a single citation within the note. |
| 93 | + * @param integer $key |
| 94 | + * @param integer $distance = # of citations from last citation to this reference |
| 95 | + * @param WCArticle $article |
| 96 | + */ |
| 97 | + public function addNoteCite( $key, WCCitation $citation ) { |
| 98 | + $this->cites[ $key ] = $citation; |
| 99 | + } |
| 100 | + |
| 101 | + |
| 102 | + /** |
| 103 | + * Render the note. |
| 104 | + * @param boolean $bibliographyExists |
| 105 | + * @return string |
| 106 | + */ |
| 107 | + public function render( $bibliographyExists ) { |
| 108 | + # Replace citation markers in note with rendered citations. |
| 109 | + if ( $this->cites ) { |
| 110 | + $currentStyle = $this->citationStyle; |
| 111 | + $currentType = $this->citationType; |
| 112 | + foreach( $this->cites as $key => $citation ) { |
| 113 | + # If an explicit style has been defined for $key, use it on subsequent citations. |
| 114 | + if ( isset( $citation->style ) ) { |
| 115 | + $currentStyle = $citation->style; |
| 116 | + } else { |
| 117 | + $citation->style = $currentStyle; |
| 118 | + } |
| 119 | + # If an explicit type has been defined, use it on subsequent citations. |
| 120 | + if ( isset( $citation->citationType ) ) { |
| 121 | + $currentType = $citation->citationType; |
| 122 | + } else { |
| 123 | + $citation->citationType = $currentType; |
| 124 | + } |
| 125 | + # The first citation is long, and subsequent citations are short. |
| 126 | + # If there is a bibliography, they are all short. |
| 127 | + if ( is_null ( $citation->citationLength) ) { |
| 128 | + if ( $citation->distance === 0 && !$bibliographyExists ) { |
| 129 | + $citation->citationLength = WCCitationLengthEnum::$long; |
| 130 | + } else { |
| 131 | + $citation->citationLength = WCCitationLengthEnum::$short; |
| 132 | + } |
| 133 | + } |
| 134 | + list( $textCitation, ) = $citation->render(); |
| 135 | + $pos = strpos( $this->text, $citation->marker ); |
| 136 | + if ( $pos !== false ) { |
| 137 | + $text = substr_replace( $this->text, $textCitation, $pos, strlen( $citation->marker ) ); |
| 138 | + } |
| 139 | + } |
| 140 | + } |
| 141 | + $markedupText = '<li id="n' . $this->marker . '">'; |
| 142 | + $markedupText .= '<a href="#t' . $this->marker . '">' . $this->number . '</a>. '; |
| 143 | + $markedupText .= $text; |
| 144 | + $markedupText .= '</li>' . PHP_EOL; |
| 145 | + return $markedupText; |
| 146 | + } |
| 147 | + |
| 148 | +} |
| 149 | + |
| 150 | + |
| 151 | +/** |
| 152 | + * Static initializer. |
| 153 | + */ |
| 154 | +WCBibliography::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/WCNote.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 155 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCGroupSegment.php |
— | — | @@ -0,0 +1,148 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCGroupSegment extends WCSegment implements Countable { |
| 12 | + |
| 13 | + public $segments; |
| 14 | + |
| 15 | + protected $delimiter; |
| 16 | + |
| 17 | + public function __construct( |
| 18 | + array $segments = array(), |
| 19 | + $delimiter = '', |
| 20 | + $prefix = '', |
| 21 | + $suffix = '' ) { |
| 22 | + parent::__construct( $prefix, $suffix ); |
| 23 | + $this->segments = $segments; |
| 24 | + $this->delimiter = $delimiter; |
| 25 | + $this->exists = True; |
| 26 | + } |
| 27 | + |
| 28 | + |
| 29 | + public function exists() { |
| 30 | + if ( $this->exists ) { |
| 31 | + foreach ( $this->segments as $segment ) { |
| 32 | + if ( $segment->exists() ) { |
| 33 | + return True; |
| 34 | + } |
| 35 | + } |
| 36 | + } |
| 37 | + $this->exists = False; |
| 38 | + return False; |
| 39 | + } |
| 40 | + |
| 41 | + |
| 42 | + public function count() { |
| 43 | + $count = 0; |
| 44 | + foreach ( $this->segments as $segment ) { |
| 45 | + if ( $segment->exists() ) { |
| 46 | + $count++; |
| 47 | + } |
| 48 | + } |
| 49 | + return $count; |
| 50 | + } |
| 51 | + |
| 52 | + |
| 53 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 54 | + $segments = $this->segments; |
| 55 | + while ( $segments ) { |
| 56 | + $lastSegment = array_pop( $segments ); |
| 57 | + if ( $lastSegment->exists() ) break; |
| 58 | + } |
| 59 | + if ( $lastSegment->exists() ) { |
| 60 | + $text = $this->prefix; |
| 61 | + foreach( $segments as $segment ) { |
| 62 | + if ( $segment->exists() ) { |
| 63 | + $text .= $segment->render( $style, $this->delimiter ); |
| 64 | + } |
| 65 | + } |
| 66 | + return $text . $lastSegment->render( $style, $this->extendSuffix( $endSeparator ) ); |
| 67 | + } |
| 68 | + return ''; |
| 69 | + } |
| 70 | + |
| 71 | + |
| 72 | + public function getSortingParts() { |
| 73 | + $parts = array(); |
| 74 | + foreach( $this->segments as $segment ) { |
| 75 | + if ( $segment->exists() ) { |
| 76 | + $parts += $segment->getSortingParts(); |
| 77 | + } |
| 78 | + } |
| 79 | + return $parts; |
| 80 | + } |
| 81 | + |
| 82 | + |
| 83 | + /** |
| 84 | + * Implements Iterator interface method. |
| 85 | + * @return string |
| 86 | + */ |
| 87 | + public function key() { |
| 88 | + $segment = current( $this->segments ); |
| 89 | + return key( $this->segments) . '–' . $segment->key(); |
| 90 | + } |
| 91 | + |
| 92 | + |
| 93 | + /** |
| 94 | + * Implements Iterator interface method. |
| 95 | + * @return WCSegment |
| 96 | + */ |
| 97 | + public function current() { |
| 98 | + $segment = current( $this->segments ); |
| 99 | + return $segment->current(); |
| 100 | + } |
| 101 | + |
| 102 | + |
| 103 | + /** |
| 104 | + * Implements Iterator interface method. |
| 105 | + */ |
| 106 | + public function next() { |
| 107 | + $currentSegment = current( $this->segments ); |
| 108 | + if ( $currentSegment === False ) { |
| 109 | + return; |
| 110 | + } else { |
| 111 | + $currentSegment->next(); |
| 112 | + if ( ! $currentSegment->valid() ) { |
| 113 | + while ( ! ( ( $nextSegment = next( $this->segments ) ) === False ) ) { |
| 114 | + if ( $nextSegment->exists() ) { |
| 115 | + $nextSegment->rewind(); |
| 116 | + if ( $nextSegment->valid() ) { |
| 117 | + return; |
| 118 | + } |
| 119 | + } |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + } |
| 124 | + |
| 125 | + |
| 126 | + /** |
| 127 | + * Implements Iterator interface method. |
| 128 | + * @return boolean |
| 129 | + */ |
| 130 | + public function valid() { |
| 131 | + $segment = current( $this->segments ); |
| 132 | + return ( ! ( $segment === False ) ) && $segment->valid() ; |
| 133 | + } |
| 134 | + |
| 135 | + |
| 136 | + /** |
| 137 | + * Implements Iterator interface method. |
| 138 | + */ |
| 139 | + public function rewind() { |
| 140 | + $segment = reset( $this->segments ); |
| 141 | + while ( ! $segment->exists() ) { |
| 142 | + if ( next( $this->segments ) == False ) { |
| 143 | + return; |
| 144 | + } |
| 145 | + } |
| 146 | + $segment->rewind(); |
| 147 | + } |
| 148 | + |
| 149 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCGroupSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 150 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCLiteralSegment.php |
— | — | @@ -0,0 +1,81 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCLiteralSegment extends WCSegment { |
| 12 | + |
| 13 | + protected $text; |
| 14 | + |
| 15 | + protected $reset; |
| 16 | + |
| 17 | + public function __construct( $text ) { |
| 18 | + parent::__construct(); |
| 19 | + $this->text = $text; |
| 20 | + $this->exists = True; |
| 21 | + } |
| 22 | + |
| 23 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 24 | + if ( $endSeparator ) { |
| 25 | + $chrL = mb_substr( $this->text, -1, 1 ); |
| 26 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 27 | + if ( $chrL == $chrR ) { |
| 28 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 29 | + } |
| 30 | + return $this->text . $endSeparator; |
| 31 | + } else { |
| 32 | + return $this->text; |
| 33 | + } |
| 34 | + } |
| 35 | + |
| 36 | + public function getSortingParts() { |
| 37 | + return array(); |
| 38 | + } |
| 39 | + |
| 40 | + /** |
| 41 | + * Implements Iterator interface method. |
| 42 | + * @return string |
| 43 | + */ |
| 44 | + public function key() { |
| 45 | + return '1'; |
| 46 | + } |
| 47 | + |
| 48 | + |
| 49 | + /** |
| 50 | + * Implements Iterator interface method. |
| 51 | + * @return WCSegment |
| 52 | + */ |
| 53 | + public function current() { |
| 54 | + return ''; |
| 55 | + } |
| 56 | + |
| 57 | + |
| 58 | + /** |
| 59 | + * Implements Iterator interface method. |
| 60 | + */ |
| 61 | + public function next() { |
| 62 | + $this->reset = False; |
| 63 | + } |
| 64 | + |
| 65 | + |
| 66 | + /** |
| 67 | + * Implements Iterator interface method. |
| 68 | + * @return boolean |
| 69 | + */ |
| 70 | + public function valid() { |
| 71 | + return $this->exists && $this->reset; |
| 72 | + } |
| 73 | + |
| 74 | + |
| 75 | + /** |
| 76 | + * Implements Iterator interface method. |
| 77 | + */ |
| 78 | + public function rewind() { |
| 79 | + $this->reset = True;; |
| 80 | + } |
| 81 | + |
| 82 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCLiteralSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 83 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCDateSegment.php |
— | — | @@ -0,0 +1,532 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Enumerations |
| 13 | + */ |
| 14 | +class WCDateParts extends WCEnum { |
| 15 | + const none = 0; |
| 16 | + const year = 1; |
| 17 | + const month = 2; |
| 18 | + const day = 3; |
| 19 | + const season = 4; |
| 20 | + const yearMonth = 5; |
| 21 | + const yearSeason = 6; |
| 22 | + const monthDay = 7; |
| 23 | + const yearMonthDay = 8; |
| 24 | + const __default = self::none; |
| 25 | +} |
| 26 | + |
| 27 | +class WCDateOrder extends WCEnum { |
| 28 | + const littleEndian = 0; |
| 29 | + const middleEndian = 1; |
| 30 | + const bigEndian = 2; |
| 31 | + const __default = self::littleEndian; |
| 32 | +} |
| 33 | + |
| 34 | +class WCDateForm extends WCEnum { |
| 35 | + const long = 0; # e.g., August |
| 36 | + const short = 1; # e.g., Aug. |
| 37 | + const numeric = 2; # e.g., 8 |
| 38 | + const numericLeadingZeros = 3; # e.g., 08 |
| 39 | + const ordinal = 4; # e.g., 8th -- not implemented yet |
| 40 | + const __default = self::long; |
| 41 | +} |
| 42 | + |
| 43 | +class WCDateRange extends WCEnum { |
| 44 | + const range = 0; |
| 45 | + const first = 1; |
| 46 | + const second = 2; |
| 47 | + const __default = self::range; |
| 48 | +} |
| 49 | + |
| 50 | +class WCDateSegment extends WCDataSegment { |
| 51 | + |
| 52 | + protected $dateObject; |
| 53 | + |
| 54 | + protected $scope; |
| 55 | + |
| 56 | + protected $propertyType; |
| 57 | + |
| 58 | + protected $datePart, $dateOrder, $dateForm, $rangePart; |
| 59 | + |
| 60 | + protected $rangePointOfDifference; |
| 61 | + |
| 62 | + public function __construct( |
| 63 | + WCCitation $citation, |
| 64 | + WCSegmentImportance $importance, |
| 65 | + WCScopeEnum $scope, |
| 66 | + WCPropertyEnum $propertyType, |
| 67 | + WCDateParts $datePart, |
| 68 | + WCDateOrder $dateOrder, |
| 69 | + WCDateForm $dateForm, |
| 70 | + WCDateRange $dateRange, |
| 71 | + $prefix = '', |
| 72 | + $suffix = '' ) { |
| 73 | + parent::__construct( $citation, $prefix, $suffix ); |
| 74 | + $this->datePart = $datePart; |
| 75 | + $this->dateOrder = $dateOrder; |
| 76 | + $this->dateForm = $dateForm; |
| 77 | + $this->rangePart = $dateRange; |
| 78 | + switch( $importance->key ) { |
| 79 | + case WCSegmentImportance::mandatory: |
| 80 | + $this->$dateObject = $citation->reference->inferProperty( $scope, $propertyType ); |
| 81 | + $this->exists = True; |
| 82 | + return; |
| 83 | + case WCSegmentImportance::important: |
| 84 | + $this->dateObject = $citation->reference->inferProperty( $scope, $propertyType ); |
| 85 | + $this->exists = (bool) $this->dateObject; |
| 86 | + break; |
| 87 | + case WCSegmentImportance::optional: |
| 88 | + $dateObject = $citation->reference->getProperty( $scope, $propertyType ); |
| 89 | + if ( isset( $dateObject ) ) { |
| 90 | + $this->dateObject = $dateObject; |
| 91 | + } else { |
| 92 | + $this->exists = False; |
| 93 | + } |
| 94 | + } |
| 95 | + # $scope and $propertyType may have changed as a side-effect of $citation->inferProperty. |
| 96 | + $this->scope = $scope; |
| 97 | + $this->propertyType = $propertyType; |
| 98 | + |
| 99 | + # Determine if the date is a range and if so, where the point of difference is. |
| 100 | + if ( isset ( $this->dateObject->year2 ) ) { |
| 101 | + $this->rangePointOfDifference = WCDateParts::year; |
| 102 | + } elseif ( isset ( $this->dateObject->month2 ) ) { |
| 103 | + $this->rangePointOfDifference = WCDateParts::month; |
| 104 | + } elseif ( isset ( $this->dateObject->day2 ) ) { |
| 105 | + $this->rangePointOfDifference = WCDateParts::day; |
| 106 | + } elseif ( isset ( $this->dateObject->season2 ) ) { |
| 107 | + $this->rangePointOfDifference = WCDateParts::season; |
| 108 | + } else { |
| 109 | + $this->rangePointOfDifference = WCDateParts::none; |
| 110 | + } |
| 111 | + |
| 112 | + } |
| 113 | + |
| 114 | + |
| 115 | + public function getLabel( WCStyle $style, WCLabelFormEnum $form, WCPluralEnum $plural ) { |
| 116 | + return $style->propertyLabels[ $this->propertyType->key ][ $form->key ][ $plural->key ]; |
| 117 | + } |
| 118 | + |
| 119 | + |
| 120 | + /** |
| 121 | + * Set the part and form to render with any subsequent calls to render(). |
| 122 | + * @param WCDateParts $dateParts |
| 123 | + * @param WCDateForm $dateForm |
| 124 | + * @param int $rangePart |
| 125 | + * @param string $prefix |
| 126 | + * @param string $suffix |
| 127 | + */ |
| 128 | + public function setPart( WCDateParts $datePart, $prefix = '', $suffix = '' ) { |
| 129 | + $this->datePart = $datePart; |
| 130 | + $this->prefix = $prefix; |
| 131 | + $this->suffix = $suffix; |
| 132 | + } |
| 133 | + |
| 134 | + |
| 135 | + public function rangePointOfDifference() { |
| 136 | + return $this->rangePointOfDifference; |
| 137 | + } |
| 138 | + |
| 139 | + |
| 140 | + public function count() { |
| 141 | + return $this->rangePointOfDifference != WCDateParts::none; |
| 142 | + } |
| 143 | + |
| 144 | + |
| 145 | + public function getSortingParts() { |
| 146 | + if ( $this->dateObject->era == WCDateTermsEnum::BC ) { |
| 147 | + $arr = array( - $this->dateObject->year ); |
| 148 | + } else { |
| 149 | + $arr = array( $this->dateObject->year ); |
| 150 | + } |
| 151 | + if ( $this->dateObject->season ) { |
| 152 | + $arr[] = $this->dateObject->season; |
| 153 | + return $arr; |
| 154 | + } |
| 155 | + if ( $this->dateObject->month ) { |
| 156 | + $arr[] = $this->dateObject->month; |
| 157 | + } |
| 158 | + if ( $this->dateObject->day ) { |
| 159 | + $arr[] = $this->dateObject->day; |
| 160 | + } |
| 161 | + return $arr; |
| 162 | + |
| 163 | + } |
| 164 | + |
| 165 | + |
| 166 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 167 | + if ( $this->dateObject ) { |
| 168 | + switch( $this->rangePart->key ) { |
| 169 | + case WCDateRange::range: |
| 170 | + switch ( $this->datePart->key ) { |
| 171 | + case WCDateParts::year: |
| 172 | + $date = $this->renderYearRange(); |
| 173 | + break; |
| 174 | + case WCDateParts::month: |
| 175 | + $date = $this->renderMonthRange(); |
| 176 | + break; |
| 177 | + case WCDateParts::day: |
| 178 | + $date = $this->renderDayRange(); |
| 179 | + break; |
| 180 | + case WCDateParts::season: |
| 181 | + $date = $this->renderSeasonRange(); |
| 182 | + break; |
| 183 | + case WCDateParts::yearMonthDay: |
| 184 | + switch( $this->dateOrder->key ) { |
| 185 | + case WCDateOrder::littleEndian: |
| 186 | + switch ( $this->rangePointOfDifference() ) { |
| 187 | + case WCDateParts::none: |
| 188 | + $date = $this->renderDay() . ' ' . $this->renderMonth() . ' ' . $this->renderYear(); |
| 189 | + break; |
| 190 | + case WCDateParts::year: |
| 191 | + $date = $this->renderDay() . ' ' . $this->renderMonth() . ' ' . $this->renderYear() . ' – ' . $this->renderDay2() . ' ' . $this->renderMonth2() . ' ' . $this->renderYear2(); |
| 192 | + break; |
| 193 | + case WCDateParts::month: |
| 194 | + $date = $this->renderDay() . ' ' . $this->renderMonth() . ' – ' . $this->renderDay2() . ' ' . $this->renderMonth2() . ' ' . $this->renderYear(); |
| 195 | + break; |
| 196 | + case WCDateParts::day: |
| 197 | + $date = $this->renderDayRange() . ' ' . $this->renderMonth() . ' ' . $this->renderYear(); |
| 198 | + break; |
| 199 | + case WCDateParts::season: |
| 200 | + $date = $this->renderSeasonRange() . ' ' . $this->renderYear(); |
| 201 | + break; |
| 202 | + default: |
| 203 | + throw new MWException( 'Point of difference is not defined' ); |
| 204 | + } |
| 205 | + break; |
| 206 | + case WCDateOrder::middleEndian: |
| 207 | + switch ( $this->rangePointOfDifference() ) { |
| 208 | + case WCDateParts::none: |
| 209 | + $date = $this->renderMonth() . ' ' . $this->renderDay() . ', ' . $this->renderYear(); |
| 210 | + break; |
| 211 | + case WCDateParts::year: |
| 212 | + $date = $this->renderMonth() . ' ' . $this->renderDay() . ', ' . $this->renderYear() . ' – ' . $this->renderMonth2() . ' ' . $this->renderDay2() . ', ' . $this->renderYear2(); |
| 213 | + break; |
| 214 | + case WCDateParts::month: |
| 215 | + $date = $this->renderMonth() . ' ' . $this->renderDay() . ' – ' . $this->renderMonth2() . ' ' . $this->renderDay2() . ', ' . $this->renderYear(); |
| 216 | + break; |
| 217 | + case WCDateParts::day: |
| 218 | + $date = $this->renderMonth() . ' ' . $this->renderDayRange() . ', ' . $this->renderYear(); |
| 219 | + break; |
| 220 | + case WCDateParts::season: |
| 221 | + $date = $this->renderSeasonRange() . ' ' . $this->renderYear(); |
| 222 | + default: |
| 223 | + throw new MWException( 'Point of difference is not defined' ); |
| 224 | + } |
| 225 | + break; |
| 226 | + case WCDateOrder::bigEndian: |
| 227 | + switch ( $this->rangePointOfDifference() ) { |
| 228 | + case WCDateParts::none: |
| 229 | + $date = $this->renderYear() . ' ' . $this->renderMonth() . ' ' . $this->renderDay(); |
| 230 | + break; |
| 231 | + case WCDateParts::year: |
| 232 | + $date = $this->renderYear() . ' ' . $this->renderMonth() . ' ' . $this->renderDay() . ' – ' . $this->renderYear2() . ' ' . $this->renderMonth2() . ' ' . $this->renderDay2(); |
| 233 | + break; |
| 234 | + case WCDateParts::month: |
| 235 | + $date = $this->renderYear() . ' ' . $this->renderMonth() . ' ' . $this->renderDay() . ' – ' . $this->renderMonth2() . ' ' . $this->renderDay2(); |
| 236 | + break; |
| 237 | + case WCDateParts::day: |
| 238 | + $date = $this->renderYear() . ' ' . $this->renderMonth() . ' ' . $this->renderDayRange(); |
| 239 | + break; |
| 240 | + case WCDateParts::season: |
| 241 | + $date = $this->renderYear() . ' ' . $this->renderSeasonRange(); |
| 242 | + break; |
| 243 | + default: |
| 244 | + throw new MWException( 'Point of difference is not defined' ); |
| 245 | + } |
| 246 | + break; |
| 247 | + default: |
| 248 | + $date = $this->renderDayFirstFull(); |
| 249 | + } |
| 250 | + break; |
| 251 | + default: |
| 252 | + throw new MWException( 'Date part is not defined' ); |
| 253 | + } |
| 254 | + break; |
| 255 | + case WCDateRange::first: |
| 256 | + switch ( $this->datePart->key ) { |
| 257 | + case WCDateParts::year: |
| 258 | + $date = $this->renderYear(); |
| 259 | + break; |
| 260 | + case WCDateParts::month: |
| 261 | + $date = $this->renderMonth(); |
| 262 | + break; |
| 263 | + case WCDateParts::day: |
| 264 | + $date = $this->renderDay(); |
| 265 | + break; |
| 266 | + case WCDateParts::season: |
| 267 | + $date = $this->renderSeason(); |
| 268 | + break; |
| 269 | + default: |
| 270 | + throw new MWException( '$this->datePart is not defined' ); |
| 271 | + } |
| 272 | + break; |
| 273 | + case WCDateRange::second: |
| 274 | + switch ( $this->datePart->key ) { |
| 275 | + case WCDateParts::year: |
| 276 | + $date = $this->renderYear2(); |
| 277 | + break; |
| 278 | + case WCDateParts::month: |
| 279 | + $date = $this->renderMonth2(); |
| 280 | + break; |
| 281 | + case WCDateParts::day: |
| 282 | + $date = $this->renderDay2(); |
| 283 | + break; |
| 284 | + case WCDateParts::season: |
| 285 | + $date = $this->renderSeason2(); |
| 286 | + break; |
| 287 | + default: |
| 288 | + throw new MWException( 'Date part is not defined' ); |
| 289 | + } |
| 290 | + } |
| 291 | + $endSeparator = $this->extendSuffix( $endSeparator ); |
| 292 | + if ( $endSeparator ) { |
| 293 | + $chrL = mb_substr( $date, -1, 1 ); |
| 294 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 295 | + if ( $chrL == $chrR ) { |
| 296 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 297 | + } |
| 298 | + $date .= $endSeparator; |
| 299 | + } |
| 300 | + return $this->prefix . $date; |
| 301 | + } else { |
| 302 | + return $this->prefix . $style->segmentMissing . $this->extendSuffix( $endSeparator ); |
| 303 | + } |
| 304 | + } |
| 305 | + |
| 306 | + |
| 307 | + protected function renderYearRange() { |
| 308 | + if ( isset ( $this->dateObject->year ) ) { |
| 309 | + if ( isset( $this->dateObject->year2 ) ) { |
| 310 | + switch ( $this->dateForm->key ) { |
| 311 | + case WCDateForm::long: |
| 312 | + case WCDateForm::numeric: |
| 313 | + return $this->dateObject->year . '–' . $this->dateObject->year2; |
| 314 | + case WCDateForm::short: |
| 315 | + case WCDateForm::leadingZeros: |
| 316 | + if ( $this->dateObject->year >= 1900 ) { |
| 317 | + return str_pad( $this->dateObject->year % 100, 2, '0', STR_PAD_LEFT ) . '–' |
| 318 | + . str_pad( $this->dateObject->year2 % 100, 2, '0', STR_PAD_LEFT ); |
| 319 | + } |
| 320 | + else { |
| 321 | + return $this->dateObject->year . '–' . $this->dateObject->year2; |
| 322 | + } |
| 323 | + } |
| 324 | + } |
| 325 | + else { |
| 326 | + switch ( $this->dateForm->key ) { |
| 327 | + case WCDateForm::long: |
| 328 | + case WCDateForm::numeric: |
| 329 | + return (string) $this->dateObject->year; |
| 330 | + case WCDateForm::short: |
| 331 | + case WCDateForm::leadingZeros: |
| 332 | + if ( $this->dateObject->year >= 1900 ) return str_pad( $this->dateObject->year % 100, 2, '0', STR_PAD_LEFT ); |
| 333 | + else return (string) $this->dateObject->year; |
| 334 | + } |
| 335 | + } |
| 336 | + } |
| 337 | + else { |
| 338 | + return Null; |
| 339 | + } |
| 340 | + } |
| 341 | + |
| 342 | + |
| 343 | + protected function renderYear() { |
| 344 | + if ( isset ( $this->dateObject->year ) ) { |
| 345 | + switch ( $this->dateForm->key ) { |
| 346 | + case WCDateForm::long: |
| 347 | + case WCDateForm::numeric: |
| 348 | + return (string) $this->dateObject->year; |
| 349 | + case WCDateForm::short: |
| 350 | + case WCDateForm::leadingZeros: |
| 351 | + if ( $this->dateObject->year >= 1900 ) return str_pad( $this->dateObject->year % 100, 2, '0', STR_PAD_LEFT ); |
| 352 | + else return (string) $this->dateObject->year; |
| 353 | + } |
| 354 | + } |
| 355 | + else { |
| 356 | + return Null; |
| 357 | + } |
| 358 | + } |
| 359 | + |
| 360 | + |
| 361 | + protected function renderYear2() { |
| 362 | + if ( isset ( $this->dateObject->year2 ) ) { |
| 363 | + switch ( $this->dateForm->key ) { |
| 364 | + case WCDateForm::long: |
| 365 | + case WCDateForm::numeric: |
| 366 | + return (string) $this->dateObject->year2; |
| 367 | + case WCDateForm::short: |
| 368 | + case WCDateForm::leadingZeros: |
| 369 | + if ( $this->dateObject->year2 >= 1900 ) return str_pad( $this->dateObject->year2 % 100, 2, '0', STR_PAD_LEFT ); |
| 370 | + else return (string) $this->dateObject->year2; |
| 371 | + } |
| 372 | + } |
| 373 | + else { |
| 374 | + return Null; |
| 375 | + } |
| 376 | + } |
| 377 | + |
| 378 | + |
| 379 | + protected function renderMonthRange() { |
| 380 | + if ( isset ( $this->dateObject->month ) ) { |
| 381 | + if ( isset( $this->dateObject->month2 ) ) { |
| 382 | + switch ( $this->dateForm->key ) { |
| 383 | + case WCDateForm::long: |
| 384 | + case WCDateForm::short: |
| 385 | + case WCDateForm::numeric: |
| 386 | + return $this->dateObject->month . '–' . $this->month2; |
| 387 | + case WCDateForm::numericLeadingZeros: |
| 388 | + return str_pad( $this->dateObject->month, 2, '0', STR_PAD_LEFT ) . '–' |
| 389 | + . str_pad( $this->dateObject->month2, 2, '0', STR_PAD_LEFT ); |
| 390 | + } |
| 391 | + } |
| 392 | + else { |
| 393 | + switch ( $this->dateForm->key ) { |
| 394 | + case WCDateForm::long: |
| 395 | + case WCDateForm::numeric: |
| 396 | + return (string) $this->dateObject->month; |
| 397 | + case WCDateForm::short: |
| 398 | + case WCDateForm::numericLeadingZeros: |
| 399 | + return str_pad( $this->dateObject->month, 2, '0', STR_PAD_LEFT ); |
| 400 | + } |
| 401 | + } |
| 402 | + } |
| 403 | + else { |
| 404 | + return Null; |
| 405 | + } |
| 406 | + } |
| 407 | + |
| 408 | + |
| 409 | + protected function renderMonth() { |
| 410 | + if ( isset ( $this->dateObject->month ) ) { |
| 411 | + switch ( $this->dateForm->key ) { |
| 412 | + case WCDateForm::long: |
| 413 | + case WCDateForm::numeric: |
| 414 | + return (string) $this->dateObject->month; |
| 415 | + case WCDateForm::short: |
| 416 | + case WCDateForm::numericLeadingZeros: |
| 417 | + return str_pad( $this->dateObject->month, 2, '0', STR_PAD_LEFT ); |
| 418 | + } |
| 419 | + } |
| 420 | + else { |
| 421 | + return Null; |
| 422 | + } |
| 423 | + } |
| 424 | + |
| 425 | + |
| 426 | + protected function renderMonth2() { |
| 427 | + if ( isset ( $this->dateObject->month2 ) ) { |
| 428 | + switch ( $this->dateForm->key ) { |
| 429 | + case WCDateForm::long: |
| 430 | + case WCDateForm::numeric: |
| 431 | + return (string) $this->dateObject->month2; |
| 432 | + case WCDateForm::short: |
| 433 | + case WCDateForm::numericLeadingZeros: |
| 434 | + return str_pad( $this->dateObject->month2, 2, '0', STR_PAD_LEFT ); |
| 435 | + } |
| 436 | + } |
| 437 | + else { |
| 438 | + return Null; |
| 439 | + } |
| 440 | + } |
| 441 | + |
| 442 | + |
| 443 | + protected function renderDayRange() { |
| 444 | + if ( isset ( $this->dateObject->day ) ) { |
| 445 | + if ( isset( $this->dateObject->day2 ) ) { |
| 446 | + switch ( $this->dateForm->key ) { |
| 447 | + case WCDateForm::numeric: |
| 448 | + return $this->dateObject->day . '–' . $this->day2; |
| 449 | + case WCDateForm::numericLeadingZeros: |
| 450 | + return str_pad( $this->dateObject->day, 2, '0', STR_PAD_LEFT ) . '–' |
| 451 | + . str_pad( $this->dateObject->day2, 2, '0', STR_PAD_LEFT ); |
| 452 | + case WCDateForm::ordinal: |
| 453 | + # This must wait until we can use PHP 5.3 NumberFormatter. |
| 454 | + return (string) $this->dateObject->day; |
| 455 | + } |
| 456 | + } |
| 457 | + else { |
| 458 | + switch ( $this->dateForm->key ) { |
| 459 | + case WCDateForm::numeric: |
| 460 | + return (string) $this->dateObject->day; |
| 461 | + case WCDateForm::numericLeadingZeros: |
| 462 | + return str_pad( $this->dateObject->day, 2, '0', STR_PAD_LEFT ); |
| 463 | + case WCDateForm::ordinal: |
| 464 | + # This must wait until we can use PHP 5.3 NumberFormatter. |
| 465 | + return $this->dateObject->day . '–' . $this->day2; |
| 466 | + } |
| 467 | + } |
| 468 | + } |
| 469 | + } |
| 470 | + |
| 471 | + |
| 472 | + protected function renderDay() { |
| 473 | + switch ( $this->dateForm->key ) { |
| 474 | + case WCDateForm::numeric: |
| 475 | + return (string) $this->dateObject->day; |
| 476 | + case WCDateForm::numericLeadingZeros: |
| 477 | + return str_pad( $this->dateObject->day, 2, '0', STR_PAD_LEFT ); |
| 478 | + case WCDateForm::ordinal: |
| 479 | + # This must wait until we can use PHP 5.3 NumberFormatter. |
| 480 | + return (string) $this->dateObject->day; |
| 481 | + } |
| 482 | + } |
| 483 | + |
| 484 | + |
| 485 | + protected function renderDay2() { |
| 486 | + switch ( $this->dateForm->key ) { |
| 487 | + case WCDateForm::numeric: |
| 488 | + return (string) $this->dateObject->day2; |
| 489 | + case WCDateForm::numericLeadingZeros: |
| 490 | + return str_pad( $this->dateObject->day2, 2, '0', STR_PAD_LEFT ); |
| 491 | + case WCDateForm::ordinal: |
| 492 | + # This must wait until we can use PHP 5.3 NumberFormatter. |
| 493 | + return (string) $this->dateObject->day2; |
| 494 | + } |
| 495 | + } |
| 496 | + |
| 497 | + |
| 498 | + protected function renderSeasonRange() { |
| 499 | + if ( isset( $this->dateObject->season ) ) { |
| 500 | + if ( isset( $this->dateObject->season2 ) ) { |
| 501 | + return $this->dateObject->season . '–' . $this->dateObject->season2; |
| 502 | + } |
| 503 | + else { |
| 504 | + return $this->dateObject->season; |
| 505 | + } |
| 506 | + } |
| 507 | + else { |
| 508 | + return Null; |
| 509 | + } |
| 510 | + } |
| 511 | + |
| 512 | + |
| 513 | + protected function renderSeason() { |
| 514 | + if ( isset( $this->dateObject->season ) ) { |
| 515 | + return $this->dateObject->season; |
| 516 | + } |
| 517 | + else { |
| 518 | + return Null; |
| 519 | + } |
| 520 | + } |
| 521 | + |
| 522 | + |
| 523 | + protected function renderSeason2() { |
| 524 | + if ( isset( $this->dateObject->season2 ) ) { |
| 525 | + return $this->dateObject->season2; |
| 526 | + } |
| 527 | + else { |
| 528 | + return Null; |
| 529 | + } |
| 530 | + } |
| 531 | + |
| 532 | + |
| 533 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCDateSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 534 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCAlternativeSegment.php |
— | — | @@ -0,0 +1,39 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCAlternativeSegment extends WCWrapperSegment { |
| 12 | + |
| 13 | + /** |
| 14 | + * Choose the first alternative in the array that exists, and cancel all |
| 15 | + * other alternatives. |
| 16 | + * @param array $segments Array of WCSegment objects. |
| 17 | + */ |
| 18 | + public function __construct( array $segments = array() ) { |
| 19 | + $this->exists = False; |
| 20 | + $theSegment = Null; |
| 21 | + foreach ( $segments as $segment ) { |
| 22 | + if ( $segment->exists() ) { |
| 23 | + if ( $this->exists ) { |
| 24 | + $segment->cancel(); |
| 25 | + } else { |
| 26 | + $this->exists = True; |
| 27 | + $theSegment = $segment; |
| 28 | + } |
| 29 | + } |
| 30 | + } |
| 31 | + parent::__construct( $theSegment ); |
| 32 | + } |
| 33 | + |
| 34 | + |
| 35 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 36 | + return $this->segment->render( $style, $endSeparator ); |
| 37 | + } |
| 38 | + |
| 39 | + |
| 40 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCAlternativeSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 41 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCLabelSegment.php |
— | — | @@ -0,0 +1,99 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCLabelFormEnum extends WCEnum { |
| 12 | + const none = 0; |
| 13 | + const long = 1; |
| 14 | + const verb = 2; |
| 15 | + const short = 3; |
| 16 | + const verbShort = 4; |
| 17 | + const symbol = 5; |
| 18 | + const __default = self::none; |
| 19 | +} |
| 20 | + |
| 21 | + |
| 22 | +class WCPluralEnum extends WCEnum { |
| 23 | + const singular = 0; |
| 24 | + const plural = 1; |
| 25 | + const __default = self::singular; |
| 26 | +} |
| 27 | + |
| 28 | + |
| 29 | +class WCLabelPluralEnum extends WCEnum { |
| 30 | + const contextual = 0; |
| 31 | + const always = 1; |
| 32 | + const never = 2; |
| 33 | + const __default = self::contextual; |
| 34 | +} |
| 35 | + |
| 36 | + |
| 37 | +class WCRelativePositionEnum extends WCEnum { |
| 38 | + const before = 0; |
| 39 | + const after = 1; |
| 40 | + const __default = self::before; |
| 41 | +} |
| 42 | + |
| 43 | + |
| 44 | +class WCLabelSegment extends WCWrapperSegment { |
| 45 | + |
| 46 | + protected $segment; |
| 47 | + protected $positionEnum, $labelForm, $labelTextCase, $plural; |
| 48 | + |
| 49 | + public function __construct( |
| 50 | + WCDataSegment $segment, |
| 51 | + WCRelativePositionEnum $positionEnum, |
| 52 | + WCLabelFormEnum $labelForm, |
| 53 | + WCTextCaseEnum $labelTextCase, |
| 54 | + WCLabelPluralEnum $labelPlural, |
| 55 | + $prefix = '', |
| 56 | + $suffix = '' ) { |
| 57 | + $this->segment = $segment; |
| 58 | + $this->positionEnum = $positionEnum; |
| 59 | + $this->labelForm = $labelForm; |
| 60 | + $this->labelTextCase = $labelTextCase; |
| 61 | + if ( $segment->exists() ) { |
| 62 | + $this->exists = True; |
| 63 | + } else { |
| 64 | + $this->exists = False; |
| 65 | + return; |
| 66 | + } |
| 67 | + switch ( $labelPlural->key ) { |
| 68 | + case WCLabelPluralEnum::contextual: |
| 69 | + if ( count( $segment ) > 1 ) { |
| 70 | + $this->plural = new WCPluralEnum( WCPluralEnum::plural ); |
| 71 | + } else { |
| 72 | + $this->plural = new WCPluralEnum( WCPluralEnum::singular ); |
| 73 | + } |
| 74 | + break; |
| 75 | + case WCLabelPluralEnum::always: |
| 76 | + $this->plural = new WCPluralEnum( WCPluralEnum::plural ); |
| 77 | + break; |
| 78 | + case WCLabelPluralEnum::never: |
| 79 | + $this->plural = new WCPluralEnum( WCPluralEnum::singular ); |
| 80 | + } |
| 81 | + |
| 82 | + } |
| 83 | + |
| 84 | + |
| 85 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 86 | + $label = $this->segment->getLabel( $style, $this->labelForm, $this->plural ); |
| 87 | + $label = $style->capitalize( $label, $this->labelTextCase ); |
| 88 | + |
| 89 | + if ( $label ) { |
| 90 | + if ( $this->positionEnum->key == WCRelativePositionEnum::before ) { |
| 91 | + $this->prefix = $label . ' ' . $this->prefix; |
| 92 | + } else { # WCRelativePositionEnum::after |
| 93 | + $this->suffix .= ', ' . $label; |
| 94 | + } |
| 95 | + return $this->prefix . $this->segment->render( $style, $this->extendSuffix( $endSeparator ) ); |
| 96 | + } |
| 97 | + } |
| 98 | + |
| 99 | + |
| 100 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCLabelSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 101 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCSegment.php |
— | — | @@ -0,0 +1,52 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +abstract class WCSegment implements Iterator { |
| 12 | + |
| 13 | + protected $prefix; |
| 14 | + |
| 15 | + protected $suffix; |
| 16 | + |
| 17 | + protected $exists; |
| 18 | + |
| 19 | + public function __construct( $prefix = '', $suffix = '' ) { |
| 20 | + $this->prefix = $prefix; |
| 21 | + $this->suffix = $suffix; |
| 22 | + } |
| 23 | + |
| 24 | + public function exists() { |
| 25 | + return $this->exists; |
| 26 | + } |
| 27 | + |
| 28 | + public function cancel() { |
| 29 | + $this->exists = False; |
| 30 | + } |
| 31 | + |
| 32 | + abstract public function render( WCStyle $style, $endSeparator = '' ); |
| 33 | + |
| 34 | + protected function extendSuffix( $endSeparator ) { |
| 35 | + if ( $this->suffix ) { |
| 36 | + if ( $endSeparator ) { |
| 37 | + $chrL = mb_substr( $this->suffix, -1, 1 ); |
| 38 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 39 | + if ( $chrL == $chrR ) { |
| 40 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 41 | + } |
| 42 | + return $this->suffix . $endSeparator; |
| 43 | + } else { |
| 44 | + return $this->suffix; |
| 45 | + } |
| 46 | + } else { |
| 47 | + return $endSeparator; |
| 48 | + } |
| 49 | + } |
| 50 | + |
| 51 | + abstract public function getSortingParts(); |
| 52 | + |
| 53 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 54 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCWrapperSegment.php |
— | — | @@ -0,0 +1,87 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCWrapperSegment extends WCSegment { |
| 12 | + |
| 13 | + protected $segment; |
| 14 | + |
| 15 | + public function __construct( $segment, $prefix = '', $suffix = '' ) { |
| 16 | + parent::__construct( $prefix, $suffix ); |
| 17 | + $this->segment = $segment; |
| 18 | + } |
| 19 | + |
| 20 | + |
| 21 | + public function exists() { |
| 22 | + if ( $this->exists ) { |
| 23 | + if ( $this->segment->exists() ) { |
| 24 | + return True; |
| 25 | + } else { |
| 26 | + $this->exists = False; |
| 27 | + } |
| 28 | + } |
| 29 | + $this->exists = False; |
| 30 | + return False; |
| 31 | + } |
| 32 | + |
| 33 | + |
| 34 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 35 | + return $this->prefix . $this->segment->render( $style, $this->extendSuffix( $endSeparator ) ); |
| 36 | + } |
| 37 | + |
| 38 | + |
| 39 | + public function getSortingParts() { |
| 40 | + if ( $this->exists ) { |
| 41 | + return $this->segment->getSortingParts(); |
| 42 | + } |
| 43 | + } |
| 44 | + |
| 45 | + |
| 46 | + /** |
| 47 | + * Implements Iterator interface method. |
| 48 | + * @return string |
| 49 | + */ |
| 50 | + public function key() { |
| 51 | + return $this->segment->key(); |
| 52 | + } |
| 53 | + |
| 54 | + |
| 55 | + /** |
| 56 | + * Implements Iterator interface method. |
| 57 | + * @return WCSegment |
| 58 | + */ |
| 59 | + public function current() { |
| 60 | + return $this->segment->current(); |
| 61 | + } |
| 62 | + |
| 63 | + |
| 64 | + /** |
| 65 | + * Implements Iterator interface method. |
| 66 | + */ |
| 67 | + public function next() { |
| 68 | + $this->segment->next(); |
| 69 | + } |
| 70 | + |
| 71 | + |
| 72 | + /** |
| 73 | + * Implements Iterator interface method. |
| 74 | + * @return boolean |
| 75 | + */ |
| 76 | + public function valid() { |
| 77 | + return $this->exists && $this->segment->valid(); |
| 78 | + } |
| 79 | + |
| 80 | + |
| 81 | + /** |
| 82 | + * Implements Iterator interface method. |
| 83 | + */ |
| 84 | + public function rewind() { |
| 85 | + $this->segment->rewind(); |
| 86 | + } |
| 87 | + |
| 88 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCWrapperSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 89 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCTitleSegment.php |
— | — | @@ -0,0 +1,139 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCTitleSegment extends WCDataSegment { |
| 12 | + |
| 13 | + protected $titleObject; |
| 14 | + |
| 15 | + protected $titleFormat; |
| 16 | + |
| 17 | + protected $scope; |
| 18 | + |
| 19 | + protected $propertyType; |
| 20 | + |
| 21 | + public function __construct( |
| 22 | + WCCitation $citation, |
| 23 | + WCSegmentImportance $importance, |
| 24 | + WCScopeEnum $scope, |
| 25 | + WCPropertyEnum $propertyType, |
| 26 | + WCTitleFormat $titleFormat, |
| 27 | + $prefix = '', |
| 28 | + $suffix = '' |
| 29 | + ) { |
| 30 | + parent::__construct( $citation, $prefix, $suffix ); |
| 31 | + $this->titleFormat = $titleFormat; |
| 32 | + switch( $importance->key ) { |
| 33 | + case WCSegmentImportance::mandatory: |
| 34 | + $this->titleObject = $citation->reference->inferProperty( $scope, $propertyType ); |
| 35 | + $this->exists = True; |
| 36 | + return; |
| 37 | + case WCSegmentImportance::important: |
| 38 | + $this->titleObject = $citation->reference->inferProperty( $scope, $propertyType ); |
| 39 | + $this->exists = (bool) $this->titleObject; |
| 40 | + break; |
| 41 | + case WCSegmentImportance::optional: |
| 42 | + $titleObject = &$citation->properties[ $scope->key ][ $propertyType->key ]; |
| 43 | + if ( isset( $titleObject ) ) { |
| 44 | + $this->titleObject = $titleObject; |
| 45 | + $this->exists = True; |
| 46 | + } else { |
| 47 | + $this->exists = False; |
| 48 | + } |
| 49 | + } |
| 50 | + # $scope and $propertyType may have changed by now. |
| 51 | + $this->scope = $scope; |
| 52 | + $this->propertyType = $propertyType; |
| 53 | + } |
| 54 | + |
| 55 | + |
| 56 | + public function getLabel( WCStyle $style, WCLabelFormEnum $form, WCPluralEnum $plural ) { |
| 57 | + return $style->propertyLabels[ $this->propertyType->key ][ $form->key ][ $plural->key ]; |
| 58 | + } |
| 59 | + |
| 60 | + |
| 61 | + /** |
| 62 | + * Format title with quotes and other optional styling. |
| 63 | + * |
| 64 | + * This will wrap the title in an HTML <cite> element. The title will also |
| 65 | + * be quoted if the reference style is designated as a quoted-style |
| 66 | + * title in WCTypeEnum::$titleFormat. |
| 67 | + * @param WCStyle $style |
| 68 | + * @param string $endSeparator |
| 69 | + * @return string |
| 70 | + */ |
| 71 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 72 | + $endSeparator = $this->extendSuffix( $endSeparator ); |
| 73 | + if ( $this->titleObject ) { |
| 74 | + $title = $this->titleObject->getTitle(); |
| 75 | + |
| 76 | + # "quoted"-type title |
| 77 | + if ( $this->titleFormat->key == WCTitleFormat::quoted ) { |
| 78 | + |
| 79 | + if ( $style->punctuationInQuotes ) { # Punctuation is inside quotes: |
| 80 | + |
| 81 | + # Check for final quotes at the end of the title: |
| 82 | + $p = preg_split( '/(<\/q>+)$/uS', $title, 2, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE ); |
| 83 | + if ( count( $p ) >= 2 ) { |
| 84 | + $title = $p[0] . mb_substr( $endSeparator, 0, 1 ) . $p[1]; |
| 85 | + $title = $style->convertSemanticToCharacterQuotes( $title, True ); |
| 86 | + $title = $style->transformTitle( $title ); |
| 87 | + $title = '<cite class="' . WCStyle::quotedTitleHTML . '">' . $title . '</cite>'; |
| 88 | + $title = $style->quote( $title ); |
| 89 | + } else { |
| 90 | + $title = $style->convertSemanticToCharacterQuotes( $title, True ); |
| 91 | + $title = $style->transformTitle( $title ); |
| 92 | + $chrL = mb_substr( $title, -1, 1 ); |
| 93 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 94 | + if ( $chrR && ( $chrL === $chrR ) ) { |
| 95 | + # Wrap <cite> tag inside the quotes. |
| 96 | + $title = '<cite class="' . WCStyle::quotedTitleHTML . '">' . $title . '</cite>'; |
| 97 | + $title = $style->quote( $title ); |
| 98 | + } else { |
| 99 | + $title = $style->quote( $title . mb_substr( $endSeparator, 0, 1 ) ); |
| 100 | + # Wrap <cite> tag outside the quotes. |
| 101 | + $title = '<cite class="' . WCStyle::quotedTitleHTML . '">' . $title . '</cite>'; |
| 102 | + } |
| 103 | + } |
| 104 | + return $this->prefix . $title . mb_substr( $endSeparator, 1 ); |
| 105 | + } else { |
| 106 | + # Punctuation follows quotes. |
| 107 | + $title = $style->convertSemanticToCharacterQuotes( $title, True ); |
| 108 | + $title = $style->transformTitle( $title ); |
| 109 | + $title = '<cite class="' . WCStyle::quotedTitleHTML . '">' . $title . '</cite>'; |
| 110 | + return $this->prefix . $style->quote( $title ) . $endSeparator; |
| 111 | + } |
| 112 | + } |
| 113 | + |
| 114 | + # "italic"-type title |
| 115 | + $title = $style->convertSemanticToCharacterQuotes( $title ); |
| 116 | + $title = $style->transformTitle( $title ); |
| 117 | + $chrL = mb_substr( $title, -1, 1 ); |
| 118 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 119 | + if ( $chrR && $chrL == $chrR ) { |
| 120 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 121 | + } |
| 122 | + if ( $this->titleFormat->key == WCTitleFormat::italic ) { |
| 123 | + # "Italic"-type title |
| 124 | + return $this->prefix . '<cite class="' . WCStyle::italicTitleHTML . '">' . $title . '</cite>' . $endSeparator; |
| 125 | + } else { |
| 126 | + # WCTitleFormat::normal: |
| 127 | + return $this->prefix . '<cite>' . $title . '</cite>' . $endSeparator; |
| 128 | + } |
| 129 | + } else { |
| 130 | + return $this->prefix . $style->segmentMissing . $endSeparator; |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + |
| 135 | + public function getSortingParts() { |
| 136 | + return array( strip_tags( $this->titleObject->getTitle() ) ); |
| 137 | + } |
| 138 | + |
| 139 | + |
| 140 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCTitleSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 141 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCConditionalSegment.php |
— | — | @@ -0,0 +1,48 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCConditionalSegment extends WCWrapperSegment { |
| 12 | + |
| 13 | + /** |
| 14 | + * Construct a conditional segment. |
| 15 | + * If $condition is true, use the first segment. |
| 16 | + * Otherwise, use the second segment if it is defined. |
| 17 | + * If not defined, then segment does not exist. |
| 18 | + */ |
| 19 | + public function __construct( $condition, WCSegment $segment1, WCSegment $segment2 = Null ) { |
| 20 | + if ( $condition ) { |
| 21 | + parent::__construct( $segment1 ); |
| 22 | + $this->exists = True; |
| 23 | + } elseif ( $segment2 == Null ) { |
| 24 | + $this->exists = False; |
| 25 | + } else { |
| 26 | + parent::__construct( $segment2 ); |
| 27 | + $this->exists = True; |
| 28 | + } |
| 29 | + } |
| 30 | + |
| 31 | + |
| 32 | + /** |
| 33 | + * Unlike other WCWrapperSegment objects, if the wrapper does not exist, |
| 34 | + * the underlying segment is not cancelled. Thus, one may use a reference |
| 35 | + * to the same (non-canceled) object in multiple places within a |
| 36 | + * WCGroupSegment, turning them off independently. |
| 37 | + * @return boolean |
| 38 | + */ |
| 39 | + public function exists() { |
| 40 | + return $this->exists; |
| 41 | + } |
| 42 | + |
| 43 | + |
| 44 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 45 | + return $this->segment->render( $style, $endSeparator ); |
| 46 | + } |
| 47 | + |
| 48 | + |
| 49 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCConditionalSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 50 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCLocatorSegment.php |
— | — | @@ -0,0 +1,78 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCLocatorSegment extends WCDataSegment { |
| 12 | + |
| 13 | + /** |
| 14 | + * The WCLocator object |
| 15 | + * @var WCLocator |
| 16 | + */ |
| 17 | + protected $locatorObject; |
| 18 | + |
| 19 | + protected $locatorType; |
| 20 | + |
| 21 | + public function __construct( |
| 22 | + WCCitation $citation, |
| 23 | + WCSegmentImportance $importance, |
| 24 | + WCPropertyEnum $locatorType, |
| 25 | + $prefix = '', |
| 26 | + $suffix = '' ) { |
| 27 | + parent::__construct( $citation, $prefix, $suffix ); |
| 28 | + switch( $importance->key ) { |
| 29 | + case WCSegmentImportance::mandatory: |
| 30 | + $this->locatorObject = $citation->inferLocator( $locatorType ); |
| 31 | + $this->exists = True; |
| 32 | + return; |
| 33 | + case WCSegmentImportance::important: |
| 34 | + $this->locatorObject = $citation->inferLocator( $locatorType ); |
| 35 | + $this->exists = (bool) $this->locatorObject; |
| 36 | + break; |
| 37 | + case WCSegmentImportance::optional: |
| 38 | + $locatorObject = $citation->getLocator( $locatorType ); |
| 39 | + if ( isset( $locatorObject ) ) { |
| 40 | + $this->locatorObject = $locatorObject; |
| 41 | + $this->exists = True; |
| 42 | + } else { |
| 43 | + $this->exists = False; |
| 44 | + } |
| 45 | + } |
| 46 | + # $locatorType may have changed as a side-effect of $citation->inferLocator. |
| 47 | + $this->locatorType = $locatorType; |
| 48 | + } |
| 49 | + |
| 50 | + public function getLabel( WCStyle $style, WCLabelFormEnum $form, WCPluralEnum $plural ) { |
| 51 | + return $style->propertyLabels[ $this->locatorType->key ][ $form->key ][ $plural->key ]; |
| 52 | + } |
| 53 | + |
| 54 | + |
| 55 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 56 | + if ( $this->locatorObject ) { |
| 57 | + return $this->prefix . $this->locatorObject->render( $this->extendSuffix( $endSeparator ) ); |
| 58 | + } else { |
| 59 | + return $this->prefix . $style->segmentMissing . $this->extendSuffix( $endSeparator ); |
| 60 | + } |
| 61 | + } |
| 62 | + |
| 63 | + |
| 64 | + public function count() { |
| 65 | + $count = count( $this->locatorObject->ranges ); |
| 66 | + if ( $count == 1 ) { |
| 67 | + $count = count( reset( $this->locatorObject->ranges ) ); |
| 68 | + } |
| 69 | + return $count; |
| 70 | + } |
| 71 | + |
| 72 | + |
| 73 | + public function getSortingParts() { |
| 74 | + # Locators are not considered for sorting. |
| 75 | + return array(); |
| 76 | + } |
| 77 | + |
| 78 | + |
| 79 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCLocatorSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 80 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCNamesSegment.php |
— | — | @@ -0,0 +1,91 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCNamesSegment extends WCDataSegment { |
| 12 | + |
| 13 | + protected $namesObject; |
| 14 | + |
| 15 | + protected $scope; |
| 16 | + |
| 17 | + protected $nameType; |
| 18 | + |
| 19 | + protected $citationPosition; |
| 20 | + |
| 21 | + protected $citationLength; |
| 22 | + |
| 23 | + protected $nameSort; |
| 24 | + |
| 25 | + public function __construct( |
| 26 | + WCCitation $citation, |
| 27 | + WCSegmentImportance $importance, |
| 28 | + WCScopeEnum $scope, |
| 29 | + WCNameTypeEnum $nameType, |
| 30 | + WCCitationPosition $citationPosition, |
| 31 | + WCCitationLengthEnum $citationLength, |
| 32 | + $nameSort = False, |
| 33 | + $prefix = '', |
| 34 | + $suffix = '' ) { |
| 35 | + parent::__construct( $citation, $prefix, $suffix ); |
| 36 | + $this->citationPosition = $citationPosition; |
| 37 | + $this->citationLength = $citationLength; |
| 38 | + $this->nameSort = $nameSort; |
| 39 | + |
| 40 | + switch( $importance->key ) { |
| 41 | + case WCSegmentImportance::mandatory: |
| 42 | + $this->namesObject = $citation->reference->inferNames( $scope, $nameType ); |
| 43 | + $this->exists = True; |
| 44 | + break; |
| 45 | + case WCSegmentImportance::important: |
| 46 | + $this->namesObject = $citation->reference->inferNames( $scope, $nameType ); |
| 47 | + $this->exists = (bool) $this->namesObject; |
| 48 | + break; |
| 49 | + case WCSegmentImportance::optional: |
| 50 | + $namesObject = $citation->reference->getNames( $scope, $nameType ); |
| 51 | + if ( isset( $namesObject ) ) { |
| 52 | + $this->namesObject = $namesObject; |
| 53 | + $this->exists = True; |
| 54 | + } else { |
| 55 | + $this->exists = False; |
| 56 | + } |
| 57 | + } |
| 58 | + # $scope and $nameType may have changed as a side-effect of $citation->inferNames. |
| 59 | + $this->scope = $scope; |
| 60 | + $this->nameType = $nameType; |
| 61 | + } |
| 62 | + |
| 63 | + |
| 64 | + public function getLabel( WCStyle $style, WCLabelFormEnum $form, WCPluralEnum $plural ) { |
| 65 | + return $style->nameLabels[ $this->nameType->key ][ $form->key ][ $plural->key ]; |
| 66 | + } |
| 67 | + |
| 68 | + |
| 69 | + public function count() { |
| 70 | + return count( $this->namesObject ); |
| 71 | + } |
| 72 | + |
| 73 | + |
| 74 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 75 | + if ( $this->namesObject ) { |
| 76 | + return $this->prefix . $this->namesObject->render( $style, $this->citationPosition, $this->citationLength, $this->extendSuffix( $endSeparator ), $this->nameSort ); |
| 77 | + } else { |
| 78 | + return $this->prefix . $style->segmentMissing . $this->extendSuffix( $endSeparator ); |
| 79 | + } |
| 80 | + } |
| 81 | + |
| 82 | + |
| 83 | + public function getSortingParts() { |
| 84 | + $arr = array(); |
| 85 | + foreach( $this->namesObject as $name ) { |
| 86 | + $arr += $name->getSortingParts(); |
| 87 | + } |
| 88 | + return $arr; |
| 89 | + } |
| 90 | + |
| 91 | + |
| 92 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCNamesSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 93 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCTextSegment.php |
— | — | @@ -0,0 +1,82 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCTextSegment extends WCDataSegment { |
| 12 | + |
| 13 | + protected $textObject; |
| 14 | + |
| 15 | + protected $scope; |
| 16 | + |
| 17 | + protected $propertyType; |
| 18 | + |
| 19 | + protected $blank; |
| 20 | + |
| 21 | + public function __construct( |
| 22 | + WCCitation $citation, |
| 23 | + WCSegmentImportance $importance, |
| 24 | + WCScopeEnum $scope, |
| 25 | + WCPropertyEnum $propertyType, |
| 26 | + $prefix = '', |
| 27 | + $suffix = '' ) { |
| 28 | + parent::__construct( $citation, $prefix, $suffix ); |
| 29 | + switch( $importance->key ) { |
| 30 | + case WCSegmentImportance::mandatory: |
| 31 | + $this->textObject = $citation->reference->inferProperty( $scope, $propertyType ); |
| 32 | + $this->exists = True; |
| 33 | + return; |
| 34 | + case WCSegmentImportance::important: |
| 35 | + $this->textObject = $citation->reference->inferProperty( $scope, $propertyType ); |
| 36 | + $this->exists = (bool) $this->textObject; |
| 37 | + break; |
| 38 | + case WCSegmentImportance::optional: |
| 39 | + $textObject = $citation->reference->getProperty( $scope, $propertyType ); |
| 40 | + if ( isset( $textObject ) ) { |
| 41 | + $this->textObject = $textObject; |
| 42 | + $this->exists = True; |
| 43 | + } else { |
| 44 | + $this->exists = False; |
| 45 | + } |
| 46 | + } |
| 47 | + # $scope and $propertyType may have changed as a side-effect of $citation->inferProperty. |
| 48 | + $this->scope = $scope; |
| 49 | + $this->propertyType = $propertyType; |
| 50 | + } |
| 51 | + |
| 52 | + |
| 53 | + public function getLabel( WCStyle $style, WCLabelFormEnum $form, WCPluralEnum $plural ) { |
| 54 | + return $style->propertyLabels[ $this->propertyType->key ][ $form->key ][ $plural->key ]; |
| 55 | + } |
| 56 | + |
| 57 | + |
| 58 | + public function render( WCStyle $style, $endSeparator = '' ) { |
| 59 | + $endSeparator = $this->extendSuffix( $endSeparator ); |
| 60 | + if ( $this->textObject ) { |
| 61 | + $text = $this->textObject->getText(); |
| 62 | + if ( $endSeparator ) { |
| 63 | + $chrL = mb_substr( $text, -1, 1 ); |
| 64 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 65 | + if ( $chrL == $chrR ) { |
| 66 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 67 | + } |
| 68 | + return $this->prefix . $text . $endSeparator; |
| 69 | + } else { |
| 70 | + return $this->prefix . $text; |
| 71 | + } |
| 72 | + } else { |
| 73 | + return $this->prefix . $style->segmentMissing . $endSeparator; |
| 74 | + } |
| 75 | + } |
| 76 | + |
| 77 | + |
| 78 | + public function getSortingParts() { |
| 79 | + return array( $this->textObject->getText() ); |
| 80 | + } |
| 81 | + |
| 82 | + |
| 83 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCTextSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 84 | + native |
Index: trunk/extensions/WikiCitation/includes/segments/WCDataSegment.php |
— | — | @@ -0,0 +1,73 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +abstract class WCDataSegment extends WCSegment implements Countable { |
| 12 | + |
| 13 | + protected $citation; |
| 14 | + |
| 15 | + protected $sortingParts; |
| 16 | + |
| 17 | + public function __construct( WCCitation $citation, $prefix = '', $suffix = '' ) { |
| 18 | + $this->citation = $citation; |
| 19 | + $this->prefix = $prefix; |
| 20 | + $this->suffix = $suffix; |
| 21 | + } |
| 22 | + |
| 23 | + abstract public function getLabel( WCStyle $style, WCLabelFormEnum $form, WCPluralEnum $plural ); |
| 24 | + |
| 25 | + public function count() { |
| 26 | + return (int) $this->exists; |
| 27 | + } |
| 28 | + |
| 29 | + |
| 30 | + /** |
| 31 | + * Implements Iterator interface method. |
| 32 | + * @return string |
| 33 | + */ |
| 34 | + public function key() { |
| 35 | + return key( $this->sortingParts ); |
| 36 | + } |
| 37 | + |
| 38 | + |
| 39 | + /** |
| 40 | + * Implements Iterator interface method. |
| 41 | + * @return WCSegment |
| 42 | + */ |
| 43 | + public function current() { |
| 44 | + return current( $this->sortingParts ); |
| 45 | + } |
| 46 | + |
| 47 | + |
| 48 | + /** |
| 49 | + * Implements Iterator interface method. |
| 50 | + */ |
| 51 | + public function next() { |
| 52 | + next( $this->sortingParts ); |
| 53 | + } |
| 54 | + |
| 55 | + |
| 56 | + /** |
| 57 | + * Implements Iterator interface method. |
| 58 | + * @return boolean |
| 59 | + */ |
| 60 | + public function valid() { |
| 61 | + return (boolean) current( $this->sortingParts ); |
| 62 | + } |
| 63 | + |
| 64 | + |
| 65 | + /** |
| 66 | + * Implements Iterator interface method. |
| 67 | + */ |
| 68 | + public function rewind() { |
| 69 | + $this->sortingParts = $this->getSortingParts(); |
| 70 | + reset( $this->sortingParts ); |
| 71 | + } |
| 72 | + |
| 73 | +} |
| 74 | + |
Property changes on: trunk/extensions/WikiCitation/includes/segments/WCDataSegment.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 75 | + native |
Property changes on: trunk/extensions/WikiCitation/includes/segments |
___________________________________________________________________ |
Added: bugtraq:number |
2 | 76 | + true |
Index: trunk/extensions/WikiCitation/includes/data/WCName.php |
— | — | @@ -0,0 +1,385 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * parts structure WCName. |
| 13 | + * Contains all information needed to be known about one name, |
| 14 | + * such as an author, editor, translator, composer, etc. |
| 15 | + */ |
| 16 | +class WCName extends WCData implements Iterator { |
| 17 | + |
| 18 | + # The numerical order of the name. |
| 19 | + public $nameNumber; |
| 20 | + |
| 21 | + /** |
| 22 | + * An array of name parts keyed to WCNamePartEnum keys |
| 23 | + */ |
| 24 | + protected $parts = array(); |
| 25 | + |
| 26 | + /** |
| 27 | + * Constructor. |
| 28 | + * @param WCScopeEnum $scope = the scope (i.e., work, container, series, etc.) |
| 29 | + * @param WCNameTypeEnum $nameType = the type of name. |
| 30 | + * @param integer $nameNumber = the numerical order of the name. |
| 31 | + */ |
| 32 | + public function __construct( $nameNumber ) { |
| 33 | + $this->nameNumber = $nameNumber; |
| 34 | + } |
| 35 | + |
| 36 | + |
| 37 | + /** |
| 38 | + * Implements Iterator interface method. |
| 39 | + * @return type |
| 40 | + */ |
| 41 | + public function key() { |
| 42 | + return key( $this->parts ); |
| 43 | + } |
| 44 | + |
| 45 | + /** |
| 46 | + * Implements Iterator interface method. |
| 47 | + * @return type |
| 48 | + */ |
| 49 | + public function current() { |
| 50 | + return current( $this->parts ); |
| 51 | + } |
| 52 | + |
| 53 | + /** |
| 54 | + * Implements Iterator interface method. |
| 55 | + * @return type |
| 56 | + */ |
| 57 | + public function next() { |
| 58 | + return next( $this->parts ); |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * Implements Iterator interface method. |
| 63 | + * @return type |
| 64 | + */ |
| 65 | + public function valid() { |
| 66 | + return (bool) current( $this->parts ); |
| 67 | + } |
| 68 | + |
| 69 | + /** |
| 70 | + * Implements Iterator interface method. |
| 71 | + * @return type |
| 72 | + */ |
| 73 | + public function rewind() { |
| 74 | + return reset( $this->parts ); |
| 75 | + } |
| 76 | + |
| 77 | + |
| 78 | + public function getPart( $partKey ) { |
| 79 | + if ( isset( $this->parts[ $partKey ] ) ) { |
| 80 | + return $this->parts[ $partKey ]; |
| 81 | + } else { |
| 82 | + return Null; |
| 83 | + } |
| 84 | + } |
| 85 | + |
| 86 | + |
| 87 | + public function setPart( WCNamePartEnum $part, $value ) { |
| 88 | + $this->parts[ $part->key ] = $value; |
| 89 | + } |
| 90 | + |
| 91 | + |
| 92 | + /** |
| 93 | + * Determine if $this can be considered a short form of argument. |
| 94 | + * If so, then determine the number of matches. |
| 95 | + * |
| 96 | + * @param WCName $name |
| 97 | + * @return integer|boolean |
| 98 | + */ |
| 99 | + public function shortFormMatches( WCData $name ) { |
| 100 | + $matches = 0; |
| 101 | + foreach( $this->parts as $partKey => $part ) { |
| 102 | + $otherPart = $name->getPart( $partKey ); |
| 103 | + if ( isset( $otherPart ) && strnatcasecmp( $part, $otherPart ) === 0 ) { |
| 104 | + ++$matches; |
| 105 | + } else { |
| 106 | + return False; |
| 107 | + } |
| 108 | + } |
| 109 | + return $matches; |
| 110 | + |
| 111 | + } |
| 112 | + |
| 113 | + |
| 114 | + /** |
| 115 | + * Composes a single name based on name parts and flags |
| 116 | + * |
| 117 | + * @param boolean $namesort = whether the surname appears first |
| 118 | + * @return string = composed name |
| 119 | + */ |
| 120 | + public function render( |
| 121 | + WCStyle $style, |
| 122 | + WCCitationLengthEnum $citationLength, |
| 123 | + $endSeparator = '', |
| 124 | + $namesort = False ) { |
| 125 | + |
| 126 | + |
| 127 | + $surname = isset( $this->parts[ WCNamePartEnum::surname ] ) ? |
| 128 | + $this->parts[ WCNamePartEnum::surname ] : Null; |
| 129 | + $given = isset( $this->parts[ WCNamePartEnum::given ] ) ? |
| 130 | + $this->transformGivenNames( $this->parts[ WCNamePartEnum::given ] ) : Null; |
| 131 | + $link = isset( $this->parts[ WCNamePartEnum::nameLink ] ) ? |
| 132 | + $this->parts[ WCNamePartEnum::nameLink ] : Null; |
| 133 | + $dp = isset( $this->parts[ WCNamePartEnum::droppingParticle ] ) ? |
| 134 | + $this->parts[ WCNamePartEnum::droppingParticle ] : Null; |
| 135 | + $dpSpace = $ndpSpace = $suffixSpace = ''; |
| 136 | + if ( $dp ) { |
| 137 | + # if the dropping particle ends in punctuation, there is no space between it and the surname or dropping particle. |
| 138 | + if ( preg_match( '/\p{P}$/u', $dp, $matches ) ) { |
| 139 | + $dpSpace = ''; |
| 140 | + } else { |
| 141 | + $dpSpace = $style->nameWhitespace; |
| 142 | + } |
| 143 | + } |
| 144 | + $ndp = isset( $this->parts[ WCNamePartEnum::nonDroppingParticle ] ) ? |
| 145 | + $this->parts[ WCNamePartEnum::nonDroppingParticle ] : Null; |
| 146 | + if ( $ndp ) { |
| 147 | + # if the non-dropping particle ends in punctuation, there is no space between it and the surname. |
| 148 | + if ( preg_match( '/\p{P}$/u', $ndp, $matches ) ) { |
| 149 | + $ndpSpace = ''; |
| 150 | + } else { |
| 151 | + $ndpSpace = $style->nameWhitespace; |
| 152 | + } |
| 153 | + } |
| 154 | + $suffix = isset( $this->parts[ WCNamePartEnum::suffix ] ) ? |
| 155 | + $this->parts[ WCNamePartEnum::suffix ] : Null; |
| 156 | + if ( $suffix ) { |
| 157 | + $suffixSpace = $style->nameSuffixDelimiter; |
| 158 | + } |
| 159 | + $literal = isset( $this->parts[ WCNamePartEnum::literal ] ) ? |
| 160 | + $this->parts[ WCNamePartEnum::literal ] : Null; |
| 161 | + |
| 162 | + # literal/organizational name |
| 163 | + if ( $literal ) { |
| 164 | + # Trim redundant separator characters |
| 165 | + $chrL = mb_substr( $literal, -1, 1 ); |
| 166 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 167 | + if ( $chrL == $chrR ) { |
| 168 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 169 | + } |
| 170 | + return WCStyle::makeWikiLink( $link, $literal, WCStyle::nameHTML ) . $endSeparator; |
| 171 | + }; |
| 172 | + |
| 173 | + $pre = $post = ''; |
| 174 | + |
| 175 | + # short form |
| 176 | + if ( $citationLength->key == WCCitationLengthEnum::short ) { |
| 177 | + if ( $surname ) { |
| 178 | + if ( $ndp ) { |
| 179 | + $surname = $ndp . $ndpSpace . $surname; |
| 180 | + } |
| 181 | + } else { |
| 182 | + if ( $link ) { |
| 183 | + $post = $link; |
| 184 | + } elseif ( $given ) { |
| 185 | + $post = $given; |
| 186 | + } else { |
| 187 | + $post = $dp . $dpSpace . $ndp . $ndpSpace . $style->missingName . $suffixSpace . $suffix; |
| 188 | + } |
| 189 | + } |
| 190 | + } |
| 191 | + |
| 192 | + # long form, name sort order |
| 193 | + elseif ( $namesort ) { |
| 194 | + if ( $surname ) { |
| 195 | + if ( !$style->demoteNonDroppingParticle && $ndp ) { |
| 196 | + $pre = $ndp . $ndpSpace; |
| 197 | + } |
| 198 | + if ( $given ) { |
| 199 | + $post = $style->sortOrderSurnameDelimiter . $given; |
| 200 | + if ( $dp ) { |
| 201 | + $post .= $style->nameWhitespace . $dp; |
| 202 | + } |
| 203 | + if ( $style->demoteNonDroppingParticle && $ndp ) { |
| 204 | + if ( $dp ) { |
| 205 | + $post .= $dpSpace; |
| 206 | + } else { |
| 207 | + $post .= $style->nameWhitespace; |
| 208 | + } |
| 209 | + $post .= $ndp; |
| 210 | + } |
| 211 | + } else { |
| 212 | + if ( $dp ) { |
| 213 | + $post .= $style->sortOrderSurnameDelimiter . $dp; |
| 214 | + } |
| 215 | + if ( $style->demoteNonDroppingParticle && $ndp ) { |
| 216 | + if ( $dp ) { |
| 217 | + $post .= $dpSpace; |
| 218 | + } else { |
| 219 | + $post .= $style->nameWhitespace; |
| 220 | + } |
| 221 | + $post .= $ndp; |
| 222 | + } |
| 223 | + } |
| 224 | + if ( $suffix ) { |
| 225 | + $post .= $suffixSpace . $suffix; |
| 226 | + } |
| 227 | + } elseif ( $link ) { |
| 228 | + $post = $link; |
| 229 | + } elseif ( $given ) { |
| 230 | + if ( $dp || $ndp || $suffix ) { |
| 231 | + if ( !$style->demoteNonDroppingParticle && $ndp ) { |
| 232 | + $post = $ndp . $ndpSpace; |
| 233 | + } |
| 234 | + $post = $style->missingName . $style->sortOrderSurnameDelimiter . $given; |
| 235 | + if ( $dp ) { |
| 236 | + $post .= $style->nameWhitespace . $dp; |
| 237 | + } |
| 238 | + if ( $style->demoteNonDroppingParticle && $ndp ) { |
| 239 | + if ( $dp ) { |
| 240 | + $post .= $dpSpace; |
| 241 | + } else { |
| 242 | + $post .= $style->nameWhitespace; |
| 243 | + } |
| 244 | + $post .= $ndp; |
| 245 | + } |
| 246 | + if ( $suffix ) { |
| 247 | + $post .= $suffixSpace . $suffix; |
| 248 | + } |
| 249 | + } else { |
| 250 | + $post = $given; |
| 251 | + } |
| 252 | + } else { |
| 253 | + if ( !$style->demoteNonDroppingParticle && $ndp ) { |
| 254 | + $post = $ndp . $ndpSpace; |
| 255 | + } else { |
| 256 | + $post = ''; |
| 257 | + } |
| 258 | + $post = $style->missingName . $style->sortOrderSurnameDelimiter . $style->missingName; |
| 259 | + if ( $dp ) { |
| 260 | + $post .= $style->nameWhitespace . $dp; |
| 261 | + } |
| 262 | + if ( $style->demoteNonDroppingParticle && $ndp ) { |
| 263 | + if ( $dp ) { |
| 264 | + $post .= $dpSpace; |
| 265 | + } else { |
| 266 | + $post .= $style->nameWhitespace; |
| 267 | + } |
| 268 | + $post .= $ndp; |
| 269 | + } |
| 270 | + if ( $suffix ) { |
| 271 | + $post .= $suffixSpace . $suffix; |
| 272 | + } |
| 273 | + } |
| 274 | + } |
| 275 | + |
| 276 | + # long form, non-name sort order |
| 277 | + else { |
| 278 | + if ( $surname ) { |
| 279 | + if ( $given ) { |
| 280 | + $pre = $given . $style->nameWhitespace; |
| 281 | + } |
| 282 | + $pre .= $dp . $dpSpace . $ndp . $ndpSpace; |
| 283 | + $post = $suffixSpace . $suffix; |
| 284 | + } elseif ( $link ) { |
| 285 | + $post = $link; |
| 286 | + } elseif ( $given ) { |
| 287 | + $post = $given . $style->nameWhitespace; |
| 288 | + if ( $dp || $ndp || $suffix ) { |
| 289 | + $post .= $dp . $dpSpace . $ndp . $ndpSpace . $style->missingName . $suffixSpace . $suffix; |
| 290 | + } |
| 291 | + } else { |
| 292 | + $post = $style->missingName . $style->nameWhitespace; |
| 293 | + if ( $dp ) { |
| 294 | + $post .= $dp . $dpSpace . $ndp . $ndpSpace . $style->missingName . $suffixSpace . $suffix; |
| 295 | + } |
| 296 | + } |
| 297 | + } |
| 298 | + |
| 299 | + $htmlClass = WCStyle::nameHTML; |
| 300 | + |
| 301 | + if ( $namesort ) { |
| 302 | + $surnameClass = WCStyle::surnameSortOrderHTML; |
| 303 | + } else { |
| 304 | + $surnameClass = WCStyle::surnameHTML; |
| 305 | + } |
| 306 | + |
| 307 | + # Trim redundant separator characters |
| 308 | + if ( $post ) { |
| 309 | + $chrL = mb_substr( $post, -1, 1 ); |
| 310 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 311 | + if ( $chrL == $chrR ) { |
| 312 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 313 | + } |
| 314 | + if ( $surname) { |
| 315 | + $nameText = $pre . WCStyle::wrapHTMLSpan( $surname, $surnameClass ) . $post; |
| 316 | + } else { |
| 317 | + $nameText = $pre . $post; |
| 318 | + } |
| 319 | + } elseif ( $surname) { |
| 320 | + $chrL = mb_substr( $surname, -1, 1 ); |
| 321 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 322 | + if ( $chrL == $chrR ) { |
| 323 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 324 | + } |
| 325 | + if ( $pre ) { |
| 326 | + $nameText = $pre . WCStyle::wrapHTMLSpan( $surname, $surnameClass ); |
| 327 | + } else { |
| 328 | + $nameText = $surname; |
| 329 | + $htmlClass .= ' ' . $surnameClass; |
| 330 | + } |
| 331 | + } else { |
| 332 | + $chrL = mb_substr( $pre, -1, 1 ); |
| 333 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 334 | + if ( $chrL == $chrR ) { |
| 335 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 336 | + } |
| 337 | + $nameText = $pre; |
| 338 | + } |
| 339 | + |
| 340 | + return WCStyle::makeWikiLink( $link, $nameText, $htmlClass ) . $endSeparator; |
| 341 | + |
| 342 | + } |
| 343 | + |
| 344 | + |
| 345 | + public function __toString() { |
| 346 | + return implode( ' ', $this->parts ); |
| 347 | + } |
| 348 | + |
| 349 | + |
| 350 | + public function getSortingParts() { |
| 351 | + if ( isset( $this->parts[ WCNamePartEnum::literal ] ) ) { |
| 352 | + return array( $this->parts[ WCNamePartEnum::literal ] ); |
| 353 | + } |
| 354 | + $sortName = ''; |
| 355 | + if ( isset( $this->parts[ WCNamePartEnum::surname ] ) ) { |
| 356 | + if ( isset( $this->parts[ WCNamePartEnum::nonDroppingParticle ] ) ) { |
| 357 | + $sortName = $this->parts[ WCNamePartEnum::nonDroppingParticle ] . ' '; |
| 358 | + } |
| 359 | + $sortName .= $this->parts[ WCNamePartEnum::surname ]; |
| 360 | + } |
| 361 | + if ( isset( $this->parts[ WCNamePartEnum::given ] ) ) { |
| 362 | + $sortName .= ' ' . $this->parts[ WCNamePartEnum::given ]; |
| 363 | + } |
| 364 | + if ( isset( $this->parts[ WCNamePartEnum::suffix ] ) ) { |
| 365 | + $sortName .= ' ' . $this->parts[ WCNamePartEnum::suffix ]; |
| 366 | + } |
| 367 | + if ( isset( $this->parts[ WCNamePartEnum::droppingParticle ] ) ) { |
| 368 | + $sortName .= ' ' . $this->parts[ WCNamePartEnum::droppingParticle ]; |
| 369 | + } |
| 370 | + return array( $sortName ); |
| 371 | + } |
| 372 | + |
| 373 | + |
| 374 | + /** |
| 375 | + * Transform the given names, such as by shortening them to initials only. |
| 376 | + * |
| 377 | + * To be defined by child classes. An idname function by default. |
| 378 | + * @return string |
| 379 | + */ |
| 380 | + protected function transformGivenNames( $givenNames ) { |
| 381 | + return $givenNames; |
| 382 | + } |
| 383 | + |
| 384 | + |
| 385 | +} |
| 386 | + |
Property changes on: trunk/extensions/WikiCitation/includes/data/WCName.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 387 | + native |
Index: trunk/extensions/WikiCitation/includes/data/WCTitle.php |
— | — | @@ -0,0 +1,113 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCTitleFormat extends WCEnum { |
| 12 | + const normal = 0; |
| 13 | + const quoted = 1; |
| 14 | + const italic = 2; |
| 15 | + const __default = self::normal; |
| 16 | +} |
| 17 | + |
| 18 | + |
| 19 | +/** |
| 20 | + * Data structure WCTitle. |
| 21 | + * Contains all information needed to be known about a title. |
| 22 | + */ |
| 23 | +class WCTitle extends WCData { |
| 24 | + |
| 25 | + # Regexes initialized by WCTitle::init() |
| 26 | + protected static $patternExternal, $patternInternal; |
| 27 | + |
| 28 | + # The title, as text. |
| 29 | + protected $title; |
| 30 | + |
| 31 | + /** |
| 32 | + * Static initializer. |
| 33 | + */ |
| 34 | + public static function init() { |
| 35 | + $iExQuoteMW = MagicWord::get( 'wc_initial_exterior_quote' ); |
| 36 | + $fExQuoteMW = MagicWord::get( 'wc_final_exterior_quote' ); |
| 37 | + $iInQuoteMW = MagicWord::get( 'wc_initial_interior_quote' ); |
| 38 | + $fInQuoteMW = MagicWord::get( 'wc_final_interior_quote' ); |
| 39 | + $iExQuotes = implode( $iExQuoteMW->getSynonyms() ); |
| 40 | + $fExQuotes = implode( $fExQuoteMW->getSynonyms() ); |
| 41 | + $iInQuotes = implode( $iInQuoteMW->getSynonyms() ); |
| 42 | + $fInQuotes = implode( $fInQuoteMW->getSynonyms() ); |
| 43 | + self::$patternExternal = '/(^|[\p{Ps}\p{Zs}\p{Pd}\p{Pi}\'])[' . $iExQuotes . '](.*?)[' . $fExQuotes . ']($|[\p{Pe}\p{Zs}\.,;:?!\p{Pd}\p{Pf}\'])/usS'; |
| 44 | + self::$patternInternal = '/(^|[\p{Ps}\p{Zs}\p{Pd}\p{Pi}"])[' . $iInQuotes . '](.*?)[' . $fInQuotes . ']($|[\p{Pe}\p{Zs}\.,;:?!\p{Pd}\p{Pf}"])/usS'; |
| 45 | + } |
| 46 | + |
| 47 | + /** |
| 48 | + * Constructor. |
| 49 | + * |
| 50 | + * Converts character-based quotes to semantic HTML quotes. |
| 51 | + * For now, this is done as an intermediate step to regularize quotes, and |
| 52 | + * to allow quotes to be shifted if the entire title is quoted. |
| 53 | + * This method assumes that the title does not contain quoted HTML |
| 54 | + * attributes. |
| 55 | + * |
| 56 | + * @param WCCitation $citation = the WCCitation object |
| 57 | + * @param WCScopeEnum $scope = the scope (i.e., work, container, series, etc.) |
| 58 | + * @param WCParameterEnum $type = the type of property. |
| 59 | + * @param string $title = the unprocessed text of the title. |
| 60 | + */ |
| 61 | + public function __construct( $title ) { |
| 62 | + |
| 63 | + # Regex for replacing internal quotes with markers. Searches for |
| 64 | + # pairs of internal quotes that are closest to each other. |
| 65 | + static $replacement = '$1<q>$2</q>$3'; |
| 66 | + do { # make substitutions for nested quotes until string stops changing. |
| 67 | + $oldTitle = $title; |
| 68 | + $title = preg_replace( self::$patternInternal, $replacement, $title ); |
| 69 | + } while ( $oldTitle != $title ); |
| 70 | + |
| 71 | + # replace double quotes |
| 72 | + do { # make substitutions for nested quotes until string stops changing. |
| 73 | + $oldTitle = $title; |
| 74 | + $title = preg_replace( self::$patternExternal, $replacement, $title ); |
| 75 | + } while ( $oldTitle != $title ); |
| 76 | + |
| 77 | + $this->title = $title; |
| 78 | + |
| 79 | + } |
| 80 | + |
| 81 | + |
| 82 | + /** |
| 83 | + * Get title. |
| 84 | + * @return string |
| 85 | + */ |
| 86 | + public function getTitle() { |
| 87 | + return $this->title; |
| 88 | + } |
| 89 | + |
| 90 | + |
| 91 | + public function __toString() { |
| 92 | + return $this->title; |
| 93 | + } |
| 94 | + |
| 95 | + |
| 96 | + /** |
| 97 | + * Determine if $this can be considered a short form of the argument. |
| 98 | + * If so, then determine the number of matches. |
| 99 | + * |
| 100 | + * @param WCTitle $title |
| 101 | + * @return integer|boolean |
| 102 | + */ |
| 103 | + public function shortFormMatches( WCData $title ) { |
| 104 | + return strnatcasecmp( $this->title, $title->getTitle() ) === 0 ? 1 : False; |
| 105 | + } |
| 106 | + |
| 107 | + |
| 108 | +} |
| 109 | + |
| 110 | +/** |
| 111 | + * Static initializer. |
| 112 | + */ |
| 113 | +WCTitle::init(); |
| 114 | + |
Property changes on: trunk/extensions/WikiCitation/includes/data/WCTitle.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 115 | + native |
Index: trunk/extensions/WikiCitation/includes/data/WCLocator.php |
— | — | @@ -0,0 +1,101 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Data structure WCLocator. |
| 13 | + * Stores and renders a location or range of locations in a source. |
| 14 | + */ |
| 15 | +class WCLocator { |
| 16 | + |
| 17 | + public $ranges; |
| 18 | + |
| 19 | + protected static $listTerms, $rangeTerms; |
| 20 | + |
| 21 | + public static function init() { |
| 22 | + $listDelimiterMW = MagicWord::get( 'wc_list_delimiter' ); |
| 23 | + $rangeDelimiterMW = MagicWord::get( 'wc_range_delimiter' ); |
| 24 | + self::$listTerms = '\s*' . implode( '\s*|\s*', $listDelimiterMW->getSynonyms() ) . '\s*|\s+'; |
| 25 | + self::$rangeTerms = '/^\p{Zs}*[\p{Pi}"\']?((?(?<=[\p{Pi}"\']).*?(?=[\p{Pf}"\'])|(?(?=\p{Ps}).+?\p{Pe}|.))*?)[\p{Pf}"\']?\p{Zs}*(?:' . implode( '|', $rangeDelimiterMW->getSynonyms() ) . '|\p{Pd})\p{Zs}*[\p{Pi}"\']*(.*?)[\p{Pf}"\']*\p{Zs}*$/uS'; |
| 26 | + } |
| 27 | + |
| 28 | + /** |
| 29 | + * Constructor. |
| 30 | + * This should be able to handle complex ranges like |
| 31 | + * "45(iv)45-(v)7, 45(ii)52-61, and 45(ix)99-100". |
| 32 | + * A dash or hyphen will be interpreted as a range, unless the number is |
| 33 | + * enclosed in quotation marks. |
| 34 | + * @param WCCitation $citation = the WCCitation object |
| 35 | + * @param WCScopeEnum $scope = the scope (i.e., work, container, series, etc.) |
| 36 | + * @param WCParameterEnum $type = the type of property. |
| 37 | + * @param string $text = the unprocessed locator text. |
| 38 | + */ |
| 39 | + public function __construct( $text ) { |
| 40 | + $this->ranges = mb_split( self::$listTerms, $text ); # Split by range-delimiting terms like comma or and |
| 41 | + foreach( $this->ranges as &$range ) { |
| 42 | + if ( !preg_match( self::$rangeTerms, $range, $matches ) ) { |
| 43 | + $range = array( $range ); |
| 44 | + continue; |
| 45 | + } |
| 46 | + $range = array( $matches[1], $matches[2] ); |
| 47 | + } |
| 48 | + return; |
| 49 | + } |
| 50 | + |
| 51 | + |
| 52 | + /** |
| 53 | + * Render the text. |
| 54 | + * @return string |
| 55 | + */ |
| 56 | + public function render( $endSeparator = '' ) { |
| 57 | + $text = ''; |
| 58 | + $rangeCount = count( $this->ranges ); |
| 59 | + # single range: |
| 60 | + if ( $rangeCount == 1 ) { |
| 61 | + $text = implode( '–', reset( $this->ranges ) ); |
| 62 | + } |
| 63 | + # two ranges |
| 64 | + elseif ( $rangeCount == 2 ) { |
| 65 | + $text = implode( '–', reset( $this->ranges ) ); |
| 66 | + $text .= ' & ' . implode( '–', next( $this->ranges ) ); |
| 67 | + } |
| 68 | + # three or more ranges: |
| 69 | + else { |
| 70 | + $text = implode( '–', reset( $this->ranges ) ); |
| 71 | + for ( $i = 2; $i < $rangeCount-1; $i++ ) { |
| 72 | + $text .= ', ' . implode( '–', next( $this->ranges ) ); |
| 73 | + } |
| 74 | + $text .= ' & ' . implode( '–', next( $this->ranges ) ); |
| 75 | + } |
| 76 | + if ( $endSeparator ) { |
| 77 | + $chrL = mb_substr( $text, -1, 1 ); |
| 78 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 79 | + if ( $chrL == $chrR ) { |
| 80 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 81 | + } |
| 82 | + return $text . $endSeparator; |
| 83 | + } else { |
| 84 | + return $text; |
| 85 | + } |
| 86 | + } |
| 87 | + |
| 88 | + |
| 89 | + public function __toString() { |
| 90 | + $arr = $this->ranges; |
| 91 | + foreach( $arr as &$range ) { |
| 92 | + $range = implode( '–', $range ); |
| 93 | + } |
| 94 | + return implode( ', ', $arr ); |
| 95 | + } |
| 96 | + |
| 97 | +} |
| 98 | + |
| 99 | +/** |
| 100 | + * Static initializer |
| 101 | + */ |
| 102 | +WCLocator::init(); |
\ No newline at end of file |
Property changes on: trunk/extensions/WikiCitation/includes/data/WCLocator.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 103 | + native |
Index: trunk/extensions/WikiCitation/includes/data/WCNames.php |
— | — | @@ -0,0 +1,224 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Data structure WCNames. |
| 13 | + * Contains information about a group of names, |
| 14 | + * such as authors, editors, translators, composers, etc. |
| 15 | + */ |
| 16 | +class WCNames extends WCData implements Countable, Iterator { |
| 17 | + |
| 18 | + /** |
| 19 | + * Array of names |
| 20 | + * @var array |
| 21 | + */ |
| 22 | + protected $names = array(); |
| 23 | + |
| 24 | + |
| 25 | + /** |
| 26 | + * Implements Iterator interface method. |
| 27 | + * @return type |
| 28 | + */ |
| 29 | + public function count() { |
| 30 | + return count( $this->names ); |
| 31 | + } |
| 32 | + |
| 33 | + /** |
| 34 | + * Implements Iterator interface method. |
| 35 | + * @return type |
| 36 | + */ |
| 37 | + public function key() { |
| 38 | + return key( $this->names ); |
| 39 | + } |
| 40 | + |
| 41 | + /** |
| 42 | + * Implements Iterator interface method. |
| 43 | + * @return type |
| 44 | + */ |
| 45 | + public function current() { |
| 46 | + return current( $this->names ); |
| 47 | + } |
| 48 | + |
| 49 | + /** |
| 50 | + * Implements Iterator interface method. |
| 51 | + * @return type |
| 52 | + */ |
| 53 | + public function next() { |
| 54 | + return next( $this->names ); |
| 55 | + } |
| 56 | + |
| 57 | + /** |
| 58 | + * Implements Iterator interface method. |
| 59 | + * @return type |
| 60 | + */ |
| 61 | + public function valid() { |
| 62 | + return (bool) current( $this->names ); |
| 63 | + } |
| 64 | + |
| 65 | + /** |
| 66 | + * Implements Iterator interface method. |
| 67 | + * @return type |
| 68 | + */ |
| 69 | + public function rewind() { |
| 70 | + return reset( $this->names ); |
| 71 | + } |
| 72 | + |
| 73 | + |
| 74 | + /** |
| 75 | + * Sort names on the basis of number. |
| 76 | + */ |
| 77 | + public function sort() { |
| 78 | + ksort( $this->names ); |
| 79 | + } |
| 80 | + |
| 81 | + |
| 82 | + /** |
| 83 | + * Determine if $this can be considered a short form of the argument. |
| 84 | + * If so, then determine the number of matches. |
| 85 | + * |
| 86 | + * @param WCNames $names |
| 87 | + * @return integer|boolean |
| 88 | + */ |
| 89 | + public function shortFormMatches( WCData $names ) { |
| 90 | + $matches = 0; |
| 91 | + foreach( $this->names as $nameKey => $thisName ) { |
| 92 | + $otherName = $names->getName( $nameKey ); |
| 93 | + $subMatches = $thisName->shortFormMatches( $otherName ); |
| 94 | + if ( $subMatches === False ) { |
| 95 | + return False; |
| 96 | + } else { |
| 97 | + $matches += $subMatches; |
| 98 | + } |
| 99 | + } |
| 100 | + return $matches; |
| 101 | + |
| 102 | + } |
| 103 | + |
| 104 | + |
| 105 | + /** |
| 106 | + * Renders a section of name info based on a group of names, |
| 107 | + * such as authors, editors, etc. |
| 108 | + * |
| 109 | + * @param boolean $namesort = whether the surname appears first |
| 110 | + * @return string = rendereded name section |
| 111 | + */ |
| 112 | + public function render( |
| 113 | + WCStyle $style, |
| 114 | + WCCitationPosition $citationPosition, |
| 115 | + WCCitationLengthEnum $citationLength, |
| 116 | + $endSeparator = '', |
| 117 | + $namesort = False ) { |
| 118 | + |
| 119 | + $nameCount = $this->count(); |
| 120 | + |
| 121 | + # no names: |
| 122 | + if ( !$nameCount ) { |
| 123 | + return ''; |
| 124 | + } |
| 125 | + |
| 126 | + # single name: |
| 127 | + if ( $nameCount == 1 ) { |
| 128 | + return $this->rewind()->render( $style, $citationLength, $endSeparator, $namesort ); |
| 129 | + } |
| 130 | + |
| 131 | + # determine whether we are using "et al." or equivalent |
| 132 | + if( $citationPosition->key == WCCitationPosition::first ) { |
| 133 | + $etAlMin = $style->etAlMin; |
| 134 | + $etAlUseFirst = $style->etAlUseFirst; |
| 135 | + } else { |
| 136 | + $etAlMin = $style->etAlSubsequentMin; |
| 137 | + $etAlUseFirst = $style->etAlSubsequentUseFirst; |
| 138 | + } |
| 139 | + $usingEtAl = $nameCount > $etAlMin; |
| 140 | + if ( $usingEtAl ) { |
| 141 | + $nameCount = $etAlUseFirst; |
| 142 | + } |
| 143 | + |
| 144 | + # single name with et al.: |
| 145 | + if ( $nameCount == 1 ) { |
| 146 | + $text = $this->rewind()->render( $style, $citationLength, $nameStyle->$etAlDelimiter, $namesort ); |
| 147 | + } |
| 148 | + |
| 149 | + # two names |
| 150 | + elseif ( $nameCount == 2 ) { |
| 151 | + $text = $this->rewind()->render( $style, $citationLength, $style->and2, $namesort ); |
| 152 | + if ( $usingEtAl ) { |
| 153 | + $text .= $this->next()->render( $style, $citationLength, $nameStyle->$etAlDelimiter, False ); |
| 154 | + } else { |
| 155 | + $text .= $this->next()->render( $style, $citationLength, $endSeparator, False ); |
| 156 | + } |
| 157 | + } |
| 158 | + |
| 159 | + # three or more names: |
| 160 | + else { |
| 161 | + $text = $this->rewind()->render( $style, $citationLength, $style->namesDelimiter, $namesort ); |
| 162 | + for ( $i = 2; $i < $nameCount-1; $i++ ) { |
| 163 | + $text .= $this->next()->render( $style, $citationLength, $style->namesDelimiter, False ); |
| 164 | + } |
| 165 | + $text .= $this->next()->render( $style, $citationLength, $style->and3, False ); |
| 166 | + if ( $usingEtAl ) { |
| 167 | + $text .= $this->next()->render( $style, $citationLength, $nameStyle->$etAlDelimiter, False ); |
| 168 | + } else { |
| 169 | + $text .= $this->next()->render( $style, $citationLength, $endSeparator, False ); |
| 170 | + } |
| 171 | + } |
| 172 | + |
| 173 | + # et al. |
| 174 | + if ( $usingEtAl ) { |
| 175 | + # Trim redundant separator characters |
| 176 | + $etal = $style->etAl; |
| 177 | + $chrL = mb_substr( $etal, -1, 1 ); |
| 178 | + $chrR = mb_substr( $endSeparator, 0, 1 ); |
| 179 | + $text .= $etal; |
| 180 | + if ( $chrL == $chrR ) { |
| 181 | + $endSeparator = ltrim( $endSeparator, $chrR ); |
| 182 | + } |
| 183 | + $text .= $endSeparator; |
| 184 | + |
| 185 | + } |
| 186 | + |
| 187 | + return $text; |
| 188 | + } |
| 189 | + |
| 190 | + |
| 191 | + public function __toString() { |
| 192 | + return implode( ' ', $this->names ); |
| 193 | + } |
| 194 | + |
| 195 | + |
| 196 | + public function getName( $nameNumber ) { |
| 197 | + if ( isset( $this->names[ $nameNumber ] ) ) { |
| 198 | + return $this->names[ $nameNumber ]; |
| 199 | + } else { |
| 200 | + return Null; |
| 201 | + } |
| 202 | + } |
| 203 | + |
| 204 | + public function setName( $nameNumber, $value ) { |
| 205 | + $this->names[ $nameNumber ] = $value; |
| 206 | + } |
| 207 | + |
| 208 | + public function getNamePart( $nameNumber, WCNamePartEnum $namePart ) { |
| 209 | + if ( isset( $this->names[ $nameNumber ] ) ) { |
| 210 | + return $this->names[ $nameNumber ]->getPart( $namePart->key ); |
| 211 | + } else { |
| 212 | + return Null; |
| 213 | + } |
| 214 | + } |
| 215 | + |
| 216 | + public function setNamePart( $nameNumber, WCNamePartEnum $namePart, $value ) { |
| 217 | + $name = &$this->names[ $nameNumber ]; |
| 218 | + if ( is_null( $name ) ) { |
| 219 | + $name = new WCName( $nameNumber ); |
| 220 | + } |
| 221 | + $name->setPart( $namePart, $value ); |
| 222 | + } |
| 223 | + |
| 224 | +} |
| 225 | + |
Property changes on: trunk/extensions/WikiCitation/includes/data/WCNames.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 226 | + native |
Index: trunk/extensions/WikiCitation/includes/data/WCText.php |
— | — | @@ -0,0 +1,59 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Data structure WCText. |
| 13 | + * Stores and renders a text attribute. |
| 14 | + */ |
| 15 | +class WCText extends WCData { |
| 16 | + |
| 17 | + # The text. |
| 18 | + protected $text; |
| 19 | + |
| 20 | + |
| 21 | + /** |
| 22 | + * Constructor. |
| 23 | + * @param WCCitation $citation = the WCCitation object |
| 24 | + * @param WCScopeEnum $scope = the scope (i.e., work, container, series, etc.) |
| 25 | + * @param WCParameterEnum $type = the type of property. |
| 26 | + * @param string $text = the unprocessed text. |
| 27 | + */ |
| 28 | + public function __construct( $text ) { |
| 29 | + $this->text = $text; |
| 30 | + } |
| 31 | + |
| 32 | + |
| 33 | + /** |
| 34 | + * Get text. |
| 35 | + * @return string |
| 36 | + */ |
| 37 | + public function getText() { |
| 38 | + return $this->text; |
| 39 | + } |
| 40 | + |
| 41 | + |
| 42 | + public function __toString() { |
| 43 | + return $this->text; |
| 44 | + } |
| 45 | + |
| 46 | + |
| 47 | + /** |
| 48 | + * Determine if $this can be considered a short form of the argument. |
| 49 | + * If so, then determine the number of matches. |
| 50 | + * |
| 51 | + * @param WCText $text |
| 52 | + * @return integer|boolean |
| 53 | + */ |
| 54 | + public function shortFormMatches( WCData $text ) { |
| 55 | + if ( strnatcasecmp( $this->text === $text->getText() ) === 0 ) return 1; else return False; |
| 56 | + } |
| 57 | + |
| 58 | + |
| 59 | +} |
| 60 | + |
Property changes on: trunk/extensions/WikiCitation/includes/data/WCText.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 61 | + native |
Index: trunk/extensions/WikiCitation/includes/data/WCData.php |
— | — | @@ -0,0 +1,18 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +abstract class WCData { |
| 12 | + |
| 13 | + /** |
| 14 | + * Tests whether $this can be considered a short form of argument $data. |
| 15 | + * @param WCData $data |
| 16 | + */ |
| 17 | + abstract public function shortFormMatches( WCData $data ); |
| 18 | + |
| 19 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/data/WCData.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 20 | + native |
Index: trunk/extensions/WikiCitation/includes/data/WCTypeData.php |
— | — | @@ -0,0 +1,65 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Data structure WCTypeData. |
| 13 | + * Stores and renders the work type (e.g., book, article, etc.). |
| 14 | + */ |
| 15 | +class WCTypeData extends WCData { |
| 16 | + |
| 17 | + /** |
| 18 | + * The enumerated attribute. |
| 19 | + * @var WCParameterEnum |
| 20 | + */ |
| 21 | + public $parameter; |
| 22 | + |
| 23 | + |
| 24 | + /** |
| 25 | + * Constructor. |
| 26 | + * |
| 27 | + * Tests to see whether $value is a valid parameter. If not, it throws a |
| 28 | + * exception if $wikiCitationValidateArguments is set. |
| 29 | + * @global $wikiCitationValidateArguments |
| 30 | + * @param string|WCParameterEnum $value = the text, which may or may not be a |
| 31 | + * valid parameter, or the WCParameterEnum object. |
| 32 | + */ |
| 33 | + public function __construct( $value = Null ) { |
| 34 | + |
| 35 | + if ( $value instanceOf WCSourceTypeEnum ) { |
| 36 | + $parameterType = $value; |
| 37 | + } else { |
| 38 | + global $wikiCitationValidateArguments; |
| 39 | + $parameterType = WCSourceTypeEnum::match( $value, WCSourceTypeEnum::$magicWordArray, |
| 40 | + WCSourceTypeEnum::$flipMagicWordKeys, 'WCTypeEnum' ); |
| 41 | + if ( !$parameterType && $wikiCitationValidateArguments ) { |
| 42 | + throw new WCException( 'wc-type-parameter-unknown', $parameterType ); |
| 43 | + } |
| 44 | + } |
| 45 | + $this->parameter = $parameterType; |
| 46 | + } |
| 47 | + |
| 48 | + |
| 49 | + public function __toString() { |
| 50 | + return (string) $this->parameter; |
| 51 | + } |
| 52 | + |
| 53 | + |
| 54 | + /** |
| 55 | + * Determine if $this can be considered a short form of the argument. |
| 56 | + * If so, then determine the number of matches. |
| 57 | + * |
| 58 | + * @param WCTypeData $typeData |
| 59 | + * @return integer|boolean |
| 60 | + */ |
| 61 | + public function shortFormMatches( WCData $typeData ) { |
| 62 | + return $this->parameter === $typeData->parameter ? 1 : False; |
| 63 | + } |
| 64 | + |
| 65 | +} |
| 66 | + |
Property changes on: trunk/extensions/WikiCitation/includes/data/WCTypeData.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 67 | + native |
Index: trunk/extensions/WikiCitation/includes/data/WCDate.php |
— | — | @@ -0,0 +1,1119 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCDateNumber { |
| 12 | + const unknown = 0; |
| 13 | + const day = 1; |
| 14 | + const month = 2; |
| 15 | + const year = 3; |
| 16 | + const notDay = 4; |
| 17 | + const notMonth = 5; |
| 18 | + const notYear = 6; |
| 19 | + |
| 20 | + public $key, $num; |
| 21 | + public $numType; |
| 22 | + public function __construct( $key, $num, $type = self::unknown ) { |
| 23 | + $this->key = $key; |
| 24 | + $this->num = $num; |
| 25 | + $this->numType = $type; |
| 26 | + } |
| 27 | + public function setDay( array &$unknowns, array &$days ) { |
| 28 | + switch ( $this->numType ) { |
| 29 | + case self::unknown: |
| 30 | + case self::notMonth: |
| 31 | + case self::notYear: |
| 32 | + $this->numType = self::day; |
| 33 | + unset( $unknowns[ $this->key ] ); |
| 34 | + $days[ $this->key ] = $this->num; |
| 35 | + return; |
| 36 | + default: |
| 37 | + return; |
| 38 | + } |
| 39 | + } |
| 40 | + public function setMonth( array &$unknowns, array &$months ) { |
| 41 | + switch ( $this->numType ) { |
| 42 | + case self::unknown: |
| 43 | + case self::notDay: |
| 44 | + case self::notYear: |
| 45 | + $this->numType = self::month; |
| 46 | + unset( $unknowns[ $this->key ] ); |
| 47 | + $months[ $this->key ] = $this->num; |
| 48 | + return; |
| 49 | + default: |
| 50 | + return; |
| 51 | + } |
| 52 | + } |
| 53 | + public function setYear( array &$unknowns, array &$years ) { |
| 54 | + switch ( $this->numType ) { |
| 55 | + case self::unknown: |
| 56 | + case self::notDay: |
| 57 | + case self::notMonth: |
| 58 | + $this->numType = self::year; |
| 59 | + unset( $unknowns[ $this->key ] ); |
| 60 | + $years[ $this->key ] = $this->num; |
| 61 | + return; |
| 62 | + default: |
| 63 | + return; |
| 64 | + } |
| 65 | + } |
| 66 | + public function setNotDay( array &$unknowns, array &$months, array &$years ) { |
| 67 | + switch ( $this->numType ) { |
| 68 | + case self::unknown: |
| 69 | + $this->numType = self::notDay; |
| 70 | + return; |
| 71 | + case self::notMonth: |
| 72 | + $this->numType = self::year; |
| 73 | + unset( $unknowns[ $this->key ] ); |
| 74 | + $years[ $this->key ] = $this->num; |
| 75 | + return; |
| 76 | + case self::notYear: |
| 77 | + $this->numType = self::month; |
| 78 | + unset( $unknowns[ $this->key ] ); |
| 79 | + $months[ $this->key ] = $this->num; |
| 80 | + return; |
| 81 | + default: |
| 82 | + return; |
| 83 | + } |
| 84 | + } |
| 85 | + public function setNotMonth( array &$unknowns, array &$days, array &$years ) { |
| 86 | + switch ( $this->numType ) { |
| 87 | + case self::unknown: |
| 88 | + $this->numType = self::notMonth; |
| 89 | + return; |
| 90 | + case self::notDay: |
| 91 | + $this->numType = self::year; |
| 92 | + unset( $unknowns[ $this->key ] ); |
| 93 | + $years[ $this->key ] = $this->num; |
| 94 | + return; |
| 95 | + case self::notYear: |
| 96 | + $this->numType = self::day; |
| 97 | + unset( $unknowns[ $this->key ] ); |
| 98 | + $days[ $this->key ] = $this->num; |
| 99 | + return; |
| 100 | + default: |
| 101 | + return; |
| 102 | + } |
| 103 | + } |
| 104 | + public function setNotYear( array &$unknowns, array &$days, array &$months ) { |
| 105 | + switch ( $this->numType ) { |
| 106 | + case self::unknown: |
| 107 | + $this->numType = self::notYear; |
| 108 | + return; |
| 109 | + case self::notDay: |
| 110 | + $this->numType = self::month; |
| 111 | + unset( $unknowns[ $this->key ] ); |
| 112 | + $months[ $this->key ] = $this->num; |
| 113 | + return; |
| 114 | + case self::notMonth: |
| 115 | + $this->numType = self::day; |
| 116 | + unset( $unknowns[ $this->key ] ); |
| 117 | + $days[ $this->key ] = $this->num; |
| 118 | + return; |
| 119 | + default: |
| 120 | + return; |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + public function isNotDay() { |
| 125 | + return $this->numType == WCDateNumber::month || $this->numType == WCDateNumber::year || $this->numType == WCDateNumber::notDay; |
| 126 | + } |
| 127 | + public function isNotMonth() { |
| 128 | + return $this->numType == WCDateNumber::day || $this->numType == WCDateNumber::year || $this->numType == WCDateNumber::notMonth; |
| 129 | + } |
| 130 | + public function isNotYear() { |
| 131 | + return $this->numType == WCDateNumber::day || $this->numType == WCDateNumber::month || $this->numType == WCDateNumber::notYear; |
| 132 | + } |
| 133 | + public function couldBeDay() { |
| 134 | + return $this->numType == WCDateNumber::day || $this->numType == WCDateNumber::unknown || $this->numType == WCDateNumber::notMonth || $this->numType == WCDateNumber::notYear; |
| 135 | + } |
| 136 | + public function couldBeMonth() { |
| 137 | + return $this->numType == WCDateNumber::month || $this->numType == WCDateNumber::unknown || $this->numType == WCDateNumber::notDay || $this->numType == WCDateNumber::notYear; |
| 138 | + } |
| 139 | + public function couldBeYear() { |
| 140 | + return $this->numType == WCDateNumber::year || $this->numType == WCDateNumber::unknown || $this->numType == WCDateNumber::notDay || $this->numType == WCDateNumber::notMonth; |
| 141 | + } |
| 142 | + |
| 143 | +} |
| 144 | + |
| 145 | +/** |
| 146 | + * Data structure WCDate. |
| 147 | + * Contains all information needed to be known about a title. |
| 148 | + */ |
| 149 | +class WCDate extends WCData { |
| 150 | + |
| 151 | + # The year, or beginning year of a range. |
| 152 | + public $year; |
| 153 | + |
| 154 | + # The end year of a range |
| 155 | + public $year2; |
| 156 | + |
| 157 | + # The era (AD, BC, etc.), or beginning era of a range. WCDateTermsEnum::AD, etc. |
| 158 | + public $era; |
| 159 | + |
| 160 | + # The end era of a range |
| 161 | + public $era2; |
| 162 | + |
| 163 | + # The month, or beginning month of a range. |
| 164 | + public $month; |
| 165 | + |
| 166 | + # The end month of a range |
| 167 | + public $month2; |
| 168 | + |
| 169 | + # The season, or beginning season of a range. WCDateTermsEnum::spring, etc. |
| 170 | + public $season; |
| 171 | + |
| 172 | + # The end season of a range |
| 173 | + public $season2; |
| 174 | + |
| 175 | + # The day, or beginning day of a range. |
| 176 | + public $day; |
| 177 | + |
| 178 | + # The end day of a range |
| 179 | + public $day2; |
| 180 | + |
| 181 | + /** |
| 182 | + * Whether the date, or beginning of date range is uncertain |
| 183 | + * @var boolean |
| 184 | + */ |
| 185 | + public $isUncertain; |
| 186 | + |
| 187 | + /** |
| 188 | + * Whether the second date is uncertain |
| 189 | + * @var boolean |
| 190 | + */ |
| 191 | + public $isUncertain2; |
| 192 | + |
| 193 | + /** |
| 194 | + * Constructor. |
| 195 | + * @param WCCitation $citation = the WCCitation object |
| 196 | + * @param WCScopeEnum $scope = the scope (i.e., work, container, series, etc.) |
| 197 | + * @param WCParameterEnum $type = the type of property. |
| 198 | + * @param string date = the unprocessed date text. |
| 199 | + */ |
| 200 | + public function __construct( $date ) { |
| 201 | + |
| 202 | + # Separate into segments comprising numbers, letters, or special terms. |
| 203 | + $adTerms = MagicWord::get( WCDateTermsEnum::$magicWordKeys[ WCDateTermsEnum::AD ] )->getSynonyms(); |
| 204 | + $bcTerms = MagicWord::get( WCDateTermsEnum::$magicWordKeys[ WCDateTermsEnum::BC ] )->getSynonyms(); |
| 205 | + $circaTerms = MagicWord::get( WCDateTermsEnum::$magicWordKeys[ WCDateTermsEnum::circa ] )->getSynonyms(); |
| 206 | + $options = implode( '|', array_merge( $adTerms, $bcTerms, $circaTerms ) ); |
| 207 | + if ( !preg_match_all( '/'. $options . '|\p{N}+|\p{L}+|./uS', $date, $matches ) ) { |
| 208 | + $this->year = 0; |
| 209 | + $this->era = WCDateTermsEnum::AD; |
| 210 | + $this->month = 0; |
| 211 | + $this->day = 0; |
| 212 | + $this->isUncertain = True; |
| 213 | + return; |
| 214 | + } |
| 215 | + |
| 216 | + $chunks = $matches[0]; |
| 217 | + $numbers = $unknowns = array(); |
| 218 | + $years = $months = $days = array(); |
| 219 | + $eras = $seasons = $circas = $yearTerms = $monthTerms = $dayTerms = array(); |
| 220 | + $counter = 0; |
| 221 | + |
| 222 | + foreach( $chunks as $chunk ) { |
| 223 | + # Match month names. |
| 224 | + $month = $this->matchMonths( $chunk ); # $month is integer >= 1 or False |
| 225 | + if ( $month && count( $months ) < 2 ) { |
| 226 | + $months[ $counter ] = $month; |
| 227 | + $numbers[ $counter++ ] = new WCDateNumber( $counter, $month, WCDateNumber::month ); |
| 228 | + continue; |
| 229 | + } |
| 230 | + |
| 231 | + # Match date terms. |
| 232 | + $dateTermEnum = WCDateTermsEnum::match( $chunk, WCDateTermsEnum::$magicWordArray, |
| 233 | + WCDateTermsEnum::$flipMagicWordKeys, 'WCDateTermsEnum' ); |
| 234 | + if ( $dateTermEnum ) { |
| 235 | + switch ( $dateTermEnum->key ) { |
| 236 | + case WCDateTermsEnum::AD: |
| 237 | + if ( count( $eras ) < 2 ) { |
| 238 | + $eras[ $counter++ ] = WCDateTermsEnum::AD; |
| 239 | + } |
| 240 | + continue 2; |
| 241 | + case WCDateTermsEnum::BC: |
| 242 | + if ( count( $eras ) < 2 ) { |
| 243 | + $eras[ $counter++ ] = WCDateTermsEnum::BC; |
| 244 | + } |
| 245 | + continue 2; |
| 246 | + case WCDateTermsEnum::spring: |
| 247 | + if ( count( $seasons ) < 2 ) { |
| 248 | + $seasons[ $counter++ ] = WCDateTermsEnum::spring; |
| 249 | + } |
| 250 | + continue 2; |
| 251 | + case WCDateTermsEnum::summer: |
| 252 | + if ( count( $seasons ) < 2 ) { |
| 253 | + $seasons[ $counter++ ] = WCDateTermsEnum::summer; |
| 254 | + } |
| 255 | + continue 2; |
| 256 | + case WCDateTermsEnum::autumn: |
| 257 | + if ( count( $seasons ) < 2 ) { |
| 258 | + $seasons[ $counter++ ] = WCDateTermsEnum::autumn; |
| 259 | + } |
| 260 | + continue 2; |
| 261 | + case WCDateTermsEnum::winter: |
| 262 | + if ( count( $seasons ) < 2 ) { |
| 263 | + $seasons[ $counter++ ] = WCDateTermsEnum::winter; |
| 264 | + } |
| 265 | + continue 2; |
| 266 | + case WCDateTermsEnum::year: |
| 267 | + if ( count( $yearTerms ) < 2 ) { |
| 268 | + $yearTerms[ $counter++ ] = WCDateTermsEnum::yearTerm; |
| 269 | + } |
| 270 | + continue 2; |
| 271 | + case WCDateTermsEnum::month: |
| 272 | + if ( count( $monthTerms ) < 2 ) { |
| 273 | + $monthTerms[ $counter++ ] = WCDateTermsEnum::monthTerm; |
| 274 | + } |
| 275 | + continue 2; |
| 276 | + case WCDateTermsEnum::day: |
| 277 | + if ( count( $dayTerms ) < 2 ) { |
| 278 | + $dayTerms[ $counter++ ] = WCDateTermsEnum::dayTerm; |
| 279 | + } |
| 280 | + continue 2; |
| 281 | + case WCDateTermsEnum::circa: |
| 282 | + if ( count( $circas ) < 2 ) { |
| 283 | + $circas[ $counter++ ] = WCDateTermsEnum::circa; |
| 284 | + } |
| 285 | + continue 2; |
| 286 | + } |
| 287 | + } |
| 288 | + |
| 289 | + # Check for roman numerals (month is often Roman in Hungary, Poland, Romania). |
| 290 | + $intTerm = $this->romanToInt( $chunk ); |
| 291 | + # Convert to integer. |
| 292 | + if ( ! $intTerm ) { |
| 293 | + $intTerm = (integer) $chunk; # Note, this converts ordinals too. |
| 294 | + if ( ! $intTerm ) { |
| 295 | + # '00' cannot be month or day, so it must be the two-digit year 2000: |
| 296 | + if ( mb_substr( $chunk, 0, 2 ) == '00' ) { |
| 297 | + $numbers[ $counter ] = new WCDateNumber( $counter, 2000, WCDateNumber::year ); |
| 298 | + $years[ $counter ] = 2000; |
| 299 | + ++$counter; |
| 300 | + continue; |
| 301 | + } else { |
| 302 | + continue; # not a recognized number |
| 303 | + } |
| 304 | + } |
| 305 | + } |
| 306 | + $numbers[ $counter ] = $unknowns[ $counter ] = new WCDateNumber( $counter, $intTerm ); |
| 307 | + ++$counter; |
| 308 | + } |
| 309 | + |
| 310 | + # Look for and handle named Year/Month/Day labels |
| 311 | + foreach( $yearTerms as $yearTermKey => $yearTerm ) { |
| 312 | + if ( empty( $unknowns ) ) break; |
| 313 | + $unknown = $this->searchAdjacentTerm( $unknowns, $yearTermKey, $chunks ); |
| 314 | + if ( $unknown && count( $years ) < 2 ) { |
| 315 | + $years[ $unknown->key ] = $unknown->num; |
| 316 | + $unknown->setYear( $unknowns, $years ); |
| 317 | + } |
| 318 | + } |
| 319 | + foreach( $monthTerms as $monthTermKey => $monthTerm ) { |
| 320 | + if ( empty( $unknowns ) ) break; |
| 321 | + $unknown = $this->searchAdjacentTerm( $unknowns, $monthTermKey, $chunks ); |
| 322 | + if ( $unknown && count( $months ) < 2 ) { |
| 323 | + $months[ $unknown->key ] = $unknown->num; |
| 324 | + $unknown->setMonth( $unknowns, $months ); |
| 325 | + } |
| 326 | + } |
| 327 | + foreach( $dayTerms as $dayTermKey => $dayTerm ) { |
| 328 | + if ( empty( $unknowns ) ) break; |
| 329 | + $unknown = $this->searchAdjacentTerm( $unknowns, $dayTermKey, $chunks ); |
| 330 | + if ( $unknown && count( $days ) < 2 ) { |
| 331 | + $days[ $unknown->key ] = $unknown->num; |
| 332 | + $unknown->setDay( $unknowns, $days ); |
| 333 | + } |
| 334 | + } |
| 335 | + |
| 336 | + # If one or more seasons is specified, treat specially and return. |
| 337 | + if ( ! empty( $seasons ) ) { |
| 338 | + $this->season = reset( $seasons ); |
| 339 | + $season2 = next( $seasons ); |
| 340 | + # Only one season specified |
| 341 | + if ( $season2 === False || $season2 == $this->season ) { |
| 342 | + $isRange = False; |
| 343 | + # Determine year. |
| 344 | + if ( count( $years ) >= 1 ) { |
| 345 | + $year = reset( $years ); # Use first number as year |
| 346 | + $this->assignYearsAndEras( $eras, False, $year->num ); |
| 347 | + } |
| 348 | + elseif ( count( $unknowns ) >= 1 ) { |
| 349 | + $year = reset( $unknowns ); # Use first number as year |
| 350 | + $this->assignYearsAndEras( $eras, False, $year->num ); |
| 351 | + } |
| 352 | + else { |
| 353 | + $curDate = getdate(); |
| 354 | + $this->year = $curDate['year']; |
| 355 | + $this->era = WCDateTermsEnum::AD; |
| 356 | + } |
| 357 | + } |
| 358 | + # Two seasons specified |
| 359 | + else { |
| 360 | + $isRange = True; |
| 361 | + $this->season2 = $season2; |
| 362 | + # Determine year |
| 363 | + if ( count( $years ) >= 2 ) { |
| 364 | + $year = reset( $years )->num; |
| 365 | + $year2 = next( $years )->num; |
| 366 | + if ( $year2 == $year ) { |
| 367 | + $this->assignYearsAndEras( $eras, False, $year ); |
| 368 | + } |
| 369 | + else { |
| 370 | + $this->assignYearsAndEras( $eras, True, $year, $year2 ); |
| 371 | + } |
| 372 | + } |
| 373 | + elseif ( count( $years ) == 1 ) { |
| 374 | + $yearA = reset( $years )->num; |
| 375 | + if ( empty( $unknowns ) ) { |
| 376 | + $this->assignYearsAndEras( $eras, False, $yearA ); |
| 377 | + } |
| 378 | + else { |
| 379 | + $yearB = reset( $unknowns )->num; |
| 380 | + if ( $yearA == $yearB ) { |
| 381 | + $this->assignYearsAndEras( $eras, False, $yearA ); |
| 382 | + } |
| 383 | + elseif ( $yearA < $yearB ) { |
| 384 | + $this->assignYearsAndEras( $eras, True, $yearA, $yearB ); |
| 385 | + } |
| 386 | + else { |
| 387 | + $this->assignYearsAndEras( $eras, True, $yearB, $yearA ); |
| 388 | + } |
| 389 | + } |
| 390 | + } |
| 391 | + elseif ( count( $unknowns ) >= 2 ) { |
| 392 | + # Use first two numbers as years. |
| 393 | + $year = reset( $unknowns )->num; |
| 394 | + $year2 = next( $unknowns )->num; |
| 395 | + if ( $year2 == $year ) { |
| 396 | + $this->assignYearsAndEras( $eras, False, $year ); |
| 397 | + } |
| 398 | + else { |
| 399 | + $this->assignYearsAndEras( $eras, True, $year, $year2 ); |
| 400 | + } |
| 401 | + } |
| 402 | + elseif ( count( $unknowns ) == 1 ) { |
| 403 | + $year = reset( $unknowns )->num; |
| 404 | + $this->assignYearsAndEras( $eras, False, $year ); |
| 405 | + } |
| 406 | + else { |
| 407 | + $curDate = getdate(); |
| 408 | + $this->year = $curDate['year']; |
| 409 | + $this->era = WCDateTermsEnum::AD; |
| 410 | + } |
| 411 | + } |
| 412 | + $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); |
| 413 | + return; |
| 414 | + } |
| 415 | + |
| 416 | + # Handle numbers and/or named months. |
| 417 | + switch ( count( $numbers ) ) { |
| 418 | + |
| 419 | + case 0: /****** CASE 0 ******/ |
| 420 | + |
| 421 | + $this->finalizeDate( $days, $months, $years, $eras ); |
| 422 | + $this->assignUncertainty( $circas, False, $numbers, $chunks ); |
| 423 | + break; |
| 424 | + |
| 425 | + case 1: /****** CASE 1 ******/ |
| 426 | + /** Must be year |
| 427 | + */ |
| 428 | + if ( ! empty( $unknowns ) ) { |
| 429 | + reset( $unknowns ) -> setYear( $unknowns, $years ); |
| 430 | + } |
| 431 | + $this->finalizeDate( $days, $months, $years, $eras ); |
| 432 | + $this->assignUncertainty( $circas, False, $numbers, $chunks ); |
| 433 | + break; |
| 434 | + |
| 435 | + case 2: /****** CASE 2 ******/ |
| 436 | + /** Can be any of the following: |
| 437 | + * month-year |
| 438 | + * year-year |
| 439 | + * year-month |
| 440 | + */ |
| 441 | + $order1 = array( WCDateNumber::month, WCDateNumber::year ); |
| 442 | + $order2 = array( WCDateNumber::year, WCDateNumber::year ); |
| 443 | + $order3 = array( WCDateNumber::year, WCDateNumber::month ); |
| 444 | + if ( ! ( |
| 445 | + $this->monthUpTo12( $unknowns, $days, $years ) || |
| 446 | + $this->cannotBeDay( $unknowns, $months, $years ) || |
| 447 | + $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || |
| 448 | + $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || |
| 449 | + $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || |
| 450 | + $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || |
| 451 | + $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) |
| 452 | + ) ) { |
| 453 | + foreach( $unknowns as $unknownKey => $unknown ) { |
| 454 | + if ( empty( $months ) ) { |
| 455 | + $months[ $unknownKey ] = $unknown->num; |
| 456 | + } |
| 457 | + elseif ( count( $years ) < 2 ) { |
| 458 | + $years[ $unknownKey ] = $unknown->num; |
| 459 | + } |
| 460 | + } |
| 461 | + } |
| 462 | + $isRange = $this->finalizeDate( $days, $months, $years, $eras ); |
| 463 | + $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); |
| 464 | + |
| 465 | + break; |
| 466 | + |
| 467 | + case 3: /****** CASE 3 ******/ |
| 468 | + /** Can be any of the following: |
| 469 | + * day-month-year |
| 470 | + * month-day-year |
| 471 | + * year-month-day |
| 472 | + * month-month-year |
| 473 | + * year-month-month |
| 474 | + */ |
| 475 | + $order1 = array( WCDateNumber::day, WCDateNumber::month, WCDateNumber::year ); |
| 476 | + $order2 = array( WCDateNumber::month, WCDateNumber::day, WCDateNumber::year ); |
| 477 | + $order3 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::day ); |
| 478 | + $order4 = array( WCDateNumber::month, WCDateNumber::month, WCDateNumber::year ); |
| 479 | + $order5 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::month ); |
| 480 | + if ( ! ( |
| 481 | + $this->dayUpTo31( $unknowns, $months, $years ) || |
| 482 | + $this->monthUpTo12( $unknowns, $days, $years ) || |
| 483 | + $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || |
| 484 | + $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || |
| 485 | + $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || |
| 486 | + $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || |
| 487 | + $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) || |
| 488 | + $this->tryOrder( $unknowns, $days, $months, $years, $order4 ) || |
| 489 | + $this->tryOrder( $unknowns, $days, $months, $years, $order5 ) |
| 490 | + ) ) { |
| 491 | + foreach( $unknowns as $unknownKey => $unknown ) { |
| 492 | + if ( empty( $day ) ) { |
| 493 | + $days[ $unknownKey ] = $unknown->num; |
| 494 | + } |
| 495 | + elseif ( empty( $months ) ) { |
| 496 | + $months[ $unknownKey ] = $unknown->num; |
| 497 | + } |
| 498 | + elseif ( empty( $years ) ) { |
| 499 | + $years[ $unknownKey ] = $unknown->num; |
| 500 | + } |
| 501 | + else { |
| 502 | + $months[ $unknownKey ] = $unknown->num; |
| 503 | + } |
| 504 | + } |
| 505 | + } |
| 506 | + $isRange = $this->finalizeDate( $days, $months, $years, $eras ); |
| 507 | + $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); |
| 508 | + |
| 509 | + break; |
| 510 | + |
| 511 | + case 4: /****** CASE 4 ******/ |
| 512 | + |
| 513 | + /** Can be any of the following: |
| 514 | + * day-day-month-year |
| 515 | + * month-day-day-year |
| 516 | + * year-month-day-day |
| 517 | + * month-year-month-year |
| 518 | + * year-month-year-month |
| 519 | + */ |
| 520 | + $order1 = array( WCDateNumber::day, WCDateNumber::day, WCDateNumber::month, WCDateNumber::year ); |
| 521 | + $order2 = array( WCDateNumber::month, WCDateNumber::day, WCDateNumber::day, WCDateNumber::year ); |
| 522 | + $order3 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::day, WCDateNumber::day ); |
| 523 | + $order4 = array( WCDateNumber::month, WCDateNumber::year, WCDateNumber::month, WCDateNumber::year ); |
| 524 | + $order5 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::year, WCDateNumber::month ); |
| 525 | + if ( ! ( |
| 526 | + $this->dayUpTo31( $unknowns, $months, $years ) || |
| 527 | + $this->monthUpTo12( $unknowns, $days, $years ) || |
| 528 | + $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || |
| 529 | + $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || |
| 530 | + $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || |
| 531 | + $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || |
| 532 | + $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) || |
| 533 | + $this->tryOrder( $unknowns, $days, $months, $years, $order4 ) || |
| 534 | + $this->tryOrder( $unknowns, $days, $months, $years, $order5 ) |
| 535 | + ) ) { |
| 536 | + foreach( $unknowns as $unknownKey => $unknown ) { |
| 537 | + if ( count( $day ) < 2 ) { |
| 538 | + $days[ $unknownKey ] = $unknown->num; |
| 539 | + } |
| 540 | + elseif ( empty( $months ) ) { |
| 541 | + $months[ $unknownKey ] = $unknown->num; |
| 542 | + } |
| 543 | + elseif ( empty( $years ) ) { |
| 544 | + $years[ $unknownKey ] = $unknown->num; |
| 545 | + } |
| 546 | + elseif ( count( $months ) < 2 ) { |
| 547 | + $months[ $unknownKey ] = $unknown->num; |
| 548 | + } |
| 549 | + else { |
| 550 | + $years[ $unknownKey ] = $unknown->num; |
| 551 | + } |
| 552 | + } |
| 553 | + } |
| 554 | + $isRange = $this->finalizeDate( $days, $months, $years, $eras ); |
| 555 | + $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); |
| 556 | + |
| 557 | + break; |
| 558 | + |
| 559 | + case 5: /****** CASE 5 ******/ |
| 560 | + |
| 561 | + /** Can be any of the following: |
| 562 | + * day-month-day-month-year |
| 563 | + * month-day-month-day-year |
| 564 | + * year-month-day-month-day |
| 565 | + */ |
| 566 | + $order1 = array( WCDateNumber::day, WCDateNumber::month, WCDateNumber::day, WCDateNumber::month, WCDateNumber::year ); |
| 567 | + $order2 = array( WCDateNumber::month, WCDateNumber::day, WCDateNumber::month, WCDateNumber::day, WCDateNumber::year ); |
| 568 | + $order3 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::day, WCDateNumber::month, WCDateNumber::day ); |
| 569 | + if ( ! ( |
| 570 | + $this->dayUpTo31( $unknowns, $months, $years ) || |
| 571 | + $this->monthUpTo12( $unknowns, $days, $years ) || |
| 572 | + $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || |
| 573 | + $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || |
| 574 | + $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || |
| 575 | + $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || |
| 576 | + $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) |
| 577 | + ) ) { |
| 578 | + foreach( $unknowns as $unknownKey => $unknown ) { |
| 579 | + if ( count( $day ) < 2 ) { |
| 580 | + $days[ $unknownKey ] = $unknown->num; |
| 581 | + } |
| 582 | + elseif ( count( $months ) < 2 ) { |
| 583 | + $months[ $unknownKey ] = $unknown->num; |
| 584 | + } |
| 585 | + else { |
| 586 | + $years[ $unknownKey ] = $unknown->num; |
| 587 | + } |
| 588 | + } |
| 589 | + } |
| 590 | + $isRange = $this->finalizeDate( $days, $months, $years, $eras ); |
| 591 | + $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); |
| 592 | + |
| 593 | + break; |
| 594 | + |
| 595 | + default: /****** CASE 6+ ******/ |
| 596 | + |
| 597 | + /** Can be one of the following: |
| 598 | + * day-month-year-day-month-year |
| 599 | + * month-day-year-month-day-year |
| 600 | + * year-month-day-year-month-day |
| 601 | + */ |
| 602 | + $order1 = array( WCDateNumber::day, WCDateNumber::month, WCDateNumber::year, WCDateNumber::day, WCDateNumber::month, WCDateNumber::year ); |
| 603 | + $order2 = array( WCDateNumber::month, WCDateNumber::day, WCDateNumber::year, WCDateNumber::month, WCDateNumber::day, WCDateNumber::year ); |
| 604 | + $order3 = array( WCDateNumber::year, WCDateNumber::month, WCDateNumber::day, WCDateNumber::year, WCDateNumber::month, WCDateNumber::day ); |
| 605 | + if ( ! ( |
| 606 | + $this->dayUpTo31( $unknowns, $months, $years ) || |
| 607 | + $this->monthUpTo12( $unknowns, $days, $years ) || |
| 608 | + $this->yearAdjacentEra( $unknowns, $years, $eras, $chunks ) || |
| 609 | + $this->yearsInOrder( $unknowns, $days, $months, $years, $eras ) || |
| 610 | + $this->tryOrder( $unknowns, $days, $months, $years, $order1 ) || |
| 611 | + $this->tryOrder( $unknowns, $days, $months, $years, $order2 ) || |
| 612 | + $this->tryOrder( $unknowns, $days, $months, $years, $order3 ) |
| 613 | + ) ) { |
| 614 | + foreach( $unknowns as $unknownKey => $unknown ) { |
| 615 | + if ( count( $day ) < 2 ) { |
| 616 | + $days[ $unknownKey ] = $unknown->num; |
| 617 | + } |
| 618 | + elseif ( count( $months ) < 2 ) { |
| 619 | + $months[ $unknownKey ] = $unknown->num; |
| 620 | + } |
| 621 | + else { |
| 622 | + $years[ $unknownKey ] = $unknown->num; |
| 623 | + } |
| 624 | + } |
| 625 | + } |
| 626 | + $isRange = $this->finalizeDate( $days, $months, $years, $eras ); |
| 627 | + $this->assignUncertainty( $circas, $isRange, $numbers, $chunks ); |
| 628 | + } |
| 629 | + |
| 630 | + } |
| 631 | + |
| 632 | + |
| 633 | + /** |
| 634 | + * Determine if $this can be considered a short form of argument $date. |
| 635 | + * If so, then determine the number of matches. |
| 636 | + * |
| 637 | + * @param WCDate $date |
| 638 | + * @return integer|boolean |
| 639 | + */ |
| 640 | + public function shortFormMatches( WCData $date ) { |
| 641 | + $matches = 0; |
| 642 | + if ( isset( $this->year ) ) { |
| 643 | + if ( $this->year === $date->year ) ++$matches; |
| 644 | + else return False; |
| 645 | + } |
| 646 | + if ( isset( $this->month ) ) { |
| 647 | + if ( $this->month === $date->month ) ++$matches; |
| 648 | + else return False; |
| 649 | + } |
| 650 | + if ( isset( $this->day ) ) { |
| 651 | + if ( $this->day === $date->day ) ++$matches; |
| 652 | + else return False; |
| 653 | + } |
| 654 | + if ( isset( $this->season ) ) { |
| 655 | + if ( $this->season === $date->season ) ++$matches; |
| 656 | + else return False; |
| 657 | + } |
| 658 | + if ( isset( $this->era ) ) { |
| 659 | + if ( $this->era === $date->era ) ++$matches; |
| 660 | + else return False; |
| 661 | + } |
| 662 | + return $matches; |
| 663 | + } |
| 664 | + |
| 665 | + |
| 666 | + public function __toString() { |
| 667 | + $text = $this->year; |
| 668 | + if ( $this->year2 ) $text .= '–' . $year2; |
| 669 | + if ( $this->season ) $text .= ' ' . $season; |
| 670 | + if ( $this->season2 ) $text .= '–' . $season2; |
| 671 | + if ( $this->month ) $text .= ' ' . $month; |
| 672 | + if ( $this->month2 ) $text .= '–' . $month2; |
| 673 | + if ( $this->day ) $text .= ' ' . $day; |
| 674 | + if ( $this->day2 ) $text .= '–' . $day2; |
| 675 | + return $text; |
| 676 | + } |
| 677 | + |
| 678 | + |
| 679 | + /** |
| 680 | + * Match localized month names and abbreviations. |
| 681 | + * |
| 682 | + * @global Language $wgContLang the content Language object |
| 683 | + * @param string $chunk the term being tested |
| 684 | + * @return int the numerical month ( or 0 if no match) |
| 685 | + */ |
| 686 | + protected function matchMonths( $date ) { |
| 687 | + global $wgContLang; |
| 688 | + for ( $i=1; $i < 13; $i++ ) { |
| 689 | + if ( $date == $wgContLang->getMonthName( $i ) |
| 690 | + || $date == $wgContLang->getMonthAbbreviation( $i ) |
| 691 | + || $date == $wgContLang->getMonthNameGen( $i ) ) { |
| 692 | + return $i; |
| 693 | + } |
| 694 | + } |
| 695 | + return 0; |
| 696 | + } |
| 697 | + |
| 698 | + |
| 699 | + /** |
| 700 | + * Convert a string Roman number to integer. |
| 701 | + * If the string does not represent a Roman number, this function returns 0. |
| 702 | + * @staticvar array $letters |
| 703 | + * @param type $romanNumber = string containing the (possibly) Roman number |
| 704 | + * @return int = the integer corresponding to the Roman number (or zero) |
| 705 | + */ |
| 706 | + protected function romanToInt( $romanNumber ) { |
| 707 | + static $letters = array( |
| 708 | + 'M' => 1000, 'CM' => 900, 'D' => 500, 'CD' => 400, 'C' => 100, |
| 709 | + 'XC' => 90, 'L' => 50, 'XL' => 40, 'X' => 10, 'IX' => 9, |
| 710 | + 'V' => 5, 'IV' => 4, 'I' => 1, |
| 711 | + ); |
| 712 | + $number = 0; |
| 713 | + foreach ( $letters as $key => $value ) { |
| 714 | + while ( mb_strpos( $romanNumber, $key ) === 0) { |
| 715 | + $result += $value; |
| 716 | + $romanNumber = mb_substr( $romanNumber, mb_strlen( $key ) ); |
| 717 | + } |
| 718 | + } |
| 719 | + return $number; |
| 720 | + } |
| 721 | + |
| 722 | + |
| 723 | + /** |
| 724 | + * If it is a two-digit year, convert to a four-digit year. |
| 725 | + * Cutoff between this and last century is 5 years in the future, |
| 726 | + * to allow for anticipatory citations of to-be-published material. |
| 727 | + * Thus, if in the year 2011 you cited a "01/01/16" publication, the year |
| 728 | + * would be interpreted as 2016, but "01/01/17" would be interpreted as |
| 729 | + * 1917. |
| 730 | + * @param int $year = a two-digit year (this is validated by the function) |
| 731 | + * @return int = the corresponding four-digit year |
| 732 | + */ |
| 733 | + protected function adjust2DigitYear( $year ) { |
| 734 | + if ( $year >= 100 ) return $year; |
| 735 | + $curDate = getdate(); |
| 736 | + $curYear = $curDate['year']; |
| 737 | + # Two digit year plus the current century: |
| 738 | + $year = $curYear - $curYear % 100 + $year; |
| 739 | + $cutoffYear = $curYear + 5; |
| 740 | + if ( $year > $curYear + 10 ) { |
| 741 | + return $year - 100; |
| 742 | + } |
| 743 | + else { |
| 744 | + return $year; |
| 745 | + } |
| 746 | + } |
| 747 | + |
| 748 | + |
| 749 | + /** |
| 750 | + * Assign up to two years and two eras (AD or BC, etc.) |
| 751 | + * If the era(s) are not defined, this function assumes AD and converts |
| 752 | + * any two-digit years to full years in the current century. Thus, years |
| 753 | + * prior to 100 AD require an explicit era designation. |
| 754 | + * @param array $eras = array of values comprising either 1=AD or -1=BC |
| 755 | + * @param int $isRange = whether or not the date is a range |
| 756 | + * @param int $year = the year, or first year |
| 757 | + * @param int $year2 = the second year |
| 758 | + */ |
| 759 | + protected function assignYearsAndEras( array $eras, $isRange, $year, $year2 = Null ) { |
| 760 | + if ( $isRange ) { |
| 761 | + if ( count( $eras ) >= 2 ) { |
| 762 | + $this->year = $year; |
| 763 | + $this->year2 = $year2; |
| 764 | + $this->era = reset( $eras ); # Use first two eras. |
| 765 | + $this->era2 = next( $eras ); |
| 766 | + } elseif ( count ( $eras ) == 1 ) { |
| 767 | + $this->year = $year; |
| 768 | + $this->year2 = $year2; |
| 769 | + $this->era = $this->era2 = reset( $eras ); |
| 770 | + } else { |
| 771 | + $this->year = $this->adjust2DigitYear( $year ); # Assume small years are 2-digit years. |
| 772 | + $this->year2 = $this->adjust2DigitYear( $year2 ); |
| 773 | + $this->era = $this->era2 = WCDateTermsEnum::AD; # Assume AD. |
| 774 | + } |
| 775 | + } else { |
| 776 | + if ( count( $eras ) >= 1 ) { |
| 777 | + $this->year = $year; |
| 778 | + $this->era = reset( $eras ); # Use first era |
| 779 | + } else { |
| 780 | + $this->year = $this->adjust2DigitYear( $year ); # Assume small years are 2-digit years. |
| 781 | + $this->era = WCDateTermsEnum::AD; # Assume AD. |
| 782 | + } |
| 783 | + } |
| 784 | + } |
| 785 | + |
| 786 | + |
| 787 | + /** |
| 788 | + * Assign uncertainty to one or both of the dates. |
| 789 | + * Uncertainty is indicated by "circa" or "c." or equivalent localized |
| 790 | + * terms. If there is only one indication of uncertainty, this function |
| 791 | + * determines whether the "circa" etc. is closer to $num1 or $num2. |
| 792 | + * @param array $circas= a list of "circa" indicators |
| 793 | + * @param type $isRange |
| 794 | + * @param array $numbers = the list of all numbers that might be uncertain |
| 795 | + * @param array $chunks = a list of date terms. |
| 796 | + */ |
| 797 | + protected function assignUncertainty( array $circas, $isRange, array $numbers, array $chunks ) { |
| 798 | + if ( $isRange ) { |
| 799 | + if ( empty( $circas ) ) { |
| 800 | + $this->isUncertain = $this->isUncertain2 = False; |
| 801 | + } |
| 802 | + # If there are two indications of uncertainty, both dates are uncertain. |
| 803 | + elseif ( count( $circas ) >= 2 ) { |
| 804 | + $this->isUncertain = $this->isUncertain2 = True; |
| 805 | + } |
| 806 | + # For just one indication of uncertainty in a range, the uncertain date is the one |
| 807 | + # where the number ($num1 or $num2) is most adjacent to the indicator |
| 808 | + # of uncertainty. |
| 809 | + else { |
| 810 | + $circaKey = key( reset( $circas ) ); |
| 811 | + $uncertainNumber = $this->searchAdjacentTerm( $numbers, $circaKey, $chunks ); |
| 812 | + if ( $uncertainNumber ) { |
| 813 | + $uncertainKey = $uncertainNumber->key; |
| 814 | + $uncertainType = $uncertainNumber->numType; |
| 815 | + foreach( $numbers as $number ) { |
| 816 | + if ( $number->numType == $uncertainType ) { |
| 817 | + if ( $number->key == $uncertainKey ) { |
| 818 | + # Key matches the first number of that type |
| 819 | + $this->isUncertain = True; |
| 820 | + $this->isUncertain2 = False; |
| 821 | + } |
| 822 | + else { |
| 823 | + # Key does not match the first number, so probably matches the second |
| 824 | + $this->isUncertain = False; |
| 825 | + $this->isUncertain2 = True; |
| 826 | + } |
| 827 | + return; |
| 828 | + } |
| 829 | + } |
| 830 | + } |
| 831 | + else { |
| 832 | + # None of the terms is adjacent. |
| 833 | + $this->isUncertain = False; |
| 834 | + return; |
| 835 | + } |
| 836 | + } |
| 837 | + } |
| 838 | + else { |
| 839 | + $this->isUncertain = ! empty( $circas ); |
| 840 | + } |
| 841 | + } |
| 842 | + |
| 843 | + |
| 844 | + public function finalizeDate( array $days, array $months, array $years, array $eras ) { |
| 845 | + $isRange = False; |
| 846 | + $year1 = reset( $years ); |
| 847 | + if ( $year1 === False ) { |
| 848 | + # No year specified |
| 849 | + $curDate = getdate(); |
| 850 | + $this->year = $curDate['year']; |
| 851 | + $this->era = WCDateTermsEnum::AD; |
| 852 | + } |
| 853 | + else { |
| 854 | + # At least one year specified |
| 855 | + $yearKey1 = key( $years ); |
| 856 | + $year2 = next( $years ); |
| 857 | + if ( $year2 === False || $year2 == $year1 ) { |
| 858 | + # Only one year specified |
| 859 | + $this->assignYearsAndEras( $eras, False, $year1 ); |
| 860 | + } |
| 861 | + else { |
| 862 | + # Two years specified |
| 863 | + $yearKey2 = key( $years ); |
| 864 | + $isRange = True; |
| 865 | + $this->assignYearsAndEras( $eras, True, $year1, $year2 ); |
| 866 | + } |
| 867 | + } |
| 868 | + |
| 869 | + $month1 = reset( $months ); |
| 870 | + if ( $month1 === False ) { |
| 871 | + # No month specified |
| 872 | + return $isRange; |
| 873 | + } |
| 874 | + else { |
| 875 | + # Month is specified |
| 876 | + $this->month = $month1; |
| 877 | + $month2 = next( $months ); |
| 878 | + if ( ! ( $month2 === False ) && $month1 != $month2 ) { |
| 879 | + # Two months specified |
| 880 | + $this->month2 = $month2; |
| 881 | + $isRange = True; |
| 882 | + } |
| 883 | + } |
| 884 | + |
| 885 | + $day1 = reset( $days ); |
| 886 | + if ( $day1 === False ) { |
| 887 | + # No day specified |
| 888 | + return $isRange; |
| 889 | + } |
| 890 | + else { |
| 891 | + # Day is specified |
| 892 | + $this->day = $day1; |
| 893 | + $day2 = next( $days ); |
| 894 | + if ( $day2 === False || $day2 == $day1 ) { |
| 895 | + # Only one day specified |
| 896 | + return $isRange; |
| 897 | + } |
| 898 | + else { |
| 899 | + # Two days specified |
| 900 | + $this->day2 = $day2; |
| 901 | + return True; |
| 902 | + } |
| 903 | + } |
| 904 | + |
| 905 | + } |
| 906 | + |
| 907 | + |
| 908 | + /** |
| 909 | + * Determine whether the term at key $termKey is adjacent to a number. |
| 910 | + * @param array $numbers = an array of WCDateTerm objects |
| 911 | + * @param int $termKey = the key of the term in question |
| 912 | + * @param array $chunks = chunks of user input |
| 913 | + * @return WCDateTerm = WCDateTerm if adjacent, Null if not |
| 914 | + */ |
| 915 | + public function searchAdjacentTerm( array $numbers, $termKey, array $chunks ) { |
| 916 | + $s1 = is_set( $numbers[ $termKey - 1 ] ); |
| 917 | + $s2 = is_set( $numbers[ $termKey + 1 ] ); |
| 918 | + if ( !$s1 && !$s2 ) { |
| 919 | + return Null; |
| 920 | + } |
| 921 | + elseif ( !$s1 && $s2 ) { |
| 922 | + $numberKey = $termKey + 1; |
| 923 | + $number = $numbers[ $numberKey ]; |
| 924 | + $years[ $numberKey ] = $number->num; |
| 925 | + return $number; |
| 926 | + } |
| 927 | + elseif ( $s1 && !$s2 ) { |
| 928 | + $numberKey = $termKey - 1; |
| 929 | + $number = $numbers[ $numberKey ]; |
| 930 | + $years[ $numberKey ] = $number->num; |
| 931 | + return $number; |
| 932 | + } |
| 933 | + else { |
| 934 | + $number1 = $numbers[ $termKey - 1 ]; |
| 935 | + $number2 = $numbers[ $termKey + 1 ]; |
| 936 | + $closestNum = $this->closestNumberToTerm( $termKey, $number1, $number2, $chunks ); |
| 937 | + if ( $closestNum->key < $termKey ) { |
| 938 | + return $number1; |
| 939 | + } |
| 940 | + else { |
| 941 | + return $number2; |
| 942 | + } |
| 943 | + } |
| 944 | + } |
| 945 | + |
| 946 | + |
| 947 | + public function closestNumberToTerm( $key, WCDateNumber $num1, WCDateNumber $num2, array $chunks ) { |
| 948 | + $key1 = $num1->key; |
| 949 | + $key2 = $num2->key; |
| 950 | + $dist1 = $key - $key1; |
| 951 | + $dist2 = $key2 - $key; |
| 952 | + $mid1 = implode( '', array_slice( $chunks, $key1 + 1, $dist1 - 1 ) ); |
| 953 | + $mid2 = implode( '', array_slice( $chunks, $key + 1, $dist2 - 1 ) ); |
| 954 | + $sp1 = preg_match('/^\p{Zs}*$/uS', $mid1 ); |
| 955 | + $sp2 = preg_match('/^\p{Zs}*$/uS', $mid2 ); |
| 956 | + # Is one number (and not the other) separated from the term by merely space? |
| 957 | + if ( !$sp1 && $sp2 ) { |
| 958 | + return $num2; |
| 959 | + } |
| 960 | + elseif ( $sp1 && !$sp2 ) { |
| 961 | + return $num1; |
| 962 | + } |
| 963 | + # Pick the number, if any, that has fewer intermediate terms. |
| 964 | + elseif ( abs( $dist1 ) < abs( $dist2 ) ) { |
| 965 | + return $num1; |
| 966 | + } |
| 967 | + elseif ( abs( $dist2 ) < abs( $dist1 ) ) { |
| 968 | + return $num2; |
| 969 | + } |
| 970 | + # Pick the number, if any, that has the shortest string between itself and the term: |
| 971 | + elseif ( mb_strlen( $mid1 ) < mb_strlen( $mid2 ) ) { |
| 972 | + return $num1; |
| 973 | + } |
| 974 | + elseif ( mb_strlen( $mid2 ) < mb_strlen( $mid1 ) ) { |
| 975 | + return $num2; |
| 976 | + } |
| 977 | + # Anything that makes it this far would look something like "…AAA 12 BBB…" or "…AAA-12-BBB…". |
| 978 | + return Null; |
| 979 | + } |
| 980 | + |
| 981 | + |
| 982 | + public function dayUpTo31( array &$unknowns, array &$months, array &$years ) { |
| 983 | + foreach( $unknowns as $unknown ) { |
| 984 | + if ( $unknown->num > 31 ) { |
| 985 | + $unknown->setNotDay( $unknowns, $months, $years ); |
| 986 | + } |
| 987 | + } |
| 988 | + return empty( $unknowns ); |
| 989 | + } |
| 990 | + |
| 991 | + |
| 992 | + public function monthUpTo12( array &$unknowns, array &$days, array &$years ) { |
| 993 | + foreach( $unknowns as $unknown ) { |
| 994 | + if ( $unknown->num > 12 ) { |
| 995 | + $unknown->setNotMonth( $unknowns, $days, $years ); |
| 996 | + } |
| 997 | + } |
| 998 | + return empty( $unknowns ); |
| 999 | + } |
| 1000 | + |
| 1001 | + |
| 1002 | + public function yearAdjacentEra( array &$unknowns, array &$years, array $eras, array $chunks ) { |
| 1003 | + if ( empty( $eras ) || empty( $unknowns ) ) { |
| 1004 | + return False; |
| 1005 | + } |
| 1006 | + foreach ( $eras as $eraKey => $era ) { |
| 1007 | + $unknown = $this->searchAdjacentTerm( $unknowns, $eraKey, $chunks ); |
| 1008 | + if ( $unknown ) { |
| 1009 | + $unknown->setYear( $unknowns, $years ); |
| 1010 | + } |
| 1011 | + } |
| 1012 | + return empty( $unknowns ); |
| 1013 | + } |
| 1014 | + |
| 1015 | + |
| 1016 | + public function cannotBeDay( array &$unknowns, &$months, &$years ) { |
| 1017 | + foreach( $unknowns as $unknown ) { |
| 1018 | + $unknown->setNotDay( $unknowns, $months, $years ); |
| 1019 | + } |
| 1020 | + return empty( $unknowns ); |
| 1021 | + } |
| 1022 | + |
| 1023 | + |
| 1024 | + /** |
| 1025 | + * Determines whether number can be a year, based on relative year order. |
| 1026 | + * This is only useful when one year has been defined, but not the other |
| 1027 | + * year. It assumes that the user will enter a year range in the proper |
| 1028 | + * numerical order. For example, "09-10" and "7 BC - 4 BC" are proper |
| 1029 | + * ranges, but if the year 7 BC has already been defined, the next year |
| 1030 | + * in the range cannot be 10 BC. |
| 1031 | + * @param array $unknowns |
| 1032 | + * @param array $days |
| 1033 | + * @param array $months |
| 1034 | + * @param array $years |
| 1035 | + * @param array $eras |
| 1036 | + * @return boolean = True if all the $unknowns have been exhausted |
| 1037 | + */ |
| 1038 | + public function yearsInOrder( array &$unknowns, array &$days, array &$months, array &$years, array $eras ) { |
| 1039 | + if ( count( $years ) == 1 ) { |
| 1040 | + $year = reset( $years ); |
| 1041 | + $yearKey = key( $years ); |
| 1042 | + # Date range spans the BC-AD era boundary: |
| 1043 | + if ( empty( $eras ) ) { |
| 1044 | + foreach( $unknowns as $unknownKey => $unknown ) { |
| 1045 | + if ( $unknownKey < $yearKey && $unknown->num > $year |
| 1046 | + || $yearKey < $unknownKey && $year > $unknown->num ) { |
| 1047 | + $unknown->setNotYear( $unknowns, $days, $months ); |
| 1048 | + } |
| 1049 | + } |
| 1050 | + } |
| 1051 | + else { |
| 1052 | + $era1 = reset( $eras ); |
| 1053 | + $era2 = next( $eras ); |
| 1054 | + if ( $era2 === False || $era1 === $era2 ) { |
| 1055 | + if ( $era1 === WCDateTermsEnum::AD ) { |
| 1056 | + foreach( $unknowns as $unknownKey => $unknown ) { |
| 1057 | + if ( $unknownKey < $yearKey && $unknown->num > $year |
| 1058 | + || $yearKey < $unknownKey && $year > $unknown->num ) { |
| 1059 | + $unknown->setNotYear( $unknowns, $days, $months ); |
| 1060 | + } |
| 1061 | + } |
| 1062 | + } |
| 1063 | + else { |
| 1064 | + foreach( $unknowns as $unknownKey => $unknown ) { |
| 1065 | + if ( $unknownKey < $yearKey && $unknown->num < $year |
| 1066 | + || $yearKey < $unknownKey && $year < $unknown->num ) { |
| 1067 | + $unknown->setNotYear( $unknowns, $days, $months ); |
| 1068 | + } |
| 1069 | + } |
| 1070 | + } |
| 1071 | + } |
| 1072 | + else { |
| 1073 | + return False; |
| 1074 | + } |
| 1075 | + } |
| 1076 | + return empty( $unknowns ); |
| 1077 | + } |
| 1078 | + else { |
| 1079 | + return False; |
| 1080 | + } |
| 1081 | + } |
| 1082 | + |
| 1083 | + |
| 1084 | + public function tryOrder( array &$unknowns, array &$days, array &$months, array &$years, array $order ) { |
| 1085 | + reset( $order ); |
| 1086 | + foreach( $unknowns as $unknown ) { |
| 1087 | + switch ( current( $order ) ) { |
| 1088 | + case WCDateNumber::year: |
| 1089 | + if ( $unknown->couldBeYear() ) break; |
| 1090 | + else return False; |
| 1091 | + case WCDateNumber::month: |
| 1092 | + if ( $unknown->couldBeMonth() ) break; |
| 1093 | + else return False; |
| 1094 | + case WCDateNumber::day: |
| 1095 | + if ( $unknown->couldBeDay() ) break; |
| 1096 | + else return False; |
| 1097 | + } |
| 1098 | + next( $order ); |
| 1099 | + } |
| 1100 | + reset( $order ); |
| 1101 | + foreach( $unknowns as $unknown ) { |
| 1102 | + switch ( current( $order ) ) { |
| 1103 | + case WCDateNumber::year: |
| 1104 | + $unknown->setYear( $unknowns, $years ); |
| 1105 | + break; |
| 1106 | + case WCDateNumber::month: |
| 1107 | + $unknown->setMonth( $unknowns, $months ); |
| 1108 | + break; |
| 1109 | + case WCDateNumber::day: |
| 1110 | + $unknown->setDay( $unknowns, $days ); |
| 1111 | + break; |
| 1112 | + } |
| 1113 | + next( $order ); |
| 1114 | + } |
| 1115 | + return empty( $unknowns ); |
| 1116 | + } |
| 1117 | + |
| 1118 | + |
| 1119 | +} |
| 1120 | + |
Property changes on: trunk/extensions/WikiCitation/includes/data/WCDate.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 1121 | + native |
Property changes on: trunk/extensions/WikiCitation/includes/data |
___________________________________________________________________ |
Added: bugtraq:number |
2 | 1122 | + true |
Index: trunk/extensions/WikiCitation/includes/WCCitation.php |
— | — | @@ -0,0 +1,326 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCCitationPosition extends WCEnum { |
| 12 | + const first = 0; |
| 13 | + const subsequent = 1; |
| 14 | +# const ibid = 2; |
| 15 | +# const ibidWithLocator = 3; |
| 16 | +# const nearNote = 4; |
| 17 | + const __default = self::first; |
| 18 | +} |
| 19 | + |
| 20 | +/** |
| 21 | + * Class representing the finalized citation. |
| 22 | + * |
| 23 | + * This class reads and processes the data from a WCArgumentReader object, |
| 24 | + * and constructs the appropriate WCStyle child based on the referencing style |
| 25 | + * and citation type. Ultimately, a call to WCCitation::composeCitation() |
| 26 | + * will output the fully-formatted citation. |
| 27 | + */ |
| 28 | +class WCCitation { |
| 29 | + |
| 30 | + /** |
| 31 | + * Associated WCReference object, representing the unique reference source. |
| 32 | + * For each WCReference instance, there may be many WCCitation instances. |
| 33 | + * @var WCReference |
| 34 | + */ |
| 35 | + public $reference; |
| 36 | + |
| 37 | + |
| 38 | + /** |
| 39 | + * Position of the citation |
| 40 | + * (E.g., first, subsequent, etc.) |
| 41 | + * @var WCCitationPosition |
| 42 | + */ |
| 43 | + public $citationPostion; |
| 44 | + |
| 45 | + |
| 46 | + /** |
| 47 | + * The citation system: notes and bibliography or author-date. |
| 48 | + * @var WCCitationSystem |
| 49 | + */ |
| 50 | + public $citationSystem; |
| 51 | + |
| 52 | + /** |
| 53 | + * Marker for this citation, left behind temporarily in text, and later replaced. |
| 54 | + * @var unknown_type |
| 55 | + */ |
| 56 | + public $marker; |
| 57 | + |
| 58 | + /** |
| 59 | + * The citation style. |
| 60 | + * @var WCStyle |
| 61 | + */ |
| 62 | + public $style; |
| 63 | + |
| 64 | + |
| 65 | + /** |
| 66 | + * The citation type. |
| 67 | + * @var WCCitationType |
| 68 | + */ |
| 69 | + public $citationType; |
| 70 | + |
| 71 | + /** |
| 72 | + * The citation length. |
| 73 | + * @var WCCitationLength |
| 74 | + */ |
| 75 | + public $citationLength; |
| 76 | + |
| 77 | + /** |
| 78 | + * Distance in number of citations from last citation to this reference |
| 79 | + * @var integer |
| 80 | + */ |
| 81 | + public $distance; |
| 82 | + |
| 83 | + /** |
| 84 | + * Locators for this citation. |
| 85 | + * @var array of WCLocator objects |
| 86 | + */ |
| 87 | + protected $locators = array(); |
| 88 | + |
| 89 | + |
| 90 | + # output of the parser |
| 91 | + protected $citationText; |
| 92 | + |
| 93 | + |
| 94 | + /** |
| 95 | + * Constructor. |
| 96 | + */ |
| 97 | + public function __construct( WCReference $reference ) { |
| 98 | + |
| 99 | + $this->reference = $reference; |
| 100 | + $this->citationPosition = new WCCitationPosition(); |
| 101 | + |
| 102 | + # Construct a random marker for storage and later replacement by the citation: |
| 103 | + $this->marker = 'wC-' . mt_rand(); |
| 104 | + |
| 105 | + } |
| 106 | + |
| 107 | + |
| 108 | + /** |
| 109 | + * Read and parse arguments from a WCArgumentReader object. |
| 110 | + * @param WCArgumentReader $wcArgumentReader = the argument reader |
| 111 | + * @global $wikiCitationValidateArguments |
| 112 | + */ |
| 113 | + public function readArguments( WCArgumentReader $argumentReader ) { |
| 114 | + |
| 115 | + $this->citationType = $argumentReader->getCitationType(); |
| 116 | + $this->citationLength = $argumentReader->getCitationLength(); |
| 117 | + |
| 118 | + /** |
| 119 | + * Recognize and process the parameters and names. |
| 120 | + */ |
| 121 | + foreach( $argumentReader->parameters as $var => $value ) { |
| 122 | + |
| 123 | + # See if scope name only is present, in which case the parameter is assumed to be the title. |
| 124 | + # This allows the user to enter "journal=Nature" or "work=Origin of Species", etc. |
| 125 | + $scope = WCScopeEnum::match( $var, WCScopeEnum::$magicWordArray, |
| 126 | + WCScopeEnum::$flipMagicWordKeys, 'WCScopeEnum' ); |
| 127 | + if ( $scope ) { |
| 128 | + $property = WCPropertyEnum::$title; |
| 129 | + $this->reference->setProperty( $scope, $property, new WCTitle( $value ) ); |
| 130 | + continue; |
| 131 | + } |
| 132 | + |
| 133 | + # Match the parameter scope. |
| 134 | + list( $scope, $parameterText ) = WCScopeEnum::matchPrefix( $var, WCScopeEnum::$magicWordArray, |
| 135 | + WCScopeEnum::$flipMagicWordKeys, 'WCScopeEnum' ); |
| 136 | + if ( !$scope ) { |
| 137 | + $scope = WCScopeEnum::$work; # Set the default |
| 138 | + } |
| 139 | + |
| 140 | + # See if a type name is present, in which case the parameter is assumed to be the title. |
| 141 | + # This allows the wiki editor to enter "book=Origin of Species", "pamphlet=Common Sense," etc., or even "container-encyclopedia=Encyclopedia Brittanica." |
| 142 | + # If either the title or type have already been set, then neither will be set again. |
| 143 | + # Thus, it will be possible to use "book" as a locator. |
| 144 | + $type = WCSourceTypeEnum::match( $parameterText, WCSourceTypeEnum::$magicWordArray, |
| 145 | + WCSourceTypeEnum::$flipMagicWordKeys, 'WCTypeEnum' ); |
| 146 | + if ( $type ) { |
| 147 | + $propertyEnumTitle = WCPropertyEnum::$title; |
| 148 | + $propertyEnumType = WCPropertyEnum::$type; |
| 149 | + $title = $this->reference->getProperty( $scope, $propertyEnumTitle ); |
| 150 | + $type = $this->reference->getProperty( $scope, $propertyEnumType ); |
| 151 | + if ( is_null( $this->reference->getProperty( $scope, $propertyEnumTitle ) ) && is_null( $this->getProperty( $scope, $propertyEnumType ) ) ) { |
| 152 | + $this->reference->setProperty( $scope, $propertyEnumTitle, new WCTitle( $value ) ); |
| 153 | + $this->reference->setProperty( $scope, $propertyEnumType, new WCTypeData( $type ) ); |
| 154 | + } |
| 155 | + continue; |
| 156 | + } |
| 157 | + |
| 158 | + global $wikiCitationValidateArguments; |
| 159 | + |
| 160 | + # Match properties. |
| 161 | + $property = WCPropertyEnum::match( $parameterText, WCPropertyEnum::$magicWordArray, |
| 162 | + WCPropertyEnum::$flipMagicWordKeys, 'WCPropertyEnum' ); |
| 163 | + if ( $property ) { |
| 164 | + $attributeKey = $property->getAttribute()->key; |
| 165 | + $attributeClass = WCAttributeEnum::$attribute[ $attributeKey ]; |
| 166 | + if ( $attributeKey == WCAttributeEnum::locator ) { |
| 167 | + # Locators disregard the scope. |
| 168 | + $locator = $this->getLocator( $property ); |
| 169 | + if ( $wikiCitationValidateArguments && isset( $locator ) ) { |
| 170 | + throw new WCException( 'wc-parameter_defined_twice', $property ); |
| 171 | + } else { |
| 172 | + $this->setLocator( $property, new WCLocator( $value ) ); |
| 173 | + } |
| 174 | + } else { |
| 175 | + $prop = $this->reference->getProperty( $scope, $property ); |
| 176 | + if ( $wikiCitationValidateArguments && isset( $prop ) ) { |
| 177 | + throw new WCException( 'wc-parameter_defined_twice', $property ); |
| 178 | + } else { |
| 179 | + $this->reference->setProperty( $scope, $property, new $attributeClass( $value ) ); |
| 180 | + } |
| 181 | + } |
| 182 | + # Set attribute |
| 183 | + continue; |
| 184 | + } |
| 185 | + |
| 186 | + # Match names. |
| 187 | + $match = False; |
| 188 | + list( $nameEnum, $namePartText ) = WCNameTypeEnum::matchPrefix( $parameterText, |
| 189 | + WCNameTypeEnum::$magicWordArray, WCNameTypeEnum::$flipMagicWordKeys, 'WCNameTypeEnum' ); |
| 190 | + if ( $namePartText ) { |
| 191 | + list( $namePartEnum, $nameNum ) = WCNamePartEnum::matchPartAndNumber( |
| 192 | + $namePartText, WCNamePartEnum::$magicWordArray, WCNamePartEnum::$flipMagicWordKeys, 'WCNamePartEnum' ); |
| 193 | + if ( $namePartEnum ) { |
| 194 | + if ( !$nameEnum ) { |
| 195 | + $nameEnum = new WCNameTypeEnum(); |
| 196 | + } |
| 197 | + $match = True; |
| 198 | + } elseif ( $nameEnum ) { |
| 199 | + $namePartEnum = new WCNamePartEnum(); |
| 200 | + $match = True; |
| 201 | + } |
| 202 | + } elseif ( $nameEnum ) { |
| 203 | + $namePartEnum = new WCNamePartEnum(); |
| 204 | + $nameNum = 1; |
| 205 | + $match = True; |
| 206 | + } |
| 207 | + if ( $match ) { |
| 208 | + if ( is_null( $this->reference->getNames( $scope, $nameEnum ) ) ) { |
| 209 | + $this->reference->setNames( $scope, $nameEnum, new WCNames() ); |
| 210 | + } |
| 211 | + $theNames = $this->reference->getNames( $scope, $nameEnum ); |
| 212 | + $part = $theNames->getNamePart( $nameNum, $namePartEnum ); |
| 213 | + if ( $wikiCitationValidateArguments && isset( $part ) ) { |
| 214 | + throw new WCException( 'wc-parameter_defined_twice', $nameEnum . $nameNum. '-' . $namePartEnum ); |
| 215 | + } else { |
| 216 | + $theNames->setNamePart( $nameNum, $namePartEnum, $value ); |
| 217 | + } |
| 218 | + continue; |
| 219 | + } |
| 220 | + |
| 221 | + # Argument has no matches. |
| 222 | + if ( $wikiCitationValidateArguments ) { |
| 223 | + throw new WCException( 'wc-parameter-unknown', $parameterText ); |
| 224 | + } |
| 225 | + } |
| 226 | + |
| 227 | + } |
| 228 | + |
| 229 | + |
| 230 | + /** |
| 231 | + * Renders the citation and stores the result in $this->citation. |
| 232 | + * @param WCStyle $style |
| 233 | + * @return array = the rendered citation and sorting parts. |
| 234 | + */ |
| 235 | + public function render() { |
| 236 | + |
| 237 | + # Build the citation |
| 238 | + if ( $this->citationLength->key == WCCitationLengthEnum::short ) { |
| 239 | + switch ( $this->citationType->key ) { |
| 240 | + case WCCitationTypeEnum::note: |
| 241 | + list( $citation, $sortingParts ) = $this->style->renderShortNoteCitation( $this ); |
| 242 | + break; |
| 243 | + case WCCitationTypeEnum::inline: |
| 244 | + list( $citation, $sortingParts ) = $this->style->renderShortInlineCitation( $this ); |
| 245 | + break; |
| 246 | + case WCCitationTypeEnum::authorDate: |
| 247 | + list( $citation, $sortingParts ) = $this->style->renderShortAuthorDateCitation( $this ); |
| 248 | + } |
| 249 | + } else { |
| 250 | + switch ( $this->citationType->key ) { |
| 251 | + case WCCitationTypeEnum::note: |
| 252 | + list( $citation, $sortingParts ) = $this->style->renderLongNoteCitation( $this ); |
| 253 | + break; |
| 254 | + case WCCitationTypeEnum::biblio: |
| 255 | + list( $citation, $sortingParts ) = $this->style->renderLongBiblioCitation( $this ); |
| 256 | + break; |
| 257 | + case WCCitationTypeEnum::authorDate: |
| 258 | + list( $citation, $sortingParts ) = $this->style->renderLongAuthorDateCitation( $this ); |
| 259 | + break; |
| 260 | + default: # case WCCitationTypeEnum::inline: |
| 261 | + list( $citation, $sortingParts ) = $this->style->renderLongInlineCitation( $this ); |
| 262 | + } |
| 263 | + } |
| 264 | + |
| 265 | + # Wrap the entire citation in an HTML span element with classes. |
| 266 | + $classHTML = WCStyle::citationHTML . ' ' . |
| 267 | + $this->style->styleHTML . ' ' . |
| 268 | + $this->reference->getWorkType() . ' ' . |
| 269 | + $this->citationType . ' ' . |
| 270 | + $this->citationLength; |
| 271 | + |
| 272 | + return array( WCStyle::wrapHTMLSpan( $citation, $classHTML ), $sortingParts ); |
| 273 | + |
| 274 | + } |
| 275 | + |
| 276 | + |
| 277 | + /** |
| 278 | + * The string representation of this object. |
| 279 | + * @return string citation as wikitext. |
| 280 | + */ |
| 281 | + final public function __toString() { |
| 282 | + return (string) $this->citationText; |
| 283 | + } |
| 284 | + |
| 285 | + |
| 286 | + /** |
| 287 | + * Infer the intended locator value string based on potentially incomplete |
| 288 | + * info. The arguments will be revised to reflect the new types. |
| 289 | + * @param WCPropertyEnum $propertyType |
| 290 | + * @return WCLocator |
| 291 | + */ |
| 292 | + public function inferLocator( WCPropertyEnum &$locatorType ) { |
| 293 | + foreach( $locatorType as $testLocatorTypeKey ) { |
| 294 | + if ( isset( $this->locators[ $testLocatorTypeKey ] ) ) { |
| 295 | + $locatorType->key = $testLocatorTypeKey; |
| 296 | + return $this->locators[ $testLocatorTypeKey ]; |
| 297 | + } |
| 298 | + } |
| 299 | + return Null; |
| 300 | + |
| 301 | + } |
| 302 | + |
| 303 | + |
| 304 | + /** |
| 305 | + * Getter for a locator. |
| 306 | + * @param WCPropertyEnum $type |
| 307 | + * @return WCLocator |
| 308 | + */ |
| 309 | + public function getLocator( WCPropertyEnum $type ) { |
| 310 | + if ( isset( $this->locators[ $type->key ] ) ) { |
| 311 | + return $this->locators[ $type->key ]; |
| 312 | + } else { |
| 313 | + return Null; |
| 314 | + } |
| 315 | + } |
| 316 | + |
| 317 | + |
| 318 | + /** |
| 319 | + * Setter for a locator. |
| 320 | + * @param WCPropertyEnum $type |
| 321 | + * @param WCLocator $locator |
| 322 | + */ |
| 323 | + public function setLocator( WCPropertyEnum $type, WCLocator $locator ) { |
| 324 | + $this->locators[ $type->key ] = $locator; |
| 325 | + } |
| 326 | + |
| 327 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/WCCitation.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 328 | + native |
Index: trunk/extensions/WikiCitation/includes/WCBibliography.php |
— | — | @@ -0,0 +1,139 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +class WCBibliography { |
| 12 | + |
| 13 | + const bibliographyHTML = 'bibliography'; # HTML class for the note marker |
| 14 | + |
| 15 | + protected static $citeStyleAttributeWords, $typeAttributeWords; |
| 16 | + |
| 17 | + protected $marker; |
| 18 | + |
| 19 | + protected $citationStyle, $citationType; |
| 20 | + |
| 21 | + protected $styleHTML; |
| 22 | + |
| 23 | + /** |
| 24 | + * Static initializer. |
| 25 | + */ |
| 26 | + public static function init() { |
| 27 | + $citeStyleMW = MagicWord::get( 'wc_citestyle_attrib' ); |
| 28 | + self::$citeStyleAttributeWords = $citeStyleMW->getSynonyms(); |
| 29 | + $typeMW = MagicWord::get( 'wc_type_attrib' ); |
| 30 | + self::$typeAttributeWords = $typeMW->getSynonyms(); |
| 31 | + } |
| 32 | + |
| 33 | + /** |
| 34 | + * Get a new WCBibliography object based on HTML arguments. |
| 35 | + * @param array $args |
| 36 | + * @return WCBibliography |
| 37 | + */ |
| 38 | + public static function getBibliography( array $args, WCStyle $defaultStyle ) { |
| 39 | + foreach( $args as $attrib => $value ) { |
| 40 | + if ( in_array( $attrib, self::$citeStyleAttributeWords ) ) { |
| 41 | + $styleClassName = WCArgumentReader::matchStyleClassName( $value ); |
| 42 | + } elseif ( in_array( $attrib, self::$typeAttributeWords ) ) { |
| 43 | + $citationTypeID = WCCitationTypeEnum::match( $value ); |
| 44 | + if ( isset( $citationTypeID ) ) { |
| 45 | + $citationType = new WCCitationTypeEnum( $citationTypeID ); |
| 46 | + } |
| 47 | + } elseif ( $args[ 'style' ] ) { |
| 48 | + $this->styleHTML = ' style="' . $args[ 'style' ] . '"'; |
| 49 | + } elseif ( $args[ 'id' ] ) { |
| 50 | + $this->styleHTML = ' id="' . $args[ 'id' ] . '"'; |
| 51 | + } |
| 52 | + } |
| 53 | + |
| 54 | + if ( isset( $styleClassName ) ) { |
| 55 | + # See if a specific style object has already been defined, and if so, use it. |
| 56 | + $styleObject = WCArticle::getStyle( $styleClassName ); |
| 57 | + } else { |
| 58 | + # Use default citation style. |
| 59 | + $styleObject = $defaultStyle; |
| 60 | + } |
| 61 | + |
| 62 | + if ( isset( $citationType ) && $citationTypeID === WCCitationTypeEnum::authorDate ) { |
| 63 | + return new WCBibliography( $styleObject, WCCitationTypeEnum::$authorDate ); |
| 64 | + } else { |
| 65 | + return new WCBibliography( $styleObject, WCCitationTypeEnum::$biblio ); |
| 66 | + } |
| 67 | + } |
| 68 | + |
| 69 | + public function __construct( WCStyle $style, WCCitationTypeEnum $type ) { |
| 70 | + $this->citationStyle = $style; |
| 71 | + $this->citationType = $type; |
| 72 | + $this->marker = 'BwC-' . mt_rand(); |
| 73 | + } |
| 74 | + |
| 75 | + public function getMarker() { |
| 76 | + return $this->marker; |
| 77 | + } |
| 78 | + |
| 79 | + /** |
| 80 | + * Need to create separate WCCitation object for each entry here!! |
| 81 | + * Enter description here ... |
| 82 | + * @param unknown_type $text |
| 83 | + * @param WCArticle $article |
| 84 | + */ |
| 85 | + public function render( &$text, WCReferenceStore $referenceStore ) { |
| 86 | + |
| 87 | + $references = $referenceStore->getReferences(); |
| 88 | + |
| 89 | + $entries = array(); |
| 90 | + |
| 91 | + # Render entries in biblio format. |
| 92 | + foreach( $references as $key => $reference ) { |
| 93 | + $citation = new WCCitation( $reference ); |
| 94 | + $citation->style = $this->citationStyle; |
| 95 | + $citation->citationType = $this->citationType; |
| 96 | + $citation->citationLength = WCCitationLengthEnum::$long; |
| 97 | + $entries[ $key ] = $citation->render(); |
| 98 | + } |
| 99 | + |
| 100 | + # Sort bibliography. |
| 101 | + $this->sortBibliography( $entries ); |
| 102 | + |
| 103 | + # Generate bibliography. |
| 104 | + $bibliography = '<ul class="bibliography"' . $this->styleHTML . '>' . PHP_EOL; |
| 105 | + foreach ( $entries as $key => $entry ) { |
| 106 | + $bibliography .= '<li id="' . $references[ $key ]->id . '">' . $entry[0] . '</li>' . PHP_EOL; |
| 107 | + } |
| 108 | + $bibliography .= '</ul>'; |
| 109 | + $text = str_replace( $this->marker, $bibliography, $text ); |
| 110 | + } |
| 111 | + |
| 112 | + protected function sortBibliography( array &$entries ) { |
| 113 | + uasort( $entries, array( 'WCBibliography', 'compareBibliographyEntries' ) ); |
| 114 | + } |
| 115 | + |
| 116 | + protected static function compareBibliographyEntries( array $entry1, array $entry2 ) { |
| 117 | + $segment1 = $entry1[1]; # WCSegment objects (usually WCGroupSegment). |
| 118 | + $segment2 = $entry2[1]; # |
| 119 | + $segment1->rewind(); |
| 120 | + $segment2->rewind(); |
| 121 | + while ( $segment1->valid() && $segment2->valid() ) { |
| 122 | + $part1 = $segment1->current(); |
| 123 | + $part2 = $segment2->current(); |
| 124 | + $cmp = strnatcasecmp( $part1, $part2 ); |
| 125 | + if ( $cmp ) { |
| 126 | + return $cmp; |
| 127 | + } |
| 128 | + $segment1->next(); |
| 129 | + $segment2->next(); |
| 130 | + } |
| 131 | + return 0; |
| 132 | + } |
| 133 | + |
| 134 | +} |
| 135 | + |
| 136 | + |
| 137 | +/** |
| 138 | + * Static initializer. |
| 139 | + */ |
| 140 | +WCBibliography::init(); |
Property changes on: trunk/extensions/WikiCitation/includes/WCBibliography.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 141 | + native |
Index: trunk/extensions/WikiCitation/includes/WCReferenceStore.php |
— | — | @@ -0,0 +1,138 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Represents a cache of unique WCReference objects. |
| 13 | + */ |
| 14 | +class WCReferenceStore { |
| 15 | + |
| 16 | + /** |
| 17 | + * List of unique references |
| 18 | + * @var array |
| 19 | + */ |
| 20 | + protected $referenceList = array(); |
| 21 | + |
| 22 | + /** |
| 23 | + * Array of references keyed to ID. |
| 24 | + * Each entry in the array is not necessarily unique |
| 25 | + * @var array [ intR ] => WCReference |
| 26 | + */ |
| 27 | + protected $references = array(); |
| 28 | + |
| 29 | + /** |
| 30 | + * Hash table for references. |
| 31 | + * @var array ( stringH => array ( int => intR ) ) |
| 32 | + */ |
| 33 | + protected $hashTable = array(); # Hash array for unique citations. |
| 34 | + |
| 35 | + /** |
| 36 | + * Constructor. |
| 37 | + */ |
| 38 | +# public function __construct() { |
| 39 | +# } |
| 40 | + |
| 41 | + /** |
| 42 | + * Add a reference to the cache, checking for prior duplicates. |
| 43 | + * @param integer $key = a unique key |
| 44 | + * @param WCReference $reference |
| 45 | + * @return integer = number of citations from last use of this reference. |
| 46 | + */ |
| 47 | + public function addUniqueReference( $key, WCReference $reference ) { |
| 48 | + $referenceKey = array( $key ); |
| 49 | + |
| 50 | + $hash = $reference->getHash(); |
| 51 | + if ( empty( $hash ) ) { |
| 52 | + # If empty hash, search all prior hashed references. |
| 53 | + foreach( $this->hashTable as &$hashArray ) { |
| 54 | + foreach( $hashArray as &$testKey ) { |
| 55 | + $testReference = $this->references[ $testKey ]; |
| 56 | + # If $reference can be considered a short form of prior reference: |
| 57 | + if ( $reference->shortFormMatches( $testReference ) ) { |
| 58 | + $lastKey = end( $testReference ->keys ); |
| 59 | + $testReference->keys += $referenceKey; |
| 60 | + # Forget this reference: |
| 61 | + $this->references[ $key ] = $testReference; |
| 62 | + return $key - $lastKey; |
| 63 | + } |
| 64 | + # If prior reference can be considered a short form of $reference: |
| 65 | + elseif ( $testReference->shortFormMatches( $reference ) ) { |
| 66 | + $lastKey = end( $testReference ->keys ); |
| 67 | + $reference->keys = $testReference->keys + $referenceKey; |
| 68 | + # Forget the earlier reference. |
| 69 | + unset( $this->referenceList [ $testKey ] ); |
| 70 | + $this->referenceList[ $key ] = $reference; |
| 71 | + $this->references[ $testKey ] = $reference; |
| 72 | + $this->references[ $key ] = $reference; |
| 73 | + $testKey = $key; |
| 74 | + return $key - $lastKey; |
| 75 | + } |
| 76 | + } |
| 77 | + } |
| 78 | + } |
| 79 | + # Handle hash table collisions. |
| 80 | + elseif ( isset( $this->hashTable[ $hash ] ) ) { |
| 81 | + # Search collision entries. |
| 82 | + foreach( $this->hashTable[ $hash ] as &$testKey ) { |
| 83 | + $testReference = $this->references[ $testKey ]; |
| 84 | + # If $reference can be considered a short form of prior reference: |
| 85 | + if ( $reference->shortFormMatches( $testReference ) ) { |
| 86 | + $lastKey = end( $testReference ->keys ); |
| 87 | + $testReference->keys += $referenceKey; |
| 88 | + # Forget this reference: |
| 89 | + $this->references[ $key ] = $testReference; |
| 90 | + return $key - $lastKey; |
| 91 | + } |
| 92 | + # if prior reference can be considered a short form of $reference: |
| 93 | + elseif ( $testReference->shortFormMatches( $reference ) ) { |
| 94 | + $lastKey = end( $testReference ->keys ); |
| 95 | + $reference->keys = $testReference->keys + $referenceKey; |
| 96 | + # Forget the earlier reference. |
| 97 | + unset( $this->referenceList [ $testKey ] ); |
| 98 | + $this->referenceList[ $key ] = $reference; |
| 99 | + $this->references[ $testKey ] = $reference; |
| 100 | + $this->references[ $key ] = $reference; |
| 101 | + $testKey = $key; |
| 102 | + return $key - $lastKey; |
| 103 | + } |
| 104 | + } |
| 105 | + # If no collision yet, search prior empty hashes. |
| 106 | + foreach( $this->hashTable[ '' ] as $id => &$testKey ) { |
| 107 | + $testReference = $this->references[ $testKey ]; |
| 108 | + if ( $testReference->shortFormMatches( $reference ) ) { |
| 109 | + $lastKey = end( $testReference ->keys ); |
| 110 | + $reference->keys = $testReference->keys + $referenceKey; |
| 111 | + # Forget the earlier reference. |
| 112 | + unset( $this->referenceList [ $testKey ] ); |
| 113 | + $this->referenceList [ $key ] = $reference; |
| 114 | + $this->references[ $testKey ] = $reference; |
| 115 | + $this->references[ $key ] = $reference; |
| 116 | + # Correct hash table |
| 117 | + unset( $this->hashTable[ '' ][ $id ] ); |
| 118 | + $this->hashTable[ $hash ][] = $key; |
| 119 | + return $key - $lastKey; |
| 120 | + } |
| 121 | + } |
| 122 | + } |
| 123 | + # If no hash table match: |
| 124 | + $reference->keys = $referenceKey; |
| 125 | + $this->referenceList[ $key ] = $reference; |
| 126 | + $this->references[ $key ] = $reference; |
| 127 | + $this->hashTable[ $hash ][] = $key; |
| 128 | + return 0; |
| 129 | + } |
| 130 | + |
| 131 | + public function getReference( $key ) { |
| 132 | + return $this->references[ $key ]; |
| 133 | + } |
| 134 | + |
| 135 | + public function getReferences() { |
| 136 | + return $this->referenceList; |
| 137 | + } |
| 138 | + |
| 139 | +} |
Property changes on: trunk/extensions/WikiCitation/includes/WCReferenceStore.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 140 | + native |
Index: trunk/extensions/WikiCitation/includes/WCException.php |
— | — | @@ -0,0 +1,32 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * An Exception for use within WikiCitation. |
| 13 | + */ |
| 14 | +class WCException extends UnexpectedValueException { |
| 15 | + |
| 16 | + /** |
| 17 | + * Constructor. |
| 18 | + * |
| 19 | + * In addition to a message key, the constructor may include optional |
| 20 | + * arguments of any number, as in: |
| 21 | + * new WCException( 'message-1', ... ); |
| 22 | + * @param messageKey string The message key |
| 23 | + * @param optionalArgs string = any number of arguments |
| 24 | + * @return string Value of object. |
| 25 | + */ |
| 26 | + public function __construct( $messageKey ) { |
| 27 | + $args = func_get_args(); |
| 28 | + array_shift( $args ); |
| 29 | + $transformedMessage = wfMsgReal( $messageKey, $args, true ); |
| 30 | + parent::__construct( $transformedMessage ); |
| 31 | + } |
| 32 | + |
| 33 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/WikiCitation/includes/WCException.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 34 | + native |
Index: trunk/extensions/WikiCitation/includes/WCReference.php |
— | — | @@ -0,0 +1,403 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Part of WikiCitation extension for Mediawiki. |
| 5 | + * |
| 6 | + * @ingroup WikiCitation |
| 7 | + * @file |
| 8 | + */ |
| 9 | + |
| 10 | + |
| 11 | +/** |
| 12 | + * Class representing a unique reference source. |
| 13 | + * |
| 14 | + * There should be only one instance of this object per unique reference. |
| 15 | + * However, there may be multiple instances per WCCitation object, if the same |
| 16 | + * reference is cited multiple times in an article. |
| 17 | + * Instances of this class are created by the WCCitation object. |
| 18 | + */ |
| 19 | +class WCReference { |
| 20 | + |
| 21 | + /** |
| 22 | + * Unique random ID for this reference, for cross-referencing bibliographies. |
| 23 | + * @var string |
| 24 | + */ |
| 25 | + public $id; |
| 26 | + |
| 27 | + /** |
| 28 | + * Keys of all citations in an article that cite this reference. |
| 29 | + * This is set by the WCReferenceStore object. |
| 30 | + * @var unknown_type |
| 31 | + */ |
| 32 | + public $keys = array(); |
| 33 | + |
| 34 | + /** |
| 35 | + * A multidimensional array of WCNames objects. |
| 36 | + * Index 1 (:: WCScopeEnum->key) is the scope of the WCNames object (e.g., work). |
| 37 | + * Index 2 (:: WCNameTypeEnum->key) is the name type of the WCNames object (e.g., author). |
| 38 | + * @var array [ int ] [ int ] => WCNames |
| 39 | + */ |
| 40 | + protected $names = array(); |
| 41 | + |
| 42 | + /** |
| 43 | + * A multidimensional array of WCData objects. |
| 44 | + * Index 1 (:: WCScopeEnum->key) is the scope of the WCData object (e.g., work). |
| 45 | + * Index 2 (:: WCPropertyEnum->key) is the property type of the WCData object (e.g., title). |
| 46 | + * @var array [ int ] [ int ] => WCData |
| 47 | + */ |
| 48 | + protected $properties = array(); |
| 49 | + |
| 50 | + |
| 51 | + /** |
| 52 | + * Constructor. |
| 53 | + */ |
| 54 | + public function __construct() { |
| 55 | + # Construct a random marker for cross-referencing bibliographies: |
| 56 | + $this->id = 'RwC-' . mt_rand(); |
| 57 | + } |
| 58 | + |
| 59 | + |
| 60 | + /** |
| 61 | + * Setter for reference properties. |
| 62 | + * @param WCScopeEnum $scope |
| 63 | + * @param WCPropertyEnum $type |
| 64 | + * @param WCData $data |
| 65 | + */ |
| 66 | + public function setProperty( WCScopeEnum $scope, WCPropertyEnum $type, WCData $data ) { |
| 67 | + $this->properties[ $scope->key ][ $type->key ] = $data; |
| 68 | + } |
| 69 | + |
| 70 | + |
| 71 | + /** |
| 72 | + * Getter for reference properties. |
| 73 | + * @param WCScopeEnum $scope |
| 74 | + * @param WCPropertyEnum $type |
| 75 | + * @return WCData |
| 76 | + */ |
| 77 | + public function getProperty( WCScopeEnum $scope, WCPropertyEnum $type ) { |
| 78 | + if ( isset( $this->properties[ $scope->key ][ $type->key ] ) ) { |
| 79 | + return $this->properties[ $scope->key ][ $type->key ]; |
| 80 | + } else { |
| 81 | + return Null; |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + |
| 86 | + /** |
| 87 | + * Setter for reference names. |
| 88 | + * @param WCScopeEnum $scope |
| 89 | + * @param WCNameTypeEnum $type |
| 90 | + * @param WCNames $names |
| 91 | + */ |
| 92 | + public function setNames( WCScopeEnum $scope, WCNameTypeEnum $type, WCNames $names ) { |
| 93 | + $this->names[ $scope->key ][ $type->key ] = $names; |
| 94 | + } |
| 95 | + |
| 96 | + |
| 97 | + /** |
| 98 | + * Getter for reference names. |
| 99 | + * @param WCScopeEnum $scope |
| 100 | + * @param WCNameTypeEnum $names |
| 101 | + * @return WCNames |
| 102 | + */ |
| 103 | + public function getNames( WCScopeEnum $scope, WCNameTypeEnum $names ) { |
| 104 | + if ( isset( $this->names[ $scope->key ][ $names->key ] ) ) { |
| 105 | + return $this->names[ $scope->key ][ $names->key ]; |
| 106 | + } else { |
| 107 | + return Null; |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + |
| 112 | + /** |
| 113 | + * Finalize the reference after all data has been added. |
| 114 | + * No data about the reference should be added after this function is called. |
| 115 | + * The function makes inferences about possible missing data. |
| 116 | + */ |
| 117 | + public function finalize() { |
| 118 | + |
| 119 | + # If the reference type values are not set, try to infer them. |
| 120 | + $this->setInferredTypes(); |
| 121 | + |
| 122 | + # Make other property inferences |
| 123 | + $this->setInferredProperties(); |
| 124 | + |
| 125 | + # Sort the names on the basis of name key order, maintaining keys. |
| 126 | + foreach( $this->names as $nameTypes ) { |
| 127 | + foreach( $nameTypes as $names ) { |
| 128 | + if ( $names ) { |
| 129 | + $names->sort(); |
| 130 | + } |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | + } |
| 135 | + |
| 136 | + |
| 137 | + /** |
| 138 | + * Infer the intended WCNames object based on potentially incomplete info. |
| 139 | + * The arguments will be revised to reflect the new types. |
| 140 | + * @param WCScopeEnum $scope |
| 141 | + * @param WCNameTypeEnum $nameType |
| 142 | + * @return WCNames |
| 143 | + */ |
| 144 | + public function inferNames( WCScopeEnum &$scope, WCNameTypeEnum &$nameType ) { |
| 145 | + foreach( $scope as $testScopeKey ) { |
| 146 | + foreach( $nameType as $testNameTypeKey ) { |
| 147 | + if ( isset( $this->names[ $testScopeKey ][ $testNameTypeKey ] ) ) { |
| 148 | + $scope->key = $testScopeKey; |
| 149 | + $nameType->key = $testNameTypeKey; |
| 150 | + return $this->names[ $testScopeKey ][ $testNameTypeKey ]; |
| 151 | + } |
| 152 | + } |
| 153 | + } |
| 154 | + return Null; |
| 155 | + } |
| 156 | + |
| 157 | + |
| 158 | + /** |
| 159 | + * Infer the intended property value string based on potentially incomplete |
| 160 | + * info. The arguments will be revised to reflect the new types. |
| 161 | + * This method should not be used with locator propreties. |
| 162 | + * @param WCScopeEnum $scope |
| 163 | + * @param WCPropertyEnum $propertyType |
| 164 | + * @return WCData |
| 165 | + */ |
| 166 | + public function inferProperty( WCScopeEnum &$scope, WCPropertyEnum &$propertyType ) { |
| 167 | + foreach( $scope as $testScopeKey ) { |
| 168 | + foreach( $propertyType as $testPropertyTypeKey ) { |
| 169 | + if ( isset( $this->properties[ $testScopeKey ][ $testPropertyTypeKey ] ) ) { |
| 170 | + $scope->key = $testScopeKey; |
| 171 | + $propertyType->key = $testPropertyTypeKey; |
| 172 | + return $this->properties[ $testScopeKey ][ $testPropertyTypeKey ]; |
| 173 | + } |
| 174 | + } |
| 175 | + } |
| 176 | + return Null; |
| 177 | + |
| 178 | + } |
| 179 | + |
| 180 | + |
| 181 | + /** |
| 182 | + * Gets the work type (i.e., book, article, etc.) |
| 183 | + * @return WCSourceTypeEnum |
| 184 | + */ |
| 185 | + public function getWorkType() { |
| 186 | + if ( isset( $this->properties[ WCScopeEnum::work ][ WCPropertyEnum::type ] ) ) { |
| 187 | + return $this->properties[ WCScopeEnum::work ][ WCPropertyEnum::type ]->parameter; |
| 188 | + } else { |
| 189 | + return WCSourceTypeEnum::$general; |
| 190 | + } |
| 191 | + } |
| 192 | + |
| 193 | + |
| 194 | + /** |
| 195 | + * Gets the container type (i.e., book, periodical, etc.) |
| 196 | + * @return WCSourceTypeEnum |
| 197 | + */ |
| 198 | + public function getContainerType() { |
| 199 | + if ( isset( $this->properties[ WCScopeEnum::container ][ WCPropertyEnum::type ] ) ) { |
| 200 | + return $this->properties[ WCScopeEnum::container ][ WCPropertyEnum::type ]->parameter; |
| 201 | + } else { |
| 202 | + return WCSourceTypeEnum::$general; |
| 203 | + } |
| 204 | + } |
| 205 | + |
| 206 | + |
| 207 | + /** |
| 208 | + * Gets the series type (i.e., journal, newspaper, etc.) |
| 209 | + * @return WCSourceTypeEnum |
| 210 | + */ |
| 211 | + public function getSeriesType() { |
| 212 | + if ( isset( $this->properties[ WCScopeEnum::series ][ WCPropertyEnum::type ] ) ) { |
| 213 | + return $this->properties[ WCScopeEnum::series ][ WCPropertyEnum::type ]->parameter; |
| 214 | + } else { |
| 215 | + return WCSourceTypeEnum::$general; |
| 216 | + } |
| 217 | + } |
| 218 | + |
| 219 | + |
| 220 | + /** |
| 221 | + * Determine if $this can be considered a short form of the argument. |
| 222 | + * If so, then determine the number of matches. |
| 223 | + * |
| 224 | + * @param WCNames $names |
| 225 | + * @return integer|boolean |
| 226 | + */ |
| 227 | + public function shortFormMatches( WCReference $reference ) { |
| 228 | + $matches = 0; |
| 229 | + # Compare names. |
| 230 | + foreach( $this->names as $scopeKey => $nameTypes ) { |
| 231 | + foreach( $nameTypes as $nameTypeKey => $thisNames ) { |
| 232 | + $otherNames = $reference->getNames( new WCScopeEnum( $scopeKey ), new WCNameTypeEnum( $nameTypeKey ) ); |
| 233 | + if ( isset( $otherNames ) ) { |
| 234 | + $subMatches = $thisNames->shortFormMatches( $otherNames ); |
| 235 | + if ( $subMatches === False ) { |
| 236 | + return False; |
| 237 | + } else { |
| 238 | + $matches += $subMatches; |
| 239 | + } |
| 240 | + } |
| 241 | + } |
| 242 | + } |
| 243 | + # Compare properties. |
| 244 | + foreach( $this->properties as $scopeKey => $propertyTypes ) { |
| 245 | + foreach( $propertyTypes as $propertyTypeKey => $thisProperty ) { |
| 246 | + $otherProperty = $reference->getProperty( new WCScopeEnum( $scopeKey ), new WCPropertyEnum( $propertyTypeKey ) ); |
| 247 | + if ( isset( $otherProperty ) ) { |
| 248 | + $subMatches = $thisProperty->shortFormMatches( $otherProperty ); |
| 249 | + if ( $subMatches === False ) { |
| 250 | + return False; |
| 251 | + } else { |
| 252 | + $matches += $subMatches; |
| 253 | + } |
| 254 | + } |
| 255 | + } |
| 256 | + } |
| 257 | + return $matches; |
| 258 | + |
| 259 | + } |
| 260 | + |
| 261 | + |
| 262 | + /** |
| 263 | + * Get a hash value which is roughly (though not always) unique to the citation. |
| 264 | + * The hash value is author surname concatenated with year. |
| 265 | + * If no author surname or year are given, the hash is an empty string. |
| 266 | + * @return string The hash value |
| 267 | + */ |
| 268 | + public function getHash() { |
| 269 | + if ( isset( $this->names[ WCScopeEnum::work ][ WCNameTypeEnum::author ] ) ) { |
| 270 | + $surname = $this->names[ WCScopeEnum::work ][ WCNameTypeEnum::author ]->getNamePart( 1, WCNamePartEnum::$surname ); |
| 271 | + if ( $surname ) { |
| 272 | + $hash = $surname; |
| 273 | + } else { |
| 274 | + return ''; |
| 275 | + } |
| 276 | + } else { |
| 277 | + return ''; |
| 278 | + } |
| 279 | + if ( isset( $this->properties[ WCScopeEnum::work ][ WCPropertyEnum::date ] ) ) { |
| 280 | + $hash .= $this->properties[ WCScopeEnum::work ][ WCPropertyEnum::date ]->year; |
| 281 | + return $hash; |
| 282 | + } else { |
| 283 | + return ''; |
| 284 | + } |
| 285 | + |
| 286 | + } |
| 287 | + |
| 288 | + |
| 289 | + /** |
| 290 | + * Infer the intended property types for each scope, if not set. |
| 291 | + */ |
| 292 | + protected function setInferredTypes() { |
| 293 | + |
| 294 | + # If any series name or property has been defined: |
| 295 | + if ( isset( $this->names[ WCScopeEnum::series ] ) || isset( $this->properties[ WCScopeEnum::series ] ) ) { |
| 296 | + $series = &$this->properties[ WCScopeEnum::series ][ WCPropertyEnum::type ]; |
| 297 | + if ( is_null( $series ) ) { |
| 298 | + # A series property has been defined, but the type has not been defined, assume it is a periodical: |
| 299 | + $series = new WCTypeData( WCSourceTypeEnum::$periodical ); |
| 300 | + } |
| 301 | + if ( isset( $this->properties[ WCScopeEnum::work ][ WCPropertyEnum::type ] ) ) { |
| 302 | + return; |
| 303 | + } |
| 304 | + else { |
| 305 | + switch ( $series->parameter->key ) { |
| 306 | + case WCSourceTypeEnum::periodical: |
| 307 | + case WCSourceTypeEnum::journal: |
| 308 | + case WCSourceTypeEnum::magazine: |
| 309 | + case WCSourceTypeEnum::newspaper: |
| 310 | + # If the series is a periodical, the work is likely an article. |
| 311 | + $type = WCSourceTypeEnum::$article; |
| 312 | + break; |
| 313 | + # If the series is designated as a book, encyclopedia or dictionary, the user probably intended it to be the container. |
| 314 | + case WCSourceTypeEnum::book: |
| 315 | + $type = WCSourceTypeEnum::$chapter; |
| 316 | + $this->properties[ WCScopeEnum::container ][ WCPropertyEnum::type ] = $series; |
| 317 | + unset( $series ); |
| 318 | + break; |
| 319 | + case WCSourceTypeEnum::encyclopedia: |
| 320 | + case WCSourceTypeEnum::dictionary: |
| 321 | + $type = new WCSourceTypeEnum( WCSourceTypeEnum::entry ); |
| 322 | + $this->properties[ WCScopeEnum::container ][ WCPropertyEnum::type ] = $series; |
| 323 | + unset( $series ); |
| 324 | + break; |
| 325 | + default: |
| 326 | + $type = new WCSourceTypeEnum( WCSourceTypeEnum::general ); |
| 327 | + } |
| 328 | + $this->properties[ WCScopeEnum::work ][ WCPropertyEnum::type ] = |
| 329 | + new WCTypeData( $type ); |
| 330 | + return; |
| 331 | + } |
| 332 | + } |
| 333 | + |
| 334 | + # If any container name or property has been defined: |
| 335 | + if ( isset( $this->names[ WCScopeEnum::container ] ) || isset( $this->properties[ WCScopeEnum::container ] ) ) { |
| 336 | + $container = &$this->properties[ WCScopeEnum::container ][ WCPropertyEnum::type ]; |
| 337 | + if ( ! isset( $container ) ) { |
| 338 | + # A series property has been defined, but the type has not been defined, assume it is a periodical: |
| 339 | + $container = new WCTypeData( WCSourceTypeEnum::$book ); |
| 340 | + } |
| 341 | + if ( isset( $this->properties[ WCScopeEnum::work ][ WCPropertyEnum::type ] ) ) { |
| 342 | + return; |
| 343 | + } |
| 344 | + else { |
| 345 | + switch ( $container->parameter->key ) { |
| 346 | + # If the series is an encyclopedia or dictionary, the work is likely a book. |
| 347 | + case WCSourceTypeEnum::encyclopedia: |
| 348 | + case WCSourceTypeEnum::dictionary: |
| 349 | + $type = WCSourceTypeEnum::$book; |
| 350 | + break; |
| 351 | + # If the container is designated as a periodical, the user probably intended it to be the series. |
| 352 | + case WCSourceTypeEnum::periodical: |
| 353 | + case WCSourceTypeEnum::journal: |
| 354 | + case WCSourceTypeEnum::magazine: |
| 355 | + case WCSourceTypeEnum::newspaper: |
| 356 | + $type = WCSourceTypeEnum::$article; |
| 357 | + $this->properties[ WCScopeEnum::series ][ WCPropertyEnum::type ] = $container; |
| 358 | + unset( $container ); |
| 359 | + default: |
| 360 | + $type = WCSourceTypeEnum::$general; |
| 361 | + } |
| 362 | + $this->properties[ WCScopeEnum::work ][ WCPropertyEnum::type ] = |
| 363 | + new WCTypeData( $type ); |
| 364 | + return; |
| 365 | + } |
| 366 | + } |
| 367 | + } |
| 368 | + |
| 369 | + /** |
| 370 | + * Infer certain intended property values, if the user-set values do not |
| 371 | + * make sense. |
| 372 | + */ |
| 373 | + protected function setInferredProperties() { |
| 374 | + # Unlike works, containers and series should not have "authors". |
| 375 | + if ( isset( $this->names[ WCScopeEnum::container ][ WCNameTypeEnum::author ] ) ) { |
| 376 | + # If there is a work author, then the user probably meant that. |
| 377 | + if ( isset( $this->names[ WCScopeEnum::work ][ WCNameTypeEnum::author ] ) ) { |
| 378 | + $this->names[ WCScopeEnum::work ][ WCNameTypeEnum::author ] = $this->names[ WCScopeEnum::series ][ WCNameTypeEnum::author ]; |
| 379 | + unset( $this->names[ WCScopeEnum::container ][ WCNameTypeEnum::author ] ); |
| 380 | + } else { |
| 381 | + # If there is a work author also, the user probably meant editor. |
| 382 | + if ( isset( $this->names[ WCScopeEnum::container ][ WCNameTypeEnum::editor ] ) ) { |
| 383 | + $this->names[ WCScopeEnum::container ][ WCNameTypeEnum::editor ] = $this->names[ WCScopeEnum::series ][ WCNameTypeEnum::author ]; |
| 384 | + unset( $this->names[ WCScopeEnum::container ][ WCNameTypeEnum::author ] ); |
| 385 | + } |
| 386 | + } |
| 387 | + } |
| 388 | + if ( isset( $this->names[ WCScopeEnum::series ][ WCNameTypeEnum::author ] ) ) { |
| 389 | + # If there is on work author, then the user probably meant that. |
| 390 | + if ( !isset( $this->names[ WCScopeEnum::work ][ WCNameTypeEnum::author ] ) ) { |
| 391 | + $this->names[ WCScopeEnum::work ][ WCNameTypeEnum::author ] = $this->names[ WCScopeEnum::series ][ WCNameTypeEnum::author ]; |
| 392 | + unset( $this->names[ WCScopeEnum::series ][ WCNameTypeEnum::author ] ); |
| 393 | + } else { |
| 394 | + # If there is a work author also, the user probably meant editor. |
| 395 | + if ( !isset( $this->names[ WCScopeEnum::series ][ WCNameTypeEnum::editor ] ) ) { |
| 396 | + $this->names[ WCScopeEnum::series ][ WCNameTypeEnum::editor ] = $this->names[ WCScopeEnum::series ][ WCNameTypeEnum::author ]; |
| 397 | + unset( $this->names[ WCScopeEnum::series ][ WCNameTypeEnum::author ] ); |
| 398 | + } |
| 399 | + } |
| 400 | + } |
| 401 | + } |
| 402 | + |
| 403 | + |
| 404 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/WikiCitation/includes/WCReference.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 405 | + native |
Property changes on: trunk/extensions/WikiCitation/includes |
___________________________________________________________________ |
Added: bugtraq:number |
2 | 406 | + true |