r85719 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r85718‎ | r85719 | r85720 >
Date:13:26, 9 April 2011
Author:foxtrott
Status:deferred (Comments)
Tags:
Comment:
extension creation
Modified paths:
  • /trunk/extensions/SemanticLingo (added) (history)
  • /trunk/extensions/SemanticLingo/COPYING (added) (history)
  • /trunk/extensions/SemanticLingo/SemanticGlossary.i18n.php (added) (history)
  • /trunk/extensions/SemanticLingo/SemanticGlossary.php (added) (history)
  • /trunk/extensions/SemanticLingo/SemanticGlossaryElement.php (added) (history)
  • /trunk/extensions/SemanticLingo/SemanticGlossaryMessageLog.php (added) (history)
  • /trunk/extensions/SemanticLingo/SemanticGlossaryParser.php (added) (history)
  • /trunk/extensions/SemanticLingo/SemanticGlossarySettings.php (added) (history)
  • /trunk/extensions/SemanticLingo/SpecialSemanticGlossaryBrowser.php (added) (history)
  • /trunk/extensions/SemanticLingo/skins (added) (history)
  • /trunk/extensions/SemanticLingo/skins/SemanticGlossary.css (added) (history)
  • /trunk/extensions/SemanticLingo/skins/SemanticGlossaryBrowser.css (added) (history)

Diff [purge]

Index: trunk/extensions/SemanticLingo/SpecialSemanticGlossaryBrowser.php
@@ -0,0 +1,459 @@
 2+<?php
 3+
 4+/**
 5+ * File holding the SpecialSemanticGlossaryBrowser class.
 6+ *
 7+ * @author Stephan Gambke
 8+ *
 9+ * @file
 10+ * @ingroup SemanticGlossary
 11+ */
 12+if ( !defined( 'SG_VERSION' ) ) {
 13+ die( 'This file is part of the Semantic Glossary extension, it is not a valid entry point.' );
 14+}
 15+
 16+/**
 17+ * This class creates and processes Special:GlossaryBrowser.
 18+ *
 19+ * Includable special pages have an execute() function which can be
 20+ * called from either context, so to parse text within them, it's
 21+ * necessary to check $this->mIncluding to determine the correct function
 22+ * to use.
 23+ *
 24+ * @todo Write this class.
 25+ * @ingroup SemanticGlossary
 26+ */
 27+class SpecialSemanticGlossaryBrowser extends SpecialPage {
 28+
 29+ private $mMessages;
 30+
 31+ function __construct () {
 32+ parent::__construct( 'SemanticGlossaryBrowser' );
 33+ $this -> mMessages = new SemanticGlossaryMessageLog();
 34+ }
 35+
 36+ function execute ( $subpage ) {
 37+
 38+ global $wgRequest, $wgOut, $wgUser;
 39+
 40+ // preparation stuff
 41+ $this -> setHeaders();
 42+ $this -> loadModules();
 43+
 44+ $hasEditRights = $wgUser -> isAllowed( 'editglossary' );
 45+
 46+ if ( $this -> isActionAllowed() ) {
 47+
 48+ if ( $wgRequest -> getText( 'submit' ) != null ) {
 49+
 50+ // if the form was submitted, store the data
 51+ $this -> actionStoreData();
 52+ } else if ( $wgRequest -> getText( 'createnew' ) != null ) {
 53+
 54+ // if a new term was defined, create it
 55+ $this -> actionCreateNewTerm();
 56+ } else if ( $wgRequest -> getText( 'delete' ) != null ) {
 57+
 58+ // if a new term was defined, create it
 59+ $this -> actionDeleteData();
 60+ }
 61+ }
 62+
 63+ // get the glossary data
 64+ $parser = new SemanticGlossaryParser();
 65+ $glossaryarray = $parser -> getGlossaryArray( $this -> mMessages );
 66+
 67+ // set function to create a table row (textareas when editing is
 68+ // allowed, else normal text)
 69+ if ( $hasEditRights ) {
 70+ $createTableRowMethod = 'createTableRowForEdit';
 71+ } else {
 72+ $createTableRowMethod = 'createTableRowForDisplay';
 73+ }
 74+
 75+ // create HTML fragment for table rows
 76+
 77+ $tablerows = '';
 78+
 79+ // loop through all terms
 80+ foreach ( $glossaryarray as $term => $glossaryElement ) {
 81+
 82+ // One term may have several definitions. Include them all.
 83+ while ( ( $key = $glossaryElement -> getCurrentKey() ) !== null ) {
 84+
 85+ $sourceArray = $glossaryElement -> getSource( $key );
 86+ $source = $sourceArray[ 2 ] . ':' . $sourceArray[ 1 ] . ':' . $sourceArray[ 0 ];
 87+ $definition = $glossaryElement -> getDefinition( $key );
 88+
 89+ $tablerows .= $this -> $createTableRowMethod( $source, $term, $definition );
 90+
 91+ $glossaryElement -> next();
 92+ }
 93+ }
 94+
 95+ if ( $tablerows != '' ) {
 96+ $listOfTermsFragment =
 97+ Html::rawElement( 'table', null,
 98+ Html::rawElement( 'tbody', null, $tablerows )
 99+ );
 100+
 101+ if ( $hasEditRights ) {
 102+ // append action buttons
 103+ $listOfTermsFragment .=
 104+ Html::element( 'input', array( 'type' => 'submit', 'name' => 'delete', 'value' => wfMsg( 'semanticglossary-deleteselected' ), 'accesskey' => 'd' ) ) .
 105+ Html::element( 'input', array( 'type' => 'submit', 'name' => 'submit', 'value' => wfMsg( 'semanticglossary-savechanges' ), 'accesskey' => 's' ) );
 106+ }
 107+
 108+ $listOfTermsFragment =
 109+ Html::rawElement( 'div', array( 'class' => 'termslist' ),
 110+ Html::element( 'div', array( 'class' => 'heading' ), wfMsg( 'semanticglossary-termsdefined' ) ) .
 111+ $listOfTermsFragment
 112+ );
 113+ } else {
 114+ $listOfTermsFragment =
 115+ Html::rawElement( 'div', array( 'class' => 'termslist' ),
 116+ Html::element( 'div', array( 'class' => 'heading' ), wfMsg( 'semanticglossary-notermsdefined' ) )
 117+ );
 118+ }
 119+
 120+ // From here on no more errors should occur. Create list of errors.
 121+ $errorsFragment = $this -> mMessages -> getMessagesFormatted( SemanticGlossaryMessageLog::SG_NOTICE );
 122+
 123+ if ( $errorsFragment ) {
 124+ $errorsFragment .= Html::rawElement( 'hr' );
 125+ }
 126+
 127+ if ( $hasEditRights ) {
 128+
 129+ // create form fragment to allow input of a new term
 130+ $newTermFragment =
 131+ Html::rawElement( 'hr' ) .
 132+ Html::rawElement( 'div', array( 'class' => 'newterm' ),
 133+ Html::rawElement( 'div', array( 'class' => 'heading' ), wfMsg( 'semanticglossary-enternewterm' ) ) .
 134+ Html::rawElement( 'table', null,
 135+ Html::rawElement( 'tbody', null,
 136+ Html::rawElement( 'tr', array( 'class' => 'row' ),
 137+ Html::rawElement( 'td', array( 'class' => 'termcell' ),
 138+ Html::element( 'textarea', array( 'name' => 'newterm' ) )
 139+ ) .
 140+ Html::rawElement( 'td', array( 'class' => 'definitioncell' ),
 141+ Html::rawElement( 'div', array( 'class' => 'definitionareawrapper' ),
 142+ Html::element( 'textarea', array( 'name' => 'newdefinition' ) )
 143+ )
 144+ )
 145+ )
 146+ )
 147+ ) .
 148+ Html::element( 'input', array( 'type' => 'submit', 'name' => 'createnew', 'value' => wfMsg( 'semanticglossary-createnew' ), 'accesskey' => 'n' ) )
 149+ );
 150+
 151+ $salt = rand( 10000, 99999 );
 152+ $editTokenFragment = Html::rawElement( 'input', array( 'type' => 'hidden', 'name' => 'editToken', 'value' => $wgUser -> editToken( $salt ) . $salt ) );
 153+
 154+ // assemble output
 155+ $output =
 156+ Html::rawElement( 'div', array( 'class' => 'glossarybrowser' ),
 157+ $errorsFragment .
 158+ Html::rawElement( 'form', array( 'method' => 'POST' ),
 159+ $listOfTermsFragment .
 160+ $newTermFragment .
 161+ $editTokenFragment
 162+ )
 163+ );
 164+ } else {
 165+
 166+ // assemble output
 167+ $output =
 168+ Html::rawElement( 'div', array( 'class' => 'glossarybrowser' ),
 169+ $errorsFragment .
 170+ $listOfTermsFragment
 171+ );
 172+ }
 173+
 174+ $wgOut -> addHTML( $output );
 175+ }
 176+
 177+ /**
 178+ * Returns the name that goes in the <h1> in the special page itself, and also the name that
 179+ * will be listed in Special:Specialpages
 180+ *
 181+ * @return String
 182+ */
 183+ function getDescription () {
 184+ return wfMsg( 'semanticglossary-browsertitle' );
 185+ }
 186+
 187+ /**
 188+ * Loads the CSS file for the GlossaryBrowser Special page
 189+ */
 190+ protected function loadModules () {
 191+
 192+ global $wgOut, $wgScriptPath;
 193+
 194+ if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) {
 195+ $wgOut -> addModules( 'ext.SemanticGlossary.Browser' );
 196+ } else {
 197+ $wgOut -> addHeadItem( 'ext.SemanticGlossary.Browser.css', '<link rel="stylesheet" href="' . $wgScriptPath . '/extensions/SemanticGlossary/skins/SemanticGlossaryBrowser.css" />' );
 198+ }
 199+ }
 200+
 201+ /**
 202+ * Gets data from wgRequest and stores it
 203+ */
 204+ protected function actionStoreData () {
 205+
 206+ global $wgRequest;
 207+
 208+ // get ass array of input values
 209+ $inputdata = $wgRequest -> getValues();
 210+
 211+ // loop through all input values
 212+ foreach ( $inputdata as $key => $value ) {
 213+
 214+ // only consider terms here, other parameters are accessed by name
 215+ if ( substr( $key, -5 ) == ':term' ) {
 216+
 217+ // cut off ':term'
 218+ $pageString = substr( $key, 0, -5 );
 219+
 220+ // new data
 221+ $newTerm = $value;
 222+ $newDefinition = $inputdata[ $pageString . ':definition' ];
 223+
 224+ $page = $this -> getPageObjectFromInputName( $pageString );
 225+
 226+ // get its data
 227+ $pageData = smwfGetStore() -> getSemanticData( $page );
 228+
 229+
 230+ // get old values
 231+ $oldTerm = $this -> getPropertyFromData( $pageData, '___glt' );
 232+ if ( !$oldTerm )
 233+ continue;
 234+
 235+ $oldDefinition = $this -> getPropertyFromData( $pageData, '___gld' );
 236+ if ( !$oldDefinition )
 237+ continue;
 238+
 239+ // only store data if anything changed
 240+ if ( $newTerm != $oldTerm || $newDefinition != $oldDefinition ) {
 241+
 242+ $this -> updateData( $page, array(
 243+ '___glt' => $newTerm,
 244+ '___gld' => $newDefinition
 245+ ) );
 246+
 247+ if ( $page -> getArticleID() != 0 ) {
 248+ $this -> mMessages -> addMessage( wfMsg( 'semanticglossary-storedtermdefinedinarticle', array( $oldTerm, $page -> getPrefixedText() ) )
 249+ , SemanticGlossaryMessageLog::SG_WARNING
 250+ );
 251+ }
 252+ }
 253+ }
 254+ }
 255+ }
 256+
 257+ protected function actionCreateNewTerm () {
 258+
 259+ global $wgRequest;
 260+
 261+ $newTerm = $wgRequest -> getText( 'newterm' );
 262+
 263+ if ( $newTerm == null || $newTerm == '' ) {
 264+ $this -> mMessages -> addMessage( 'Term was empty. Nothing created.', SemanticGlossaryMessageLog::SG_WARNING );
 265+ return;
 266+ }
 267+
 268+ $newDefinition = $wgRequest -> getText( 'newdefinition' );
 269+
 270+ $termNumber = 1;
 271+
 272+ // find unused SMW page
 273+ do {
 274+ $page = SMWWikiPageValue::makePage( "GlossaryTerm#$termNumber", 0 );
 275+ $termNumber++;
 276+ } while ( count( smwfGetStore() -> getProperties( $page ) ) > 0 );
 277+
 278+ // store data
 279+ $this -> updateData( $page, array(
 280+ '___glt' => $newTerm,
 281+ '___gld' => $newDefinition
 282+ ) );
 283+ }
 284+
 285+ protected function actionDeleteData () {
 286+
 287+ global $wgRequest;
 288+
 289+ // get ass array of input values
 290+ $inputdata = $wgRequest -> getValues();
 291+
 292+ foreach ( $inputdata as $key => $value ) {
 293+
 294+ // only consider checkboxes here
 295+ if ( substr( $key, -8 ) == ':checked' ) {
 296+
 297+ // cut off ':checked'
 298+ $pageString = substr( $key, 0, -8 );
 299+
 300+ $page = $this -> getPageObjectFromInputName( $pageString );
 301+
 302+ $this -> updateData( $page, array(
 303+ '___glt' => null,
 304+ '___gld' => null
 305+ ) );
 306+
 307+ $title = $page -> getTitle();
 308+
 309+ $oldTerm = $wgRequest -> getVal( $pageString . ':term' );
 310+
 311+ if ( $title && $title -> exists() ) {
 312+
 313+ $this -> mMessages -> addMessage( wfMsg( 'semanticglossary-deletedtermdefinedinarticle', array( $oldTerm, $page -> getPrefixedText() ) )
 314+ , SemanticGlossaryMessageLog::SG_WARNING
 315+ );
 316+ } else {
 317+ $this -> mMessages -> addMessage( wfMsg( 'semanticglossary-termdeleted', array( $oldTerm ) ), SemanticGlossaryMessageLog::SG_NOTICE );
 318+ }
 319+ }
 320+ }
 321+ }
 322+
 323+ protected function getPropertyFromData ( SMWSemanticData &$pageData, $propertyName ) {
 324+
 325+ $property = SMWPropertyValue::makeProperty( $propertyName );
 326+ $propertyValues = $pageData -> getPropertyValues( $property );
 327+
 328+ if ( count( $propertyValues ) > 1 ) {
 329+ $this -> mMessages -> addMessage( wfMsg( 'semanticglossary-storedtermdefinedtwice', array( $pageData -> getSubject() -> getPrefixedText(), $propertyName, $newTerm ) ),
 330+ SemanticGlossaryMessageLog::SG_ERROR
 331+ );
 332+ return false;
 333+ }
 334+
 335+ return $propertyValues[ 0 ] -> getShortWikiText();
 336+ }
 337+
 338+ protected function getPageObjectFromInputName ( $pageString ) {
 339+
 340+ // split the source string into interwiki reference, namespace and page title
 341+ $matches = array( );
 342+ preg_match( '/^(.*):(.*):(.*)$/', $pageString, $matches );
 343+
 344+ // create SMWWikiPageValue (SMW's wiki page representation)
 345+ return SMWWikiPageValue::makePage( $matches[ 3 ], $matches[ 2 ], '', $matches[ 1 ] );
 346+ }
 347+
 348+ protected function updateData ( SMWWikiPageValue &$page, array $data ) {
 349+
 350+ $newData = new SMWSemanticData( $page, false );
 351+
 352+ $oldData = smwfGetStore() -> getSemanticData( $page );
 353+ $oldProps = $oldData -> getProperties();
 354+
 355+ // get properties, replace as requested, retain other properties
 356+ foreach ( $oldProps as $property ) {
 357+
 358+ $propertyID = $property -> getPropertyID();
 359+
 360+ if ( array_key_exists( $propertyID, $data ) ) {
 361+
 362+
 363+ // set new data if defined, else ignore property (i.e. delete property from page)
 364+ if ( $data[ $propertyID ] != null ) {
 365+
 366+ $value = SMWDataValueFactory::newPropertyObjectValue( $property, $data[ $propertyID ] );
 367+ $newData -> addPropertyObjectValue( $property, $value );
 368+ }
 369+
 370+ unset( $data[ $propertyID ] );
 371+ } else {
 372+
 373+ $values = $oldData -> getPropertyValues( $property );
 374+ foreach ( $values as $value ) {
 375+ $newData -> addPropertyObjectValue( $property, $value );
 376+ }
 377+ }
 378+ }
 379+
 380+ // store properties that were not present before, i.e. properties
 381+ // remaining in $data
 382+ foreach ( $data as $propertyID => $propertyValue ) {
 383+
 384+ // set new data if defined, else ignore property (i.e. do not set property on this page)
 385+ if ( $data[ $propertyID ] != null ) {
 386+
 387+ $property = SMWPropertyValue::makeProperty( $propertyID );
 388+ $value = SMWDataValueFactory::newPropertyObjectValue( $property, $data[ $propertyID ] );
 389+ $newData -> addPropertyObjectValue( $property, $value );
 390+ }
 391+
 392+ unset( $data[ $propertyID ] );
 393+ }
 394+
 395+ // finally store the updated page data
 396+ smwfGetStore() -> doDataUpdate( $newData );
 397+ }
 398+
 399+ private function createTableRowForEdit ( $source, $term, $definition ) {
 400+
 401+ return
 402+ Html::rawElement( 'tr', array( 'class' => 'row' ),
 403+ Html::rawElement( 'td', array( 'class' => 'actioncell' ),
 404+ Html::input( "$source:checked", 'true', 'checkbox' )
 405+ ) .
 406+ Html::rawElement( 'td', array( 'class' => 'termcell' ),
 407+ Html::textarea( "$source:term", $term )
 408+ ) .
 409+ Html::rawElement( 'td', array( 'class' => 'definitioncell' ),
 410+ Html::rawElement( 'div', array( 'class' => 'definitionareawrapper' ),
 411+ Html::textarea( "$source:definition", $definition )
 412+ )
 413+ )
 414+ );
 415+ }
 416+
 417+ private function createTableRowForDisplay ( $source, $term, $definition ) {
 418+
 419+ return
 420+ Html::rawElement( 'tr', array( 'class' => 'row' ),
 421+ Html::rawElement( 'td', array( 'class' => 'termcell' ), $term ) .
 422+ Html::rawElement( 'td', array( 'class' => 'definitioncell' ), $definition )
 423+ );
 424+ }
 425+
 426+ /**
 427+ * Checks if the user wants to perform an action, has the necessary right
 428+ * and submitted a valid edit token.
 429+ *
 430+ * @return Boolean
 431+ */
 432+ private function isActionAllowed () {
 433+
 434+ global $wgRequest, $wgUser;
 435+
 436+ $editTokenWithSalt = $wgRequest -> getText( 'editToken' );
 437+ $actionRequested = ( $editTokenWithSalt != null );
 438+
 439+ if ( $actionRequested ) { // user wants to perform an action
 440+ if ( $wgUser -> isAllowed( 'editglossary' ) ) { // user has the necessary right
 441+ $editTokenAndSaltArray = explode( EDIT_TOKEN_SUFFIX, $editTokenWithSalt );
 442+ $tokenValid = $wgUser -> matchEditTokenNoSuffix( $editTokenAndSaltArray[ 0 ], $editTokenAndSaltArray[ 1 ] );
 443+
 444+ if ( $tokenValid ) { // edit token is valid
 445+ return true;
 446+ } else {
 447+ $this -> mMessages -> addMessage( wfMsg( 'semanticglossary-brokensession' ), SemanticGlossaryMessageLog::SG_ERROR );
 448+ }
 449+ } else {
 450+ $this -> mMessages -> addMessage( wfMsg( 'semanticglossary-norights' ), SemanticGlossaryMessageLog::SG_ERROR );
 451+ }
 452+ }
 453+
 454+ // user does not want to perform an action
 455+ // OR does not have the rights
 456+ // OR did not submit a valid edit token
 457+ return false;
 458+ }
 459+
 460+}
Property changes on: trunk/extensions/SemanticLingo/SpecialSemanticGlossaryBrowser.php
___________________________________________________________________
Added: svn:eol-style
1461 + native
Index: trunk/extensions/SemanticLingo/SemanticGlossaryMessageLog.php
@@ -0,0 +1,81 @@
 2+<?php
 3+
 4+/**
 5+ * File holding the SemanticGlossaryMessageLog class.
 6+ *
 7+ * @author Stephan Gambke
 8+ *
 9+ * @file
 10+ * @ingroup SemanticGlossary
 11+ */
 12+if ( !defined( 'SG_VERSION' ) ) {
 13+ die( 'This file is part of the Semantic Glossary extension, it is not a valid entry point.' );
 14+}
 15+
 16+/**
 17+ * This class holds messages (errors, warnings, notices) for Semantic Glossary
 18+ *
 19+ * Contains a static function to initiate the parsing.
 20+ *
 21+ * @ingroup SemanticGlossary
 22+ */
 23+class SemanticGlossaryMessageLog {
 24+
 25+ private $mMessages = array( );
 26+ private $parser = null;
 27+
 28+ const SG_ERROR = 1;
 29+ const SG_WARNING = 2;
 30+ const SG_NOTICE = 3;
 31+
 32+ function addMessage ( $message, $severity = self::SG_NOTICE ) {
 33+ $this -> mMessages[ ] = array( $message, $severity );
 34+ }
 35+
 36+ function addError ( $message ) {
 37+ $this -> mMessages[ ] = array( $message, self::SG_ERROR );
 38+ }
 39+
 40+ function addWarning ( $message ) {
 41+ $this -> mMessages[ ] = array( $message, self::SG_WARNING );
 42+ }
 43+
 44+ function addNotice ( $message ) {
 45+ $this -> mMessages[ ] = array( $message, self::SG_NOTICE );
 46+ }
 47+
 48+ function getMessagesFormatted ( $severity = self::SG_WARNING, $header = null ) {
 49+
 50+ global $wgTitle, $wgUser;
 51+
 52+ $ret = '';
 53+
 54+ if ( $header == null ) {
 55+ $header = wfMsg( 'semanticglossary-messageheader' );
 56+ }
 57+
 58+ foreach ( $this -> mMessages as $message ) {
 59+ if ( $message[ 1 ] <= $severity ) {
 60+// $ret .= Html::element( 'li', null, $message[ 0 ] );
 61+ $ret .= "* " . $message[ 0 ] . "\n";
 62+ }
 63+ }
 64+
 65+ if ( $ret != '' ) {
 66+
 67+ if ( !$this -> parser ) {
 68+ $parser = new Parser();
 69+ }
 70+
 71+ $ret = Html::rawElement( 'div', array( 'class' => 'messages' ),
 72+ Html::rawElement( 'div', array( 'class' => 'heading' ), $header ) .
 73+ $parser -> parse( $ret, $wgTitle, ParserOptions::newFromUser( $wgUser ) ) -> getText()
 74+ );
 75+
 76+ }
 77+
 78+ return $ret;
 79+ }
 80+
 81+}
 82+
Property changes on: trunk/extensions/SemanticLingo/SemanticGlossaryMessageLog.php
___________________________________________________________________
Added: svn:eol-style
183 + native
Index: trunk/extensions/SemanticLingo/SemanticGlossaryElement.php
@@ -0,0 +1,77 @@
 2+<?php
 3+
 4+/**
 5+ * File holding the SemanticGlossaryElement class.
 6+ *
 7+ * @author Stephan Gambke
 8+ *
 9+ * @file
 10+ * @ingroup SemanticGlossary
 11+ */
 12+if ( !defined( 'SG_VERSION' ) ) {
 13+ die( 'This file is part of the Semantic Glossary extension, it is not a valid entry point.' );
 14+}
 15+
 16+/**
 17+ * This class represents a term-definition pair.
 18+ * One term may be related to several definitions.
 19+ *
 20+ * @ingroup SemanticGlossary
 21+ */
 22+class SemanticGlossaryElement {
 23+ const SG_DEFINITION = 1;
 24+ const SG_SOURCE = 2;
 25+
 26+ private $mTerm;
 27+ private $mFullDefinition = null;
 28+ private $mDefinitions = array( );
 29+
 30+ public function __construct ( $term=null, $definition=null, $source=null ) {
 31+ $this -> mTerm = $term;
 32+
 33+ if ( $definition ) {
 34+ $this -> addDefinition( $definition, $source );
 35+ }
 36+ }
 37+
 38+ public function addDefinition ( $definition=null, $source=null ) {
 39+
 40+ $this -> mDefinitions[ ] = array(
 41+ self::SG_DEFINITION => $definition,
 42+ self::SG_SOURCE => $source,
 43+ );
 44+ }
 45+
 46+ public function getFullDefinition ( DOMDocument &$doc ) {
 47+
 48+ if ( $this -> mFullDefinition == null ) {
 49+
 50+ $this -> mFullDefinition = $doc -> createElement('span');
 51+
 52+ foreach ( $this -> mDefinitions as $definition ) {
 53+ $element = $doc -> createElement('span', $definition[ self::SG_DEFINITION ] );
 54+ $this -> mFullDefinition -> appendChild( $element );
 55+ }
 56+
 57+ }
 58+
 59+ return $this -> mFullDefinition -> cloneNode( true);
 60+ }
 61+
 62+ public function getCurrentKey () {
 63+ return key( $this -> mDefinitions );
 64+ }
 65+
 66+ public function getSource ( $key ) {
 67+ return $this -> mDefinitions[ $key ][ self::SG_SOURCE ];
 68+ }
 69+
 70+ public function getDefinition ( $key ) {
 71+ return $this -> mDefinitions[ $key ][ self::SG_DEFINITION ];
 72+ }
 73+
 74+ public function next () {
 75+ next( $this -> mDefinitions );
 76+ }
 77+
 78+}
Property changes on: trunk/extensions/SemanticLingo/SemanticGlossaryElement.php
___________________________________________________________________
Added: svn:eol-style
179 + native
Index: trunk/extensions/SemanticLingo/skins/SemanticGlossaryBrowser.css
@@ -0,0 +1,74 @@
 2+/*
 3+* Stylesheet for the markup of the glossary browser.
 4+*/
 5+
 6+.glossarybrowser table {
 7+ margin: 1em 0;
 8+ width: 100%;
 9+ border-collapse: separate;
 10+ border-spacing: 0.4em;
 11+}
 12+
 13+.glossarybrowser .messages,
 14+.glossarybrowser .termslist,
 15+.glossarybrowser .newterm,
 16+.glossarybrowser .setupbutton {
 17+ margin: 2em 0;
 18+}
 19+
 20+.glossarybrowser .heading {
 21+ font-weight: bold;
 22+}
 23+
 24+.glossarybrowser td {
 25+ padding: 0;
 26+ vertical-align: top;
 27+}
 28+
 29+.glossarybrowser .actioncell {
 30+ text-align: center;
 31+}
 32+
 33+.glossarybrowser .termcell {
 34+ width: 20%;
 35+}
 36+
 37+.glossarybrowser .definitioncell {
 38+ width: 80%;
 39+}
 40+
 41+.glossarybrowser .definitioncell .definitionareawrapper {
 42+ position: relative;
 43+}
 44+
 45+.glossarybrowser textarea {
 46+ border: 1px solid gray;
 47+ margin: 0;
 48+ padding: 0;
 49+ height: 1.3em;
 50+ width: 99%;
 51+ resize: none;
 52+ position: static;
 53+ z-index: 1;
 54+ overflow: hidden;
 55+}
 56+
 57+.glossarybrowser .termslist textarea {
 58+ border-color: transparent;
 59+}
 60+
 61+.glossarybrowser .termslist textarea:hover {
 62+ border-color: gray;
 63+}
 64+
 65+.glossarybrowser .termslist textarea:focus {
 66+ border-color: gray;
 67+}
 68+
 69+.glossarybrowser .definitioncell textarea:focus {
 70+ height: 5em;
 71+ position: absolute;
 72+ top: 0;
 73+ left: 0;
 74+ z-index: 2;
 75+}
Property changes on: trunk/extensions/SemanticLingo/skins/SemanticGlossaryBrowser.css
___________________________________________________________________
Added: svn:eol-style
176 + native
Index: trunk/extensions/SemanticLingo/skins/SemanticGlossary.css
@@ -0,0 +1,39 @@
 2+/*
 3+* Stylesheet for the markup of glossary terms in wiki pages.
 4+*/
 5+
 6+.tooltip {
 7+ display: inline;
 8+ position: static;
 9+ cursor: help;
 10+}
 11+
 12+.tooltip_abbr {
 13+ border-bottom: 1px dotted #00f;;
 14+}
 15+
 16+.tooltip_tip {
 17+ display: none;
 18+
 19+ border: 1px solid gray;
 20+ background-color: white;
 21+ padding: 0.1em 0.2em 0.1em 0.1em;
 22+ margin: 0;
 23+ line-height: 1.2em;
 24+
 25+ position: absolute;
 26+ top: 1.1em;
 27+ left: 1em;
 28+}
 29+
 30+.tooltip_tip span {
 31+ display: block;
 32+}
 33+
 34+.tooltip:hover {
 35+ position: relative;
 36+}
 37+
 38+.tooltip:hover .tooltip_tip {
 39+ display: block;
 40+}
Property changes on: trunk/extensions/SemanticLingo/skins/SemanticGlossary.css
___________________________________________________________________
Added: svn:eol-style
141 + native
Index: trunk/extensions/SemanticLingo/COPYING
@@ -0,0 +1,350 @@
 2+The license text below "----" applies to all files within this distribution,
 3+other than those that are in a directory which contains files named "LICENSE"
 4+or "COPYING", or a subdirectory thereof. For those files, the license text
 5+contained in said file overrides any license information contained in
 6+directories of smaller depth. Alternative licenses are typically used for
 7+software that is provided by external parties, and merely packaged with the
 8+Semantic Lingo release for convenience.
 9+
 10+----
 11+
 12+ GNU GENERAL PUBLIC LICENSE
 13+ Version 2, June 1991
 14+
 15+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
 16+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 17+ Everyone is permitted to copy and distribute verbatim copies
 18+ of this license document, but changing it is not allowed.
 19+
 20+ Preamble
 21+
 22+ The licenses for most software are designed to take away your
 23+freedom to share and change it. By contrast, the GNU General Public
 24+License is intended to guarantee your freedom to share and change free
 25+software--to make sure the software is free for all its users. This
 26+General Public License applies to most of the Free Software
 27+Foundation's software and to any other program whose authors commit to
 28+using it. (Some other Free Software Foundation software is covered by
 29+the GNU Library General Public License instead.) You can apply it to
 30+your programs, too.
 31+
 32+ When we speak of free software, we are referring to freedom, not
 33+price. Our General Public Licenses are designed to make sure that you
 34+have the freedom to distribute copies of free software (and charge for
 35+this service if you wish), that you receive source code or can get it
 36+if you want it, that you can change the software or use pieces of it
 37+in new free programs; and that you know you can do these things.
 38+
 39+ To protect your rights, we need to make restrictions that forbid
 40+anyone to deny you these rights or to ask you to surrender the rights.
 41+These restrictions translate to certain responsibilities for you if you
 42+distribute copies of the software, or if you modify it.
 43+
 44+ For example, if you distribute copies of such a program, whether
 45+gratis or for a fee, you must give the recipients all the rights that
 46+you have. You must make sure that they, too, receive or can get the
 47+source code. And you must show them these terms so they know their
 48+rights.
 49+
 50+ We protect your rights with two steps: (1) copyright the software, and
 51+(2) offer you this license which gives you legal permission to copy,
 52+distribute and/or modify the software.
 53+
 54+ Also, for each author's protection and ours, we want to make certain
 55+that everyone understands that there is no warranty for this free
 56+software. If the software is modified by someone else and passed on, we
 57+want its recipients to know that what they have is not the original, so
 58+that any problems introduced by others will not reflect on the original
 59+authors' reputations.
 60+
 61+ Finally, any free program is threatened constantly by software
 62+patents. We wish to avoid the danger that redistributors of a free
 63+program will individually obtain patent licenses, in effect making the
 64+program proprietary. To prevent this, we have made it clear that any
 65+patent must be licensed for everyone's free use or not licensed at all.
 66+
 67+ The precise terms and conditions for copying, distribution and
 68+modification follow.
 69+
 70+ GNU GENERAL PUBLIC LICENSE
 71+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
 72+
 73+ 0. This License applies to any program or other work which contains
 74+a notice placed by the copyright holder saying it may be distributed
 75+under the terms of this General Public License. The "Program", below,
 76+refers to any such program or work, and a "work based on the Program"
 77+means either the Program or any derivative work under copyright law:
 78+that is to say, a work containing the Program or a portion of it,
 79+either verbatim or with modifications and/or translated into another
 80+language. (Hereinafter, translation is included without limitation in
 81+the term "modification".) Each licensee is addressed as "you".
 82+
 83+Activities other than copying, distribution and modification are not
 84+covered by this License; they are outside its scope. The act of
 85+running the Program is not restricted, and the output from the Program
 86+is covered only if its contents constitute a work based on the
 87+Program (independent of having been made by running the Program).
 88+Whether that is true depends on what the Program does.
 89+
 90+ 1. You may copy and distribute verbatim copies of the Program's
 91+source code as you receive it, in any medium, provided that you
 92+conspicuously and appropriately publish on each copy an appropriate
 93+copyright notice and disclaimer of warranty; keep intact all the
 94+notices that refer to this License and to the absence of any warranty;
 95+and give any other recipients of the Program a copy of this License
 96+along with the Program.
 97+
 98+You may charge a fee for the physical act of transferring a copy, and
 99+you may at your option offer warranty protection in exchange for a fee.
 100+
 101+ 2. You may modify your copy or copies of the Program or any portion
 102+of it, thus forming a work based on the Program, and copy and
 103+distribute such modifications or work under the terms of Section 1
 104+above, provided that you also meet all of these conditions:
 105+
 106+ a) You must cause the modified files to carry prominent notices
 107+ stating that you changed the files and the date of any change.
 108+
 109+ b) You must cause any work that you distribute or publish, that in
 110+ whole or in part contains or is derived from the Program or any
 111+ part thereof, to be licensed as a whole at no charge to all third
 112+ parties under the terms of this License.
 113+
 114+ c) If the modified program normally reads commands interactively
 115+ when run, you must cause it, when started running for such
 116+ interactive use in the most ordinary way, to print or display an
 117+ announcement including an appropriate copyright notice and a
 118+ notice that there is no warranty (or else, saying that you provide
 119+ a warranty) and that users may redistribute the program under
 120+ these conditions, and telling the user how to view a copy of this
 121+ License. (Exception: if the Program itself is interactive but
 122+ does not normally print such an announcement, your work based on
 123+ the Program is not required to print an announcement.)
 124+
 125+These requirements apply to the modified work as a whole. If
 126+identifiable sections of that work are not derived from the Program,
 127+and can be reasonably considered independent and separate works in
 128+themselves, then this License, and its terms, do not apply to those
 129+sections when you distribute them as separate works. But when you
 130+distribute the same sections as part of a whole which is a work based
 131+on the Program, the distribution of the whole must be on the terms of
 132+this License, whose permissions for other licensees extend to the
 133+entire whole, and thus to each and every part regardless of who wrote it.
 134+
 135+Thus, it is not the intent of this section to claim rights or contest
 136+your rights to work written entirely by you; rather, the intent is to
 137+exercise the right to control the distribution of derivative or
 138+collective works based on the Program.
 139+
 140+In addition, mere aggregation of another work not based on the Program
 141+with the Program (or with a work based on the Program) on a volume of
 142+a storage or distribution medium does not bring the other work under
 143+the scope of this License.
 144+
 145+ 3. You may copy and distribute the Program (or a work based on it,
 146+under Section 2) in object code or executable form under the terms of
 147+Sections 1 and 2 above provided that you also do one of the following:
 148+
 149+ a) Accompany it with the complete corresponding machine-readable
 150+ source code, which must be distributed under the terms of Sections
 151+ 1 and 2 above on a medium customarily used for software interchange; or,
 152+
 153+ b) Accompany it with a written offer, valid for at least three
 154+ years, to give any third party, for a charge no more than your
 155+ cost of physically performing source distribution, a complete
 156+ machine-readable copy of the corresponding source code, to be
 157+ distributed under the terms of Sections 1 and 2 above on a medium
 158+ customarily used for software interchange; or,
 159+
 160+ c) Accompany it with the information you received as to the offer
 161+ to distribute corresponding source code. (This alternative is
 162+ allowed only for noncommercial distribution and only if you
 163+ received the program in object code or executable form with such
 164+ an offer, in accord with Subsection b above.)
 165+
 166+The source code for a work means the preferred form of the work for
 167+making modifications to it. For an executable work, complete source
 168+code means all the source code for all modules it contains, plus any
 169+associated interface definition files, plus the scripts used to
 170+control compilation and installation of the executable. However, as a
 171+special exception, the source code distributed need not include
 172+anything that is normally distributed (in either source or binary
 173+form) with the major components (compiler, kernel, and so on) of the
 174+operating system on which the executable runs, unless that component
 175+itself accompanies the executable.
 176+
 177+If distribution of executable or object code is made by offering
 178+access to copy from a designated place, then offering equivalent
 179+access to copy the source code from the same place counts as
 180+distribution of the source code, even though third parties are not
 181+compelled to copy the source along with the object code.
 182+
 183+ 4. You may not copy, modify, sublicense, or distribute the Program
 184+except as expressly provided under this License. Any attempt
 185+otherwise to copy, modify, sublicense or distribute the Program is
 186+void, and will automatically terminate your rights under this License.
 187+However, parties who have received copies, or rights, from you under
 188+this License will not have their licenses terminated so long as such
 189+parties remain in full compliance.
 190+
 191+ 5. You are not required to accept this License, since you have not
 192+signed it. However, nothing else grants you permission to modify or
 193+distribute the Program or its derivative works. These actions are
 194+prohibited by law if you do not accept this License. Therefore, by
 195+modifying or distributing the Program (or any work based on the
 196+Program), you indicate your acceptance of this License to do so, and
 197+all its terms and conditions for copying, distributing or modifying
 198+the Program or works based on it.
 199+
 200+ 6. Each time you redistribute the Program (or any work based on the
 201+Program), the recipient automatically receives a license from the
 202+original licensor to copy, distribute or modify the Program subject to
 203+these terms and conditions. You may not impose any further
 204+restrictions on the recipients' exercise of the rights granted herein.
 205+You are not responsible for enforcing compliance by third parties to
 206+this License.
 207+
 208+ 7. If, as a consequence of a court judgment or allegation of patent
 209+infringement or for any other reason (not limited to patent issues),
 210+conditions are imposed on you (whether by court order, agreement or
 211+otherwise) that contradict the conditions of this License, they do not
 212+excuse you from the conditions of this License. If you cannot
 213+distribute so as to satisfy simultaneously your obligations under this
 214+License and any other pertinent obligations, then as a consequence you
 215+may not distribute the Program at all. For example, if a patent
 216+license would not permit royalty-free redistribution of the Program by
 217+all those who receive copies directly or indirectly through you, then
 218+the only way you could satisfy both it and this License would be to
 219+refrain entirely from distribution of the Program.
 220+
 221+If any portion of this section is held invalid or unenforceable under
 222+any particular circumstance, the balance of the section is intended to
 223+apply and the section as a whole is intended to apply in other
 224+circumstances.
 225+
 226+It is not the purpose of this section to induce you to infringe any
 227+patents or other property right claims or to contest validity of any
 228+such claims; this section has the sole purpose of protecting the
 229+integrity of the free software distribution system, which is
 230+implemented by public license practices. Many people have made
 231+generous contributions to the wide range of software distributed
 232+through that system in reliance on consistent application of that
 233+system; it is up to the author/donor to decide if he or she is willing
 234+to distribute software through any other system and a licensee cannot
 235+impose that choice.
 236+
 237+This section is intended to make thoroughly clear what is believed to
 238+be a consequence of the rest of this License.
 239+
 240+ 8. If the distribution and/or use of the Program is restricted in
 241+certain countries either by patents or by copyrighted interfaces, the
 242+original copyright holder who places the Program under this License
 243+may add an explicit geographical distribution limitation excluding
 244+those countries, so that distribution is permitted only in or among
 245+countries not thus excluded. In such case, this License incorporates
 246+the limitation as if written in the body of this License.
 247+
 248+ 9. The Free Software Foundation may publish revised and/or new versions
 249+of the General Public License from time to time. Such new versions will
 250+be similar in spirit to the present version, but may differ in detail to
 251+address new problems or concerns.
 252+
 253+Each version is given a distinguishing version number. If the Program
 254+specifies a version number of this License which applies to it and "any
 255+later version", you have the option of following the terms and conditions
 256+either of that version or of any later version published by the Free
 257+Software Foundation. If the Program does not specify a version number of
 258+this License, you may choose any version ever published by the Free Software
 259+Foundation.
 260+
 261+ 10. If you wish to incorporate parts of the Program into other free
 262+programs whose distribution conditions are different, write to the author
 263+to ask for permission. For software which is copyrighted by the Free
 264+Software Foundation, write to the Free Software Foundation; we sometimes
 265+make exceptions for this. Our decision will be guided by the two goals
 266+of preserving the free status of all derivatives of our free software and
 267+of promoting the sharing and reuse of software generally.
 268+
 269+ NO WARRANTY
 270+
 271+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
 272+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
 273+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
 274+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
 275+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 276+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
 277+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
 278+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
 279+REPAIR OR CORRECTION.
 280+
 281+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
 282+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
 283+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
 284+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
 285+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
 286+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
 287+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
 288+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
 289+POSSIBILITY OF SUCH DAMAGES.
 290+
 291+ END OF TERMS AND CONDITIONS
 292+
 293+ How to Apply These Terms to Your New Programs
 294+
 295+ If you develop a new program, and you want it to be of the greatest
 296+possible use to the public, the best way to achieve this is to make it
 297+free software which everyone can redistribute and change under these terms.
 298+
 299+ To do so, attach the following notices to the program. It is safest
 300+to attach them to the start of each source file to most effectively
 301+convey the exclusion of warranty; and each file should have at least
 302+the "copyright" line and a pointer to where the full notice is found.
 303+
 304+ <one line to give the program's name and a brief idea of what it does.>
 305+ Copyright (C) <year> <name of author>
 306+
 307+ This program is free software; you can redistribute it and/or modify
 308+ it under the terms of the GNU General Public License as published by
 309+ the Free Software Foundation; either version 2 of the License, or
 310+ (at your option) any later version.
 311+
 312+ This program is distributed in the hope that it will be useful,
 313+ but WITHOUT ANY WARRANTY; without even the implied warranty of
 314+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 315+ GNU General Public License for more details.
 316+
 317+ You should have received a copy of the GNU General Public License
 318+ along with this program; if not, write to the Free Software
 319+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 320+
 321+
 322+Also add information on how to contact you by electronic and paper mail.
 323+
 324+If the program is interactive, make it output a short notice like this
 325+when it starts in an interactive mode:
 326+
 327+ Gnomovision version 69, Copyright (C) year name of author
 328+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
 329+ This is free software, and you are welcome to redistribute it
 330+ under certain conditions; type `show c' for details.
 331+
 332+The hypothetical commands `show w' and `show c' should show the appropriate
 333+parts of the General Public License. Of course, the commands you use may
 334+be called something other than `show w' and `show c'; they could even be
 335+mouse-clicks or menu items--whatever suits your program.
 336+
 337+You should also get your employer (if you work as a programmer) or your
 338+school, if any, to sign a "copyright disclaimer" for the program, if
 339+necessary. Here is a sample; alter the names:
 340+
 341+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
 342+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
 343+
 344+ <signature of Ty Coon>, 1 April 1989
 345+ Ty Coon, President of Vice
 346+
 347+This General Public License does not permit incorporating your program into
 348+proprietary programs. If your program is a subroutine library, you may
 349+consider it more useful to permit linking proprietary applications with the
 350+library. If this is what you want to do, use the GNU Library General
 351+Public License instead of this License.
Property changes on: trunk/extensions/SemanticLingo/COPYING
___________________________________________________________________
Added: svn:eol-style
1352 + native
Index: trunk/extensions/SemanticLingo/SemanticGlossaryParser.php
@@ -0,0 +1,226 @@
 2+<?php
 3+
 4+/**
 5+ * File holding the SemanticGlossaryParser class.
 6+ *
 7+ * @author Stephan Gambke
 8+ *
 9+ * @file
 10+ * @ingroup SemanticGlossary
 11+ */
 12+if ( !defined( 'SG_VERSION' ) ) {
 13+ die( 'This file is part of the Semantic Glossary extension, it is not a valid entry point.' );
 14+}
 15+
 16+/**
 17+ * This class parses the given text and enriches it with definitions for defined
 18+ * terms.
 19+ *
 20+ * Contains a static function to initiate the parsing.
 21+ *
 22+ * @ingroup SemanticGlossary
 23+ */
 24+class SemanticGlossaryParser {
 25+
 26+ /**
 27+ *
 28+ * @param $parser
 29+ * @param $text
 30+ * @return Boolean
 31+ */
 32+ static function parse( &$parser, &$text ) {
 33+
 34+ $sl = new SemanticGlossaryParser();
 35+ $sl -> realParse( $parser, $text );
 36+
 37+ return true;
 38+ }
 39+
 40+ /**
 41+ * Returns the list of terms applicable in the current context
 42+ *
 43+ * @return Array an array mapping terms (keys) to descriptions (values)
 44+ */
 45+ function getGlossaryArray( SemanticGlossaryMessageLog &$messages = null ) {
 46+
 47+ global $smwgQDefaultNamespaces;
 48+
 49+ $store = smwfGetStore(); // default store
 50+
 51+ // Create query
 52+ $desc = new SMWSomeProperty(SMWPropertyValue::makeProperty( '___glt' ), new SMWThingDescription());
 53+ $desc -> addPrintRequest(new SMWPrintRequest( SMWPrintRequest::PRINT_PROP, null, SMWPropertyValue::makeProperty( '___glt' ) ));
 54+ $desc -> addPrintRequest(new SMWPrintRequest( SMWPrintRequest::PRINT_PROP, null, SMWPropertyValue::makeProperty( '___gld' ) ));
 55+
 56+ $query = new SMWQuery( $desc, true, false );
 57+ $query -> querymode = SMWQuery::MODE_INSTANCES;
 58+
 59+ global $smwgQDefaultLimit;
 60+ $query -> setLimit( $smwgQDefaultLimit );
 61+ $query -> sortkeys[ '___glt' ] = 'ASC';
 62+
 63+ // get the query result
 64+ $queryresult = $store -> getQueryResult( $query );
 65+
 66+ // assemble the result array
 67+ $result = array( );
 68+ while ( ( $resultline = $queryresult -> getNext() ) ) {
 69+
 70+ $term = $resultline[ 0 ] -> getNextText( SMW_OUTPUT_HTML );
 71+ $definition = $resultline[ 1 ] -> getNextText( SMW_OUTPUT_HTML );
 72+ $subject = $resultline[ 0 ] -> getResultSubject();
 73+
 74+ // FIXME: SMW has a bug that right after storing data this data
 75+ // might be available twice. The workaround here is to compare the
 76+ // first and second result and if they are identical assume that
 77+ // it is because of the bug. (2nd condition in the if below)
 78+
 79+ $nextTerm = $resultline[ 0 ] -> getNextText( SMW_OUTPUT_HTML );
 80+ $nextDefinition = $resultline[ 1 ] -> getNextText( SMW_OUTPUT_HTML );
 81+
 82+ // skip if more then one term or more than one definition present
 83+ if ( ( $nextTerm || $nextDefinition ) &&
 84+ !( $nextTerm == $term && $nextDefinition == $definition ) ) {
 85+
 86+ if ( $messages ) {
 87+ $messages -> addMessage(
 88+ wfMsg('semanticglossary-termdefinedtwice', array($subject -> getPrefixedText())),
 89+ SemanticGlossaryMessageLog::SG_WARNING );
 90+ }
 91+
 92+ continue;
 93+ }
 94+
 95+ $source = $subject -> getDBkeys();
 96+
 97+ if ( array_key_exists( $term, $result ) ) {
 98+ $result[ $term ] -> addDefinition( $definition, $source );
 99+ } else {
 100+ $result[ $term ] = new SemanticGlossaryElement( $term, $definition, $source );
 101+ }
 102+ }
 103+
 104+ return $result;
 105+ }
 106+
 107+ /**
 108+ * Parses the given text and enriches applicable terms
 109+ *
 110+ * This method currently only recognizes terms consisting of max one word
 111+ *
 112+ * @param $parser
 113+ * @param $text
 114+ * @return Boolean
 115+ */
 116+ protected function realParse( &$parser, &$text ) {
 117+
 118+ global $wgRequest, $sggSettings;
 119+
 120+ $action = $wgRequest -> getVal( 'action', 'view' );
 121+ if ( $text == null || $text == '' || $action == "edit" || $action == "ajax" || isset( $_POST[ 'wpPreview' ] ) )
 122+ return true;
 123+ // Get array of terms
 124+ $terms = $this -> getGlossaryArray();
 125+
 126+ if ( empty( $terms ) )
 127+ return true;
 128+
 129+ //Get the minimum length abbreviation so we don't bother checking against words shorter than that
 130+ $min = min( array_map( 'strlen', array_keys( $terms ) ) );
 131+
 132+// var_export($text);
 133+ //Parse HTML from page
 134+// $doc = new DOMDocument();
 135+//// @$doc -> loadHTML( '<html><meta http-equiv="content-type" content="charset=utf-8"/>' . $text . '</html>' );
 136+// $doc -> loadHTML( $text );
 137+
 138+ // this works in PHP 5.3.3. What about 5.1?
 139+ $doc = @DOMDocument::loadHTML($text);
 140+
 141+ //Find all text in HTML.
 142+ $xpath = new DOMXpath( $doc );
 143+ $elements = $xpath -> query( "//*[not(ancestor::*[@class='noglossary'])][text()!=' ']/text()" );
 144+
 145+ //Iterate all HTML text matches
 146+ $nb = $elements -> length;
 147+ $changed = false;
 148+
 149+ for ( $pos = 0; $pos < $nb; $pos++ ) {
 150+
 151+ $el = &$elements -> item( $pos );
 152+
 153+ if ( strlen( $el -> nodeValue ) < $min )
 154+ continue;
 155+
 156+ //Split node text into words, putting offset and text into $offsets[0] array
 157+// preg_match_all( "/\b[^\b\s\.,;:]+/", $el -> nodeValue, $offsets, PREG_OFFSET_CAPTURE );
 158+ preg_match_all( "/[^\s$sggSettings->punctuationCharacters]+/", $el -> nodeValue, $offsets, PREG_OFFSET_CAPTURE );
 159+
 160+ //Search and replace words in reverse order (from end of string backwards),
 161+ //This way we don't mess up the offsets of the words as we iterate
 162+ $len = count( $offsets[ 0 ] );
 163+
 164+ for ( $i = $len - 1; $i >= 0; $i-- ) {
 165+
 166+ $offset = $offsets[ 0 ][ $i ];
 167+
 168+ //Check if word is an abbreviation from the terminologies
 169+ if ( !is_numeric( $offset[ 0 ] ) && isset( $terms[ $offset[ 0 ] ] ) ) { //Word matches, replace with appropriate span tag
 170+ $changed = true;
 171+
 172+ $beforeMatchNode = $doc -> createTextNode( substr( $el -> nodeValue, 0, $offset[ 1 ] ) );
 173+ $afterMatchNode = $doc -> createTextNode( substr( $el -> nodeValue, $offset[ 1 ] + strlen( $offset[ 0 ] ), strlen( $el -> nodeValue ) - 1 ) );
 174+
 175+ //Wrap abbreviation in <span> tags
 176+ $span = @$doc -> createElement( 'span' );
 177+ $span -> setAttribute( 'class', "tooltip" );
 178+
 179+ //Wrap abbreviation in <span> tags, hidden
 180+ $spanAbr = @$doc -> createElement( 'span', $offset[ 0 ] );
 181+ $spanAbr -> setAttribute( 'class', "tooltip_abbr" );
 182+
 183+ //Wrap definition in <span> tags, hidden
 184+ $spanTip = $terms[ $offset[ 0 ] ] -> getFullDefinition( $doc );
 185+ $spanTip -> setAttribute( 'class', "tooltip_tip" );
 186+
 187+ $el -> parentNode -> insertBefore( $beforeMatchNode, $el );
 188+ $el -> parentNode -> insertBefore( $span, $el );
 189+ $span -> appendChild( $spanAbr );
 190+ $span -> appendChild( $spanTip );
 191+ $el -> parentNode -> insertBefore( $afterMatchNode, $el );
 192+ $el -> parentNode -> removeChild( $el );
 193+ $el = $beforeMatchNode; //Set new element to the text before the match for next iteration
 194+ }
 195+ }
 196+ }
 197+
 198+ if ( $changed ) {
 199+ $body = $xpath -> query( '/html/body' );
 200+ $text = $doc -> saveHTML();
 201+ $this -> loadModules( $parser );
 202+ }
 203+
 204+ return true;
 205+ }
 206+
 207+ protected function loadModules( &$parser ) {
 208+
 209+ global $wgOut, $wgScriptPath;
 210+
 211+ if ( defined( 'MW_SUPPORTS_RESOURCE_MODULES' ) ) {
 212+
 213+ if ( !is_null( $parser ) ) {
 214+ $parser -> getOutput() -> addModules( 'ext.SemanticGlossary' );
 215+ } else {
 216+ $wgOut -> addModules( 'ext.SemanticGlossary' );
 217+ }
 218+ } else {
 219+ if ( !is_null( $parser ) && ( $wgOut -> isArticle() ) ) {
 220+ $parser -> getOutput() -> addHeadItem( '<link rel="stylesheet" href="' . $wgScriptPath . '/extensions/SemanticGlossary/skins/SemanticGlossary.css" />', 'ext.SemanticGlossary.css' );
 221+ } else {
 222+ $wgOut -> addHeadItem( 'ext.SemanticGlossary.css', '<link rel="stylesheet" href="' . $wgScriptPath . '/extensions/SemanticGlossary/skins/SemanticGlossary.css" />' );
 223+ }
 224+ }
 225+ }
 226+
 227+}
Property changes on: trunk/extensions/SemanticLingo/SemanticGlossaryParser.php
___________________________________________________________________
Added: svn:eol-style
1228 + native
Index: trunk/extensions/SemanticLingo/SemanticGlossary.i18n.php
@@ -0,0 +1,69 @@
 2+<?php
 3+/**
 4+ * Language file for Semantic Glossary
 5+ */
 6+
 7+$messages = array();
 8+$specialPageAliases = array();
 9+
 10+/** English
 11+ * @author F.trott
 12+ */
 13+$messages['en'] = array(
 14+ 'semanticglossary-desc' => 'A terminology markup extension with a [http://semantic-mediawiki.org Semantic MediaWiki] backend',
 15+ 'semanticglossary-browsertitle' => 'Glossary',
 16+ 'semanticglossary-deleteselected' => 'Delete selected',
 17+ 'semanticglossary-savechanges' => 'Save changes',
 18+ 'semanticglossary-createnew' => 'Create new term',
 19+
 20+ 'semanticglossary-termsdefined' => 'These are the terms defined in the wiki:',
 21+ 'semanticglossary-notermsdefined' => 'There are currently no terms defined in the wiki.',
 22+ 'semanticglossary-enternewterm' => 'You can enter a new term and definition here:',
 23+
 24+ 'semanticglossary-messageheader' => 'Messages:',
 25+ 'semanticglossary-storedtermdefinedinarticle' => 'The term \'$1\' was originally defined in article [[$2]]. The definition was changed as required for now. However, as soon as the original article is edited again, the definition there takes precedence.',
 26+ 'semanticglossary-deletedtermdefinedinarticle' => 'The term \'$1\' was originally defined in article [[$2]]. The definition was deleted as required for now. However, as soon as the original article is edited again, the definition there takes precedence.',
 27+ 'semanticglossary-termdeleted' => 'Deleted $1.',
 28+ 'semanticglossary-storedtermdefinedtwice' => 'The article [[$1]] contains more than one property named $2. Will not store data for term \'$3\'.',
 29+ 'semanticglossary-termdefinedtwice' => 'The article [[$1]] contains more than one term and/or more than one definition. The entries will not be available for the glossary.',
 30+
 31+ 'semanticglossary-brokensession' => 'Action not allowed. Broken session data.',
 32+ 'semanticglossary-norights' => 'Action not allowed. Insufficient rights.',
 33+
 34+ '___glt' => 'Glossary-Term',
 35+ '___gld' => 'Glossary-Definition',
 36+
 37+);
 38+
 39+$specialPageAliases['en'] = array(
 40+ 'SemanticGlossaryBrowser' => array( 'Glossary' ),
 41+);
 42+
 43+/** Message documentation (Message documentation)
 44+ * @author F.trott
 45+ */
 46+$messages['qqq'] = array(
 47+ 'semanticglossary-desc' => '{{desc}}',
 48+);
 49+
 50+$messages['de'] = array(
 51+ 'semanticglossary-desc' => 'A terminology markup extension with a [http://semantic-mediawiki.org Semantic MediaWiki] backend',
 52+ 'semanticglossary-browsertitle' => 'Glossar',
 53+ 'semanticglossary-deleteselected' => 'Ausgewählte löschen',
 54+ 'semanticglossary-savechanges' => 'Änderungen speichern',
 55+ 'semanticglossary-createnew' => 'Neuen Term anlegen',
 56+
 57+ 'semanticglossary-termsdefined' => 'Diese Begriffe sind im Wiki definiert:',
 58+ 'semanticglossary-notermsdefined' => 'Es sind derzeit keine Begriffe im Wiki definiert.',
 59+ 'semanticglossary-enternewterm' => 'Du kannst hier einen neuen Term mit Definition eingeben:',
 60+
 61+ 'semanticglossary-messageheader' => 'Meldungen:',
 62+
 63+ '___glt' => 'Glossar-Term',
 64+ '___gld' => 'Glossar-Definition',
 65+);
 66+
 67+$specialPageAliases['de'] = array(
 68+ 'SemanticGlossaryBrowser' => array( 'Glossar' ),
 69+);
 70+
Property changes on: trunk/extensions/SemanticLingo/SemanticGlossary.i18n.php
___________________________________________________________________
Added: svn:eol-style
171 + native
Index: trunk/extensions/SemanticLingo/SemanticGlossary.php
@@ -0,0 +1,123 @@
 2+<?php
 3+
 4+/**
 5+ * A terminology markup extension with a Semantic MediaWiki backend
 6+ *
 7+ * @defgroup SemanticGlossary
 8+ * @author Stephan Gambke
 9+ * @version 0.1 alpha
 10+ */
 11+
 12+/**
 13+ * The main file of the SemanticGlossary extension
 14+ *
 15+ * @author Stephan Gambke
 16+ *
 17+ * @file
 18+ * @ingroup SemanticGlossary
 19+ */
 20+
 21+
 22+if ( !defined( 'MEDIAWIKI' ) ) {
 23+ die( 'This file is part of a MediaWiki extension, it is not a valid entry point.' );
 24+}
 25+
 26+if ( !defined( 'SMW_VERSION' ) ) {
 27+ die( 'Semantic Glossary depends on the Semantic MediaWiki extension. You need to install Semantic MediaWiki first.' );
 28+}
 29+
 30+/**
 31+ * The Semantic Glossary version
 32+ */
 33+define( 'SG_VERSION', '0.1 alpha' );
 34+
 35+
 36+// register the extension
 37+$wgExtensionCredits[ defined( 'SEMANTIC_EXTENSION_TYPE' ) ? 'semantic' : 'other' ][ ] = array(
 38+ 'path' => __FILE__,
 39+ 'name' => 'Semantic Glossary',
 40+ 'author' => array( '[http://www.mediawiki.org/wiki/User:F.trott Stephan Gambke]' ),
 41+ 'url' => 'http://www.mediawiki.org/wiki/Extension:Semantic_Glossary',
 42+ 'descriptionmsg' => 'semanticglossary-desc',
 43+ 'version' => SG_VERSION,
 44+);
 45+
 46+// server-local path to this file
 47+$dir = dirname( __FILE__ );
 48+
 49+
 50+// register message file
 51+$wgExtensionMessagesFiles[ 'SemanticGlossary' ] = $dir . '/SemanticGlossary.i18n.php';
 52+
 53+
 54+// register class files with the Autoloader
 55+$wgAutoloadClasses[ 'SemanticGlossarySettings' ] = $dir . '/SemanticGlossarySettings.php';
 56+$wgAutoloadClasses[ 'SemanticGlossaryParser' ] = $dir . '/SemanticGlossaryParser.php';
 57+$wgAutoloadClasses[ 'SemanticGlossaryElement' ] = $dir . '/SemanticGlossaryElement.php';
 58+$wgAutoloadClasses[ 'SemanticGlossaryMessageLog' ] = $dir . '/SemanticGlossaryMessageLog.php';
 59+$wgAutoloadClasses[ 'SpecialSemanticGlossaryBrowser' ] = $dir . '/SpecialSemanticGlossaryBrowser.php';
 60+
 61+
 62+// register Special pages
 63+$wgSpecialPages[ 'SemanticGlossaryBrowser' ] = 'SpecialSemanticGlossaryBrowser'; # Tell MediaWiki about the new special page and its class name
 64+$wgSpecialPageGroups[ 'SemanticGlossaryBrowser' ] = 'other';
 65+
 66+// register hook handlers
 67+//$wgHooks['ParserFirstCallInit'][] = 'SemanticGlossarySetup'; // Define a setup function
 68+$wgHooks[ 'ParserAfterTidy' ][ ] = array( 'SemanticGlossaryParser::parse' );
 69+
 70+
 71+$wgHooks[ 'smwInitProperties' ][] = 'SemanticGlossaryRegisterProperties';
 72+$wgHooks[ 'smwInitDatatypes'][] = 'SemanticGlossaryRegisterPropertyAliases';
 73+
 74+// register resource modules with the Resource Loader
 75+$wgResourceModules[ 'ext.SemanticGlossary' ] = array(
 76+ // JavaScript and CSS styles. To combine multiple file, just list them as an array.
 77+ //'scripts' => 'js/ext.myExtension.js',
 78+ 'styles' => 'css/SemanticGlossary.css',
 79+
 80+ // When your module is loaded, these messages will be available to mediaWiki.msg()
 81+ //'messages' => array( 'myextension-hello-world', 'myextension-goodbye-world' ),
 82+
 83+ // If your scripts need code from other modules, list their identifiers as dependencies
 84+ // and ResourceLoader will make sure they're loaded before you.
 85+ // You don't need to manually list 'mediawiki' or 'jquery', which are always loaded.
 86+ //'dependencies' => array( 'jquery.ui.datepicker' ),
 87+
 88+ // ResourceLoader needs to know where your files are; specify your
 89+ // subdir relative to "extensions" or $wgExtensionAssetsPath
 90+ 'localBasePath' => dirname( __FILE__ ),
 91+ 'remoteExtPath' => 'SemanticGlossary'
 92+);
 93+
 94+$wgResourceModules[ 'ext.SemanticGlossary.Browser' ] = array(
 95+ 'styles' => 'css/SemanticGlossaryBrowser.css',
 96+ 'localBasePath' => dirname( __FILE__ ),
 97+ 'remoteExtPath' => 'SemanticGlossary'
 98+);
 99+
 100+// Create new permission 'editglossary' and assign it to usergroup 'user' by default
 101+$wgGroupPermissions[ 'user' ][ 'editglossary' ] = true;
 102+
 103+// create and initialize settings object
 104+$sggSettings = new SemanticGlossarySettings();
 105+
 106+/**
 107+ * Handler for late setup of Semantic Glossary
 108+ */
 109+//function SemanticGlossarySetup () {
 110+//
 111+// return true;
 112+//}
 113+
 114+function SemanticGlossaryRegisterProperties () {
 115+ SMWPropertyValue::registerProperty( '___glt', '_str', false , true );
 116+ SMWPropertyValue::registerProperty( '___gld', '_txt', false , true );
 117+ return true;
 118+}
 119+
 120+function SemanticGlossaryRegisterPropertyAliases () {
 121+ SMWPropertyValue::registerPropertyAlias( '___glt', wfMsg( '___glt' ) );
 122+ SMWPropertyValue::registerPropertyAlias( '___gld', wfMsg( '___gld' ) );
 123+ return true;
 124+}
Property changes on: trunk/extensions/SemanticLingo/SemanticGlossary.php
___________________________________________________________________
Added: svn:eol-style
1125 + native
Index: trunk/extensions/SemanticLingo/SemanticGlossarySettings.php
@@ -0,0 +1,26 @@
 2+<?php
 3+
 4+/**
 5+ * File holding the default settings for the Semantic Glossary extension
 6+ *
 7+ * @author Stephan Gambke
 8+ *
 9+ * @file
 10+ * @ingroup SemanticGlossary
 11+ */
 12+if ( !defined( 'SG_VERSION' ) ) {
 13+ die( 'This file is part of the Semantic Glossary extension, it is not a valid entry point.' );
 14+}
 15+
 16+/**
 17+ * Class to encapsulate Semantic Glossary settings
 18+ * @ingroup SemanticGlossary
 19+ */
 20+class SemanticGlossarySettings {
 21+
 22+ /**
 23+ * @var Contains the characters that may not be part of a term.
 24+ */
 25+ public $punctuationCharacters = '\.(),;:?!';
 26+}
 27+
Property changes on: trunk/extensions/SemanticLingo/SemanticGlossarySettings.php
___________________________________________________________________
Added: svn:eol-style
128 + native

Follow-up revisions

RevisionCommit summaryAuthorDate
r85729followup r85719: separated messages and special page aliases to enable i18nfoxtrott17:51, 9 April 2011
r85737followup r85719: renamed some message identifiersfoxtrott20:16, 9 April 2011

Comments

#Comment by Siebrand (talk | contribs)   17:36, 9 April 2011

If you would like this extension to be supported in the Translate extension (and on translatewiki.net), please put the special page aliases in a separate file.

#Comment by F.trott (talk | contribs)   17:54, 9 April 2011

Done. Thanks for the tip! And just in case nobody ever told you: translatewiki.net is great! :)

#Comment by Siebrand (talk | contribs)   17:59, 9 April 2011

Thanks for the fix and the kudos. r85729 was incomplete, so I fixed that. Doing a quick review of the messages now, and will add support for the extension soonish.

#Comment by Siebrand (talk | contribs)   18:05, 9 April 2011
#Comment by F.trott (talk | contribs)   18:06, 9 April 2011

Cool, thanks!

#Comment by F.trott (talk | contribs)   18:00, 9 April 2011

Oops. Thanks!

#Comment by Siebrand (talk | contribs)   20:07, 9 April 2011

Would it be possible to change the keys that start with underscores? Not sure how MediaWiki proper responds to it, but at least the Translate extension does not like keys starting with underscores (as they are interpreted by MediaWiki as spaces).

+ '___glt' => 'Glossary-Term',

+ '___gld' => 'Glossary-Definition',

#Comment by F.trott (talk | contribs)   20:17, 9 April 2011

No problem. Done.

Status & tagging log