Index: trunk/extensions/SemanticExpressiveness/SemanticExpressiveness.php |
— | — | @@ -0,0 +1,193 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * 'Semantic Expressiveness' introduces a short hand query syntax to query single values from the |
| 6 | + * same or another page. It aims to further reduce redundancy and to make wikitext and query |
| 7 | + * outputs more expressive by adding information where queried values come from. |
| 8 | + * |
| 9 | + * Documentation: https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 10 | + * Support: https://www.mediawiki.org/wiki/Extension_talk:Semantic_Expressiveness |
| 11 | + * Source code: https://svn.wikimedia.org/viewvc/mediawiki/trunk/extensions/SemanticExpressiveness |
| 12 | + * |
| 13 | + * @version: 0.1 alpha |
| 14 | + * @license: ISC License |
| 15 | + * @author: Daniel Werner < danweetz@web.de > |
| 16 | + * |
| 17 | + * @file SemanticExpressiveness.php |
| 18 | + * @ingroup SemanticExpressiveness |
| 19 | + */ |
| 20 | + |
| 21 | +if( !defined( 'MEDIAWIKI' ) ) { die(); } |
| 22 | + |
| 23 | +$wgExtensionCredits[ defined( 'SEMANTIC_EXTENSION_TYPE' ) ? 'semantic' : 'other' ][] = array( |
| 24 | + 'path' => __FILE__, |
| 25 | + 'name' => 'Semantic Expressiveness', |
| 26 | + 'descriptionmsg' => 'semex-desc', |
| 27 | + 'version' => ExtSemEx::VERSION, |
| 28 | + 'author' => '[https://www.mediawiki.org/wiki/User:Danwe Daniel Werner]', |
| 29 | + 'url' => 'https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness', |
| 30 | +); |
| 31 | + |
| 32 | +$wgHooks['ParserFirstCallInit' ][] = 'ExtSemEx::init'; |
| 33 | + |
| 34 | +// language files: |
| 35 | +$wgExtensionMessagesFiles['SemEx' ] = ExtSemEx::getDir() . '/SemanticExpressiveness.i18n.php'; |
| 36 | +$wgExtensionMessagesFiles['SemExMagic'] = ExtSemEx::getDir() . '/SemanticExpressiveness.i18n.magic.php'; |
| 37 | + |
| 38 | +// resources inclusion: |
| 39 | +ExtSemEx::registerResourceModules(); |
| 40 | +$wgHooks['OutputPageParserOutput'][] = 'ExtSemEx::onOutputPageParserOutput'; |
| 41 | +$wgHooks['InternalParseBeforeSanitize'][] = 'ExtSemEx::onInternalParseBeforeSanitize'; |
| 42 | + |
| 43 | + |
| 44 | +$incDir = ExtSemEx::getDir() . '/includes/'; |
| 45 | + |
| 46 | +// general inclusions: |
| 47 | +$wgAutoloadClasses['SemExExpressiveString' ] = $incDir . 'SemExExpressiveString.php'; |
| 48 | +$wgAutoloadClasses['SemExExpressiveStringPiece' ] = $incDir . 'SemExExpressiveStringPiece.php'; |
| 49 | +$wgAutoloadClasses['SemExExpressiveStringPieceByRegex' ] = $incDir . 'SemExExpressiveStringPieceByRegex.php'; |
| 50 | +$wgAutoloadClasses['SemExExpressiveStringPieceSQ' ] = $incDir . 'SemExExpressiveStringPieceSQ.php'; |
| 51 | +$wgAutoloadClasses['SemExExpressiveStringPieceSQResult'] = $incDir . 'SemExExpressiveStringPieceSQResult.php'; |
| 52 | +$wgAutoloadClasses['SemExExpressiveStringPieceWikiLink'] = $incDir . 'SemExExpressiveStringPieceWikiLink.php'; |
| 53 | +$wgAutoloadClasses['SemExExpressiveStringOutputOptions'] = $incDir . 'SemExExpressiveStringOutputOptions.php'; |
| 54 | +$wgAutoloadClasses['SemExQueryPF' ] = $incDir . 'SemExQueryPF.php'; |
| 55 | +$wgAutoloadClasses['SemExShortQuery' ] = $incDir . 'SemExShortQuery.php'; |
| 56 | +$wgAutoloadClasses['SemExShortQueryProcessor' ] = $incDir . 'SemExShortQueryProcessor.php'; |
| 57 | +$wgAutoloadClasses['SemExShortQueryResult' ] = $incDir . 'SemExShortQueryResult.php'; |
| 58 | +$wgAutoloadClasses['SemExShortQueryAbstractResult' ] = $incDir . 'SemExShortQueryAbstractResult.php'; |
| 59 | +$wgAutoloadClasses['SemExShortQueryOutputOptions' ] = $incDir . 'SemExShortQueryOutputOptions.php'; |
| 60 | +$wgAutoloadClasses['SemExPFParamsBasedFactory' ] = $incDir . 'SemExPFParamsBasedFactory.php'; |
| 61 | + |
| 62 | +// validator stuff: |
| 63 | +$wgAutoloadClasses['SemExCriterionIsProperty' ] = $incDir . 'validation/SemExCriterionIsProperty.php'; |
| 64 | +$wgAutoloadClasses['SemExCriterionIsQuerySource' ] = $incDir . 'validation/SemExCriterionIsQuerySource.php'; |
| 65 | +$wgAutoloadClasses['SemExParamManipulationProperty' ] = $incDir . 'validation/SemExParamManipulationProperty.php'; |
| 66 | +$wgAutoloadClasses['SemExParamManipulationQuerySource'] = $incDir . 'validation/SemExParamManipulationQuerySource.php'; |
| 67 | + |
| 68 | +// Parser function initializations: |
| 69 | +$wgAutoloadClasses['SemExQueryPF' ] = $incDir . 'SemExQueryPF.php'; |
| 70 | +$wgAutoloadClasses['SemExExpressiveStringPF' ] = $incDir . 'SemExExpressiveStringPF.php'; |
| 71 | + |
| 72 | +$wgHooks['ParserFirstCallInit'][] = 'SemExExpressiveStringPF::staticInit'; |
| 73 | + |
| 74 | +unset( $incDir ); |
| 75 | + |
| 76 | + |
| 77 | +define( 'SEMEX_EXPR_PIECE_STRING', SemExExpressiveStringPiece::getType() ); |
| 78 | +define( 'SEMEX_EXPR_PIECE_SQRESULT', SemExExpressiveStringPieceSQResult::getType() ); |
| 79 | +define( 'SEMEX_EXPR_PIECE_SQ', SemExExpressiveStringPieceSQ::getType() ); |
| 80 | +define( 'SEMEX_EXPR_PIECE_WIKILINK', SemExExpressiveStringPieceWikiLink::getType() ); |
| 81 | + |
| 82 | + |
| 83 | +class ExtSemEx { |
| 84 | + |
| 85 | + const VERSION = '0.1 alpha'; |
| 86 | + |
| 87 | + static function init( &$parser ) { |
| 88 | + $parser->setFunctionHook( '?', array( 'SemExQueryPF', 'render' ), SFH_NO_HASH ); |
| 89 | + //$parser->setFunctionHook( '?!', array( 'SemExPlainQueryPF', 'render' ), SFH_NO_HASH ); |
| 90 | + $parser->setFunctionHook( '?to?!', __CLASS__ . '::parserFunc_QueryToPlainQuery', SFH_NO_HASH ); |
| 91 | + return true; |
| 92 | + } |
| 93 | + |
| 94 | + /** |
| 95 | + * Returns the extensions base installation directory. |
| 96 | + * @return string |
| 97 | + */ |
| 98 | + public static function getDir() { |
| 99 | + static $dir = null; |
| 100 | + if( $dir === null ) { |
| 101 | + $dir = dirname( __FILE__ ); |
| 102 | + } |
| 103 | + return $dir; |
| 104 | + } |
| 105 | + |
| 106 | + /** |
| 107 | + * Get the RPG-Dev-Tools installation directory path as seen from the web. |
| 108 | + * @return string |
| 109 | + */ |
| 110 | + public static function getScriptPath() { |
| 111 | + static $path = null; |
| 112 | + if( $path === null ) { |
| 113 | + global $wgVersion, $wgScriptPath, $wgExtensionAssetsPath; |
| 114 | + |
| 115 | + $dir = str_replace( '\\', '/', self::getDir() ); |
| 116 | + $dirName = substr( $dir, strrpos( $dir, '/' ) + 1 ); |
| 117 | + |
| 118 | + $path = ( |
| 119 | + ( version_compare( $wgVersion, '1.16', '>=' ) && isset( $wgExtensionAssetsPath ) && $wgExtensionAssetsPath ) |
| 120 | + ? $wgExtensionAssetsPath |
| 121 | + : $wgScriptPath . '/extensions' |
| 122 | + ) . "/$dirName"; |
| 123 | + } |
| 124 | + return $path; |
| 125 | + } |
| 126 | + |
| 127 | + /** |
| 128 | + * Registers JavaScript and CSS to ResourceLoader. |
| 129 | + */ |
| 130 | + public static function registerResourceModules() { |
| 131 | + global $wgResourceModules; |
| 132 | + |
| 133 | + $moduleTemplate = array( |
| 134 | + 'localBasePath' => self::getDir(), |
| 135 | + 'remoteBasePath' => self::getScriptPath(), |
| 136 | + 'group' => 'ext.semex' |
| 137 | + ); |
| 138 | + $wgResourceModules['ext.semex'] = $moduleTemplate + array( |
| 139 | + 'scripts' => array( |
| 140 | + 'resources/ext.semex.js', |
| 141 | + 'resources/ext.semex.ShortQueryResult.js', |
| 142 | + 'resources/ext.semex.ui.js', |
| 143 | + 'resources/ext.semex.ui.InlineMeasurer.js', |
| 144 | + 'resources/ext.semex.ui.ContextPopup.js', |
| 145 | + 'resources/ext.semex.ui.TitledContextPopup.js', |
| 146 | + 'resources/ext.semex.ui.ShortQueryHover.js', |
| 147 | + 'resources/ext.semex.ui.ShortQueryHover.Cache.js', |
| 148 | + 'resources/ext.semex.ui.ShortQueryHover.initialize.js', |
| 149 | + ), |
| 150 | + 'styles' => array( |
| 151 | + 'resources/ext.semex.css', |
| 152 | + 'resources/ext.semex.ui.ContextPopup.css', |
| 153 | + 'resources/ext.semex.ui.TitledContextPopup.css', |
| 154 | + 'resources/ext.semex.ui.ShortQueryHover.css', |
| 155 | + ), |
| 156 | + 'messages' => array( |
| 157 | + 'semex-shortquery-title', |
| 158 | + 'semex-shortquery-hover-loading', |
| 159 | + 'semex-shortquery-hover-loading-failed' |
| 160 | + ), |
| 161 | + ); |
| 162 | + } |
| 163 | + |
| 164 | + public static function onOutputPageParserOutput() { |
| 165 | + // load CSS and JavaScript |
| 166 | + // we can't add this just within SemExShortQueryResult since it's possible to get a |
| 167 | + // short query result from another page which is stored within a SMW property! |
| 168 | + global $wgOut; |
| 169 | + $wgOut->addModules( 'ext.semex' ); |
| 170 | + return true; |
| 171 | + } |
| 172 | + |
| 173 | + /* |
| 174 | + * NOTE: this hook requires the fix for bug #34678, https://bugzilla.wikimedia.org/show_bug.cgi?id=34678 |
| 175 | + */ |
| 176 | + public static function onInternalParseBeforeSanitize( Parser &$parser, &$text ) { |
| 177 | + $exprString = new SemExExpressiveString( $text, $parser, SEMEX_EXPR_PIECE_SQ ); |
| 178 | + $text = $exprString->getWikiText(); |
| 179 | + |
| 180 | + /* |
| 181 | + * Sanitize the whole thing, otherwise HTML and JS code injection would be possible. |
| 182 | + * Basically the same is happening in Parser::internalParse() right before 'InternalParseBeforeLinks' hook is called. |
| 183 | + */ |
| 184 | + /* |
| 185 | + $text = Sanitizer::removeHTMLtags( |
| 186 | + $text, |
| 187 | + array( &$parser, 'attributeStripCallback' ), |
| 188 | + false, |
| 189 | + array_keys( $parser->mTransparentTagHooks ) |
| 190 | + ); |
| 191 | + */ |
| 192 | + return true; |
| 193 | + } |
| 194 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/SemanticExpressiveness.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 195 | + native |
Index: trunk/extensions/SemanticExpressiveness/RELEASE-NOTES |
— | — | @@ -0,0 +1,15 @@ |
| 2 | + 'Semantic Expressiveness' Changelog:
|
| 3 | + =====================================
|
| 4 | +
|
| 5 | + * Version 0.1 alpha
|
| 6 | + ~~ THIS IS NOT A FINAL RELEASE YET ~~
|
| 7 | +
|
| 8 | + - Syntax for so called inline short queries, basically "<?property::page>" with a few advanced
|
| 9 | + syntactical features like nested "<?A::<?B::page>>" or "<?A::B::page>". This syntax is getting
|
| 10 | + parsed after template execution and fully respects nowiki, noincude, comments, pre and others.
|
| 11 | + - Parser function version of the new syntax called "?" with advanced parameters.
|
| 12 | + - Extensive JavaScript allowing to display information from a short queries source page like the
|
| 13 | + pages fact box or any other content. Might need some configuration for custom wiki adjustment.
|
| 14 | + - "?to?!" (might be renamed later) parser function allowing to parse the short query syntax early
|
| 15 | + to give template programmers full control.
|
| 16 | + - "SemExExpressiveString" class, extendable parser for the new syntax, also recognizes wikilinks. |
\ No newline at end of file |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPiece.php |
— | — | @@ -0,0 +1,290 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class representing one piece of a SemExExpressiveString. |
| 6 | + * |
| 7 | + * @since 0.1 |
| 8 | + * |
| 9 | + * @file SemExExpressiveStringPiece.php |
| 10 | + * @ingroup SemanticExpressiveness |
| 11 | + * |
| 12 | + * @author Daniel Werner < danweetz@web.de > |
| 13 | + */ |
| 14 | +class SemExExpressiveStringPiece { |
| 15 | + |
| 16 | + protected $value; |
| 17 | + |
| 18 | + /** |
| 19 | + * Constructor |
| 20 | + * |
| 21 | + * @param mixed $value |
| 22 | + */ |
| 23 | + function __construct( $value ) { |
| 24 | + $this->value = $value; |
| 25 | + } |
| 26 | + |
| 27 | + /** |
| 28 | + * Returns the value of this piece |
| 29 | + * |
| 30 | + * @return mixed depending on the pieces type |
| 31 | + */ |
| 32 | + public function getValue() { |
| 33 | + return $this->value; |
| 34 | + } |
| 35 | + |
| 36 | + /** |
| 37 | + * Returns the raw text value of this piece. Doesn't contain any expressive markup anymore, |
| 38 | + * just its textual representation. If there is no textual representation, this will return |
| 39 | + * an empty string even though the actual textual representation could be an empty string. |
| 40 | + * static::isUnresolvable() can be used to make sure whether any textual representation is |
| 41 | + * available. |
| 42 | + * |
| 43 | + * @return string |
| 44 | + */ |
| 45 | + public function getRawText() { |
| 46 | + return $this->value; |
| 47 | + } |
| 48 | + |
| 49 | + /** |
| 50 | + * Same as getRawText() but potentially with more expensive markup for wiki text usage. |
| 51 | + * |
| 52 | + * @return string |
| 53 | + */ |
| 54 | + public function getWikiText( |
| 55 | + $linked = SemExExpressiveStringOutputOptions::LINK_ALL, |
| 56 | + $showErrors = false |
| 57 | + ) { |
| 58 | + return $this->value; |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * Returns an abstract textual representation of this pieces meaning. If the type doesn't |
| 63 | + * support abstract representation, this will return the normal raw text. |
| 64 | + * |
| 65 | + * @return string |
| 66 | + */ |
| 67 | + public function getAbstractRawText() { |
| 68 | + return $this->getRawText(); |
| 69 | + } |
| 70 | + |
| 71 | + /** |
| 72 | + * Returns the abstract wiki text representation of this piece. If the type doesn't support |
| 73 | + * abstract representation, this will return the normal wiki text. |
| 74 | + * |
| 75 | + * @return string |
| 76 | + */ |
| 77 | + public function getAbstractWikiText( |
| 78 | + $linked = SemExExpressiveStringOutputOptions::LINK_ALL, |
| 79 | + $showErrors = false |
| 80 | + ) { |
| 81 | + return $this->getWikiText( $linked, $showErrors ); |
| 82 | + } |
| 83 | + |
| 84 | + /** |
| 85 | + * Returns the output of the piece in a form specified by a SemExExpressiveStringOutputOptions |
| 86 | + * object. |
| 87 | + * |
| 88 | + * @param SemExExpressiveStringOutputOptions $options |
| 89 | + * @return string |
| 90 | + */ |
| 91 | + public final function getOutput( SemExExpressiveStringOutputOptions $options ) { |
| 92 | + // make sure that the output options object contains all options which might be expected by |
| 93 | + // any overridden ancestor class function. |
| 94 | + $dfltOptions = $this->getDefaultOutputOptions(); |
| 95 | + |
| 96 | + if( get_class( $options ) !== get_class( $dfltOptions ) ) { |
| 97 | + $dfltOptions->mergeOptions( $options ); |
| 98 | + $options = $dfltOptions; |
| 99 | + } |
| 100 | + return $this->getOutputByOptions( $options ); |
| 101 | + } |
| 102 | + |
| 103 | + /** |
| 104 | + * This is the function handling getOutput() internally, receiving ab appropriate instance of |
| 105 | + * 'SemExExpressiveStringOutputOptions' or rather of the subclass describing all options for |
| 106 | + * the piece type. |
| 107 | + * It is datermined by getDefaultOutputOptions() which one would be the most suitable |
| 108 | + * 'SemExExpressiveStringOutputOptions' subclass for this type. |
| 109 | + * |
| 110 | + * @param SemExExpressiveStringOutputOptions $options |
| 111 | + * @return string |
| 112 | + */ |
| 113 | + protected function getOutputByOptions( SemExExpressiveStringOutputOptions $options ) { |
| 114 | + $useRaw = $options->getFormat() === SemExExpressiveStringOutputOptions::FORMAT_RAW; |
| 115 | + $linked = $options->getLink(); |
| 116 | + $errors = $options->getShowErrors(); |
| 117 | + |
| 118 | + if( $options->getShowAbstract() === SemExExpressiveStringOutputOptions::ABSTRACT_ONLY |
| 119 | + || $options->getShowAbstract() === SemExExpressiveStringOutputOptions::ABSTRACT_IF_FAILURE |
| 120 | + && $this->isUnresolvable() |
| 121 | + ) { |
| 122 | + if( $useRaw ) { |
| 123 | + return $this->getAbstractRawText(); |
| 124 | + } else { |
| 125 | + return $this->getAbstractWikiText( $linked, $errors ); |
| 126 | + } |
| 127 | + } else { |
| 128 | + if( $useRaw ) { |
| 129 | + return $this->getRawText(); |
| 130 | + } else { |
| 131 | + return $this->getWikiText( $linked, $errors ); |
| 132 | + } |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + /** |
| 137 | + * Returns true if the expressive meaning can't be resolved into a textual representation. |
| 138 | + * |
| 139 | + * @return bool |
| 140 | + */ |
| 141 | + public function isUnresolvable() { |
| 142 | + return false; |
| 143 | + } |
| 144 | + |
| 145 | + /** |
| 146 | + * Returns whether there have occurred errors of any kind. |
| 147 | + * |
| 148 | + * @return bool |
| 149 | + */ |
| 150 | + public function hasErrors() { |
| 151 | + $errors = $this->getErrors(); |
| 152 | + return !empty( $errors ); |
| 153 | + } |
| 154 | + |
| 155 | + /** |
| 156 | + * Returns all errors occurred so far |
| 157 | + * Note that this will return true if isUnresolvable() is true, even though this cann still |
| 158 | + * have an abstract representation instead. |
| 159 | + * |
| 160 | + * @return string[] |
| 161 | + */ |
| 162 | + public final function getErrors() { |
| 163 | + $errors = $this->getErrors_internal(); |
| 164 | + if( $this->isUnresolvable() ) { |
| 165 | + $errors = array_merge( array( 'semex-expressivestring-unresolvable' ), $errors ); |
| 166 | + } |
| 167 | + return $errors; |
| 168 | + } |
| 169 | + |
| 170 | + /** |
| 171 | + * Function to gather errors from the internal $value. Use this rather than overwriting getErrors() |
| 172 | + * |
| 173 | + * @return string[] |
| 174 | + */ |
| 175 | + protected function getErrors_internal() { |
| 176 | + return array(); |
| 177 | + } |
| 178 | + |
| 179 | + /** |
| 180 | + * Returns whether this piece type has a meaningful abstract representation. |
| 181 | + * |
| 182 | + * @return bool |
| 183 | + */ |
| 184 | + public static function hasAbstractRepresentation() { |
| 185 | + return false; |
| 186 | + } |
| 187 | + |
| 188 | + /** |
| 189 | + * Returns what kind of piece of an expressive string this is. |
| 190 | + * |
| 191 | + * @return string |
| 192 | + */ |
| 193 | + public static function getType() { |
| 194 | + return get_called_class(); |
| 195 | + } |
| 196 | + |
| 197 | + /** |
| 198 | + * Returns an instance of SemExExpressiveStringOutputOptions (or a descendant class engineered for |
| 199 | + * this specific piece type) which holds the default output options. |
| 200 | + * |
| 201 | + * @return SemExExpressiveStringOutputOptions |
| 202 | + */ |
| 203 | + public static function getDefaultOutputOptions() { |
| 204 | + return new SemExExpressiveStringOutputOptions(); |
| 205 | + } |
| 206 | + |
| 207 | + /** |
| 208 | + * Whether or not this piece has a expressive meaning, basically this is true if this is not a |
| 209 | + * simple string. |
| 210 | + * |
| 211 | + * @return bool |
| 212 | + */ |
| 213 | + public static function isExpressive() { |
| 214 | + // will return true for inherited classes but still allows them to overwrite. |
| 215 | + return ( static::getType() !== SEMEX_EXPR_PIECE_STRING ); |
| 216 | + } |
| 217 | + |
| 218 | + /** |
| 219 | + * This will initialize the piece type within a existing SemExExpressiveString object by examining |
| 220 | + * its non-expressive parts for expressive meaning. |
| 221 | + * |
| 222 | + * @param SemExExpressiveString $target |
| 223 | + */ |
| 224 | + public static function initWithin( SemExExpressiveString $target ) { |
| 225 | + if( ! static::isExpressive() ) { |
| 226 | + // unnecessary to examine a non-expressive meaning just to end up with the same! |
| 227 | + return; |
| 228 | + } |
| 229 | + $i = -1; |
| 230 | + foreach( $target->getPieces() as $piece ) { |
| 231 | + $i++; |
| 232 | + $newPieces = static::examinePiece( $piece, $target->getParser() ); |
| 233 | + if( $newPieces === false ) { |
| 234 | + // no meaning in this context |
| 235 | + continue; |
| 236 | + } |
| 237 | + |
| 238 | + // replace old piece with its new resolved meaning: |
| 239 | + $target->removePieces( $i, 1 ); |
| 240 | + $target->addPieces( $newPieces, $i ); |
| 241 | + |
| 242 | + $i += count( $newPieces ) - 1; |
| 243 | + } |
| 244 | + } |
| 245 | + |
| 246 | + /** |
| 247 | + * Examines a string or a SemExExpressiveStringPiece about whether it does match this piece type |
| 248 | + * and returns an array with this type of piece detected and non-expressive information as normal |
| 249 | + * SemExExpressiveStringPiece objects. Returns false if nothing detected. |
| 250 | + * |
| 251 | + * @param string|SemExExpressiveStringPiece $piece |
| 252 | + * @param Parser $parser |
| 253 | + * @return SemExExpressiveStringPiece[]|false |
| 254 | + */ |
| 255 | + public final static function examinePiece( $piece, Parser $parser ) { |
| 256 | + if( ! $piece->isExpressive() ) { |
| 257 | + $piece = $piece->getRawText(); |
| 258 | + } |
| 259 | + if( is_string( $piece ) ) { |
| 260 | + return static::examineString( $piece, $parser ); |
| 261 | + } |
| 262 | + |
| 263 | + return static::examineExpressivePiece( $piece, $parser ); |
| 264 | + } |
| 265 | + |
| 266 | + /** |
| 267 | + * Examines a string for expressive meaning matching this piece type and returns an array |
| 268 | + * with this type of piece detected and non-expressive information as normal |
| 269 | + * SemExExpressiveStringPiece objects. Returns false if nothing detected. |
| 270 | + * |
| 271 | + * @param string $string |
| 272 | + * @param Parser $parser |
| 273 | + * @return SemExExpressiveStringPiece[]|false |
| 274 | + */ |
| 275 | + protected static function examineString( $string, Parser $parser ) { |
| 276 | + return false; |
| 277 | + } |
| 278 | + |
| 279 | + /** |
| 280 | + * Examines an piece which already has its expressive meaning detected for further meaning |
| 281 | + * matching this type and returns an array of detected pieces. Returns false if nothing |
| 282 | + * detected. |
| 283 | + * |
| 284 | + * @param SemExExpressiveStringPiece $piece |
| 285 | + * @param Parser $parser |
| 286 | + * @return SemExExpressiveStringPiece[]|false |
| 287 | + */ |
| 288 | + protected static function examineExpressivePiece( SemExExpressiveStringPiece $piece, Parser $parser ) { |
| 289 | + return false; |
| 290 | + } |
| 291 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPiece.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 292 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExQueryPF.php |
— | — | @@ -0,0 +1,65 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class for '?' short query parser function |
| 6 | + * |
| 7 | + * @since 0.1 |
| 8 | + * |
| 9 | + * @file SemExQueryPF.php |
| 10 | + * @ingroup SemanticExpressiveness |
| 11 | + * |
| 12 | + * @author Daniel Werner < danweetz@web.de > |
| 13 | + */ |
| 14 | + |
| 15 | +class SemExQueryPF { |
| 16 | + |
| 17 | + public static function render( Parser &$parser ) { |
| 18 | + global $smwgQEnabled, $smwgIQRunningNumber; |
| 19 | + |
| 20 | + if ( $smwgQEnabled ) { |
| 21 | + $smwgIQRunningNumber++; |
| 22 | + |
| 23 | + $params = func_get_args(); |
| 24 | + array_shift( $params ); // remove $parser |
| 25 | + |
| 26 | + $query = SemExShortQuery::newFromPFParams( |
| 27 | + $params, |
| 28 | + array( 'property', Validator::PARAM_UNNAMED ) |
| 29 | + ); |
| 30 | + $options = SemExShortQueryOutputOptions::newFromPFParams( $params ); |
| 31 | + |
| 32 | + if( ! $query || ! $options ) { |
| 33 | + // @ToDo: real error message (anyway, in what case can this happen?) |
| 34 | + return 'FALSE'; |
| 35 | + } |
| 36 | + |
| 37 | + $result = SemExShortQueryProcessor::getResultFromQuery( $parser, $query, $options ); |
| 38 | + } else { |
| 39 | + $result = smwfEncodeMessages( array( wfMsgForContent( 'smw_iq_disabled' ) ) ); |
| 40 | + } |
| 41 | + |
| 42 | + return $result; |
| 43 | + } |
| 44 | + |
| 45 | + /** |
| 46 | + * Returns a description of all allowed function Parameters. |
| 47 | + * |
| 48 | + * @return array |
| 49 | + */ |
| 50 | + public static function getParameters() { |
| 51 | + $params = array(); |
| 52 | + |
| 53 | + $params['intro'] = new Parameter( 'intro' ); |
| 54 | + $params['outro'] = new Parameter( 'outro' ); |
| 55 | + $params['default'] = new Parameter( 'default' ); |
| 56 | + |
| 57 | + // add function parameters describing the querry and its options: |
| 58 | + $params = array_merge( |
| 59 | + $params, |
| 60 | + SemExShortQuery::getPFParams(), |
| 61 | + SemExShortQueryOutputOptions::getPFParams() |
| 62 | + ); |
| 63 | + |
| 64 | + return $params; |
| 65 | + } |
| 66 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExQueryPF.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 67 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPieceWikiLink.php |
— | — | @@ -0,0 +1,83 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class representing one piece of a SemExExpressiveString representing a wiki link. |
| 6 | + * This represents all kinds of wiki links, also category links and SMW property declarations. |
| 7 | + * This implementation is rather shallow and mainly serves to filter Links. |
| 8 | + * |
| 9 | + * @since 0.1 |
| 10 | + * |
| 11 | + * @file SemExExpressiveStringPiece.php |
| 12 | + * @ingroup SemanticExpressiveness |
| 13 | + * |
| 14 | + * @author Daniel Werner < danweetz@web.de > |
| 15 | + */ |
| 16 | +class SemExExpressiveStringPieceWikiLink extends SemExExpressiveStringPieceByRegex { |
| 17 | + |
| 18 | + // Search all kind of wiki links (including category and SMW) |
| 19 | + // $1: ":" if this is a normal link explicitly |
| 20 | + // $2: empty or source |
| 21 | + // $3: text and if $2 is empty also source |
| 22 | + protected static $regex = '\[\[ (:?) ( \s* (?=[^\[\]\|]*\|)[^\[\]\|]* \s* \| | )( [^\[\]]* ) \]\]'; |
| 23 | + protected static $regex_modifiers = 'x'; |
| 24 | + protected static $regex_essentials = array( true, true, true ); |
| 25 | + |
| 26 | + protected $isExplicitLink; |
| 27 | + protected $linkTarget; |
| 28 | + protected $linkText; |
| 29 | + |
| 30 | + function __construct( array $value ) { |
| 31 | + parent::__construct( $value ); |
| 32 | + |
| 33 | + $this->isExplicitLink = $value['explicit']; |
| 34 | + $this->linkTarget = $value['target']; |
| 35 | + $this->linkText = $value['text']; |
| 36 | + } |
| 37 | + |
| 38 | + /** |
| 39 | + * Returns the link in its raw form as wiki text. |
| 40 | + * |
| 41 | + * @return string |
| 42 | + */ |
| 43 | + public function getRawLink() { |
| 44 | + return '[[' . ( $this->isExplicitLink ? ':' : '' ) . $this->linkTarget . $this->linkText . ']]'; |
| 45 | + } |
| 46 | + |
| 47 | + public function getRawText() { |
| 48 | + return $this->linkText; |
| 49 | + } |
| 50 | + |
| 51 | + public function getWikiText( |
| 52 | + $linked = SemExExpressiveStringOutputOptions::LINK_ALL, |
| 53 | + $showErrors = false |
| 54 | + ) { |
| 55 | + if( $linked === SemExExpressiveStringOutputOptions::LINK_ALL ) { |
| 56 | + return $this->getRawLink(); |
| 57 | + } else { |
| 58 | + return $this->linkText; |
| 59 | + } |
| 60 | + } |
| 61 | + |
| 62 | + public function isUnresolvable() { |
| 63 | + return false; |
| 64 | + } |
| 65 | + |
| 66 | + public static function hasAbstractRepresentation() { |
| 67 | + return false; |
| 68 | + } |
| 69 | + |
| 70 | + protected static function examineRegexMatch( array $backRefs, Parser $parser ) { |
| 71 | + $result = array(); |
| 72 | + |
| 73 | + $result['explicit'] = $backRefs[1] === ':'; |
| 74 | + $result['text'] = $backRefs[3]; // can contain leading/trailing spaces |
| 75 | + $result['target'] = ( $backRefs[2] !== '' ) |
| 76 | + ? $backRefs[2] |
| 77 | + : trim( $result['text'] ); |
| 78 | + |
| 79 | + // Don't do further checks about whether this is a valid title since this could be |
| 80 | + // SMW property declaration syntax as well |
| 81 | + |
| 82 | + return new static( $result ); |
| 83 | + } |
| 84 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPieceWikiLink.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 85 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPieceSQResult.php |
— | — | @@ -0,0 +1,117 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class representing one short query result piece of a SemExExpressiveString. |
| 6 | + * Similar to SemExExpressiveStringPieceSQ with the difference that the initialization routines for |
| 7 | + * this type search for the result of an already queried short query within a string. |
| 8 | + * |
| 9 | + * @since 0.1 |
| 10 | + * |
| 11 | + * @file SemExExpressiveStringPieceSQResult.php |
| 12 | + * @ingroup SemanticExpressiveness |
| 13 | + * |
| 14 | + * @author Daniel Werner < danweetz@web.de > |
| 15 | + */ |
| 16 | +class SemExExpressiveStringPieceSQResult extends SemExExpressiveStringPieceByRegex { |
| 17 | + |
| 18 | + // [1] match <span> with 'shortQuery' class if we can make sure... |
| 19 | + // [2] ... no further <span>-pairs inside... |
| 20 | + // OR |
| 21 | + // [3] ... DOM inside only contains opening+closing <span>-pairs (ensured by recursive regex) |
| 22 | + protected static $regex = ' |
| 23 | + (?# COMMENT #1 ) |
| 24 | + <span \s+(?:[^>]*\s+|) class\s*=\s*(?P<q>[\'"])(?:[^>\k<q>]*\s+|\s*) shortQuery (?:[^>\k<q>]*\s+|\s*)\k<q>[^>]*> |
| 25 | + |
| 26 | + (?# COMMENT #2 ) |
| 27 | + ( (?>(?!<span(?:\s+[^>]*|)>|<\/span>).)* |
| 28 | + |
| 29 | + (?# COMMENT #3 ) |
| 30 | + | (?P<innerDOM> <span(?:\s+[^>]*|)>(?: (?>(?!<span(?:\s+[^>]*|)>|<\/span>).)* | (?&innerDOM) )*?<\/span> )* |
| 31 | + )* <\/span>'; |
| 32 | + |
| 33 | + protected static $regex_modifiers = 'sx'; |
| 34 | + protected static $regex_essentials = array( false, false ); |
| 35 | + |
| 36 | + /** |
| 37 | + * @var SemExShortQueryResult |
| 38 | + */ |
| 39 | + protected $value; |
| 40 | + |
| 41 | + function __construct( SemExShortQueryResult $value ) { |
| 42 | + parent::__construct( $value ); |
| 43 | + } |
| 44 | + |
| 45 | + public function getRawText() { |
| 46 | + return $this->value->getRawText(); |
| 47 | + } |
| 48 | + |
| 49 | + public function getWikiText( |
| 50 | + $linked = SemExExpressiveStringOutputOptions::LINK_ALL, |
| 51 | + $showErrors = false |
| 52 | + ) { |
| 53 | + return $this->value->getWikiText( $linked, $showErrors ); |
| 54 | + } |
| 55 | + |
| 56 | + public function getAbstractRawText() { |
| 57 | + return $this->value->getAbstractResult()->getRawText(); |
| 58 | + } |
| 59 | + |
| 60 | + public function getAbstractWikiText( |
| 61 | + $linked = SemExExpressiveStringOutputOptions::LINK_ALL, |
| 62 | + $showErrors = false |
| 63 | + ) { |
| 64 | + return $this->value->getAbstractResult()->getWikiText( $linked, $showErrors ); |
| 65 | + } |
| 66 | + |
| 67 | + public static function hasAbstractRepresentation() { |
| 68 | + return true; |
| 69 | + } |
| 70 | + |
| 71 | + public function isUnresolvable() { |
| 72 | + return $this->value->isEmpty(); |
| 73 | + } |
| 74 | + |
| 75 | + protected function getErrors_internal() { |
| 76 | + return $this->value->getErrors(); |
| 77 | + } |
| 78 | + |
| 79 | + protected function getOutputByOptions( SemExExpressiveStringOutputOptions $options ) { |
| 80 | + return $this->value->getOutput( $options ); |
| 81 | + } |
| 82 | + |
| 83 | + /** |
| 84 | + * @return SemExShortQueryOutputOptions |
| 85 | + */ |
| 86 | + public static function getDefaultOutputOptions() { |
| 87 | + return new SemExShortQueryOutputOptions(); |
| 88 | + } |
| 89 | + |
| 90 | + protected static function examineRegexMatch( array $backRefs, Parser $parser ) { |
| 91 | + /* |
| 92 | + $part = str_replace( ' ', ' ', $part ); |
| 93 | + $part = str_replace( ' ', ' ', $part ); |
| 94 | + $part = str_replace( ' ', ' ', $part ); |
| 95 | + */ |
| 96 | + $xmlDoc = new DOMDocument(); |
| 97 | + $xmlDoc->strictErrorChecking = false; |
| 98 | + |
| 99 | + wfSuppressWarnings(); |
| 100 | + $validDom = $xmlDoc->loadXML( $backRefs[0] ); |
| 101 | + wfRestoreWarnings(); |
| 102 | + |
| 103 | + if( ! $validDom ) { |
| 104 | + // no well-formed xml, insert as plain string |
| 105 | + return false; |
| 106 | + } |
| 107 | + |
| 108 | + try { |
| 109 | + // try to re-fabricate short query result from DOM: |
| 110 | + $sqResult = SemExShortQueryResult::newFromDOM( $xmlDoc->documentElement, $parser ); |
| 111 | + } catch( Exception $exc ) { |
| 112 | + // invalid, insert as plain string |
| 113 | + return false; |
| 114 | + } |
| 115 | + |
| 116 | + return new static( $sqResult ); |
| 117 | + } |
| 118 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPieceSQResult.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 119 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPieceSQ.php |
— | — | @@ -0,0 +1,119 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class representing one short query (sq) piece of a SemExExpressiveString. |
| 6 | + * Similar to SemExExpressiveStringPieceSQResult with the difference that this piece represents a |
| 7 | + * syntax for short to be executed instead of their actual results. |
| 8 | + * |
| 9 | + * Basically, this is the parser for the "<?property::page>" syntax which gets more complicated with |
| 10 | + * advanced nested variations "<?a::b::c::d::e>" or "<?a::b::<?c::<?d::e>>>". |
| 11 | + * |
| 12 | + * @since 0.1 |
| 13 | + * |
| 14 | + * @file SemExExpressiveStringPieceSQ.php |
| 15 | + * @ingroup SemanticExpressiveness |
| 16 | + * |
| 17 | + * @author Daniel Werner < danweetz@web.de > |
| 18 | + */ |
| 19 | +class SemExExpressiveStringPieceSQ extends SemExExpressiveStringPieceSQResult { |
| 20 | + |
| 21 | + /* using: |
| 22 | + * $origLimit = ini_set( 'pcre.recursion_limit', 8 ); |
| 23 | + * to enforce hard limit for nested syntax for this regex doesn't work. The whole regex will fail |
| 24 | + */ |
| 25 | + protected static $regex = '<\?!?\s* [^<\|>]{1,64}? (?:\s*::\s*:?\s* (?>[^<>]{0,32}(?R)?){1,4})? \s*>'; |
| 26 | + protected static $regex_modifiers = 'x'; |
| 27 | + protected static $regex_essentials = array(); |
| 28 | + |
| 29 | + |
| 30 | + protected static function examineRegexMatch( array $backRefs, Parser $parser ) { |
| 31 | + // handle one single short query of the whole sentence |
| 32 | + // split it into its compontents: |
| 33 | + preg_match( |
| 34 | + '/^<(\?!|\?)\s* ([^<\|>)]+?) (?:\s*::\s* (:?) \s* (.*?) )? \s*>$/x', |
| 35 | + $backRefs[0], $matches |
| 36 | + ); |
| 37 | + $matches += array( 3 => false, 4 => false ); |
| 38 | + $isPlain = ( $matches[1] == '?!' ); |
| 39 | + $pageSrcExplicit = ( $matches[3] == ':' ); |
| 40 | + |
| 41 | + $property = SMWPropertyValue::makeUserProperty( $matches[2] ); |
| 42 | + |
| 43 | + $source = $matches[4]; |
| 44 | + if( $source === false ) { |
| 45 | + $source = null; // source is current page |
| 46 | + } |
| 47 | + else { |
| 48 | + // (recursivelly) examine the source for further short query syntax within: |
| 49 | + $source = new SemExExpressiveString( $source, $parser, static::getType() ); |
| 50 | + $source = static::resolveDeepOneLinerNotation( $source ); |
| 51 | + |
| 52 | + if( $source === false ) { |
| 53 | + // source is invalid in some way |
| 54 | + return false; |
| 55 | + } |
| 56 | + } |
| 57 | + |
| 58 | + // set the source of the query to a Title or another expressive string which |
| 59 | + // can contain several short queries all over again |
| 60 | + $query = new SemExShortQuery( $property, $source ); |
| 61 | + return new static( |
| 62 | + new SemExShortQueryResult( $query, $parser ) |
| 63 | + ); |
| 64 | + } |
| 65 | + |
| 66 | + /** |
| 67 | + * Helper function to resolve short query notation like "<?a::b::c::d::e>". |
| 68 | + * Note: "e" could also be another short query like "<?a::b::c::<?d::e>>", the parts before on |
| 69 | + * the other hand are all properties which do not support a short query or expressive string |
| 70 | + * source at the time. |
| 71 | + * |
| 72 | + * @param SemExExpressiveString $eSrc |
| 73 | + * @return Title|SemExExpressiveString|false |
| 74 | + */ |
| 75 | + protected static function resolveDeepOneLinerNotation( SemExExpressiveString $eSrc ) { |
| 76 | + if( $eSrc->getPiece( 0 )->isExpressive() ) { |
| 77 | + // whole meaning examined already and behind an expressive there can't be any "::" as |
| 78 | + // separator between property and source unless we'd allow expressive property sources. |
| 79 | + return $eSrc; |
| 80 | + } |
| 81 | + |
| 82 | + /* |
| 83 | + * $eSrc only has one piece OR the next piece must be expressive. There could be further |
| 84 | + * string pieces after the expressive one, but in that case they are part of the last part |
| 85 | + */ |
| 86 | + $sources = preg_split( |
| 87 | + '/\s*::\s*/', |
| 88 | + $eSrc->getPiece( 0 )->getRawText() |
| 89 | + ); |
| 90 | + $eSrc->removePieces( 0 ); |
| 91 | + |
| 92 | + // part behind last "::" is part of final source |
| 93 | + $eSrc->addString( array_pop( $sources ), 0 ); |
| 94 | + |
| 95 | + if( ! $eSrc->hasExpressiveness() ) { |
| 96 | + $eSrc = Title::newFromText( $eSrc->getRawText() ); |
| 97 | + if( $eSrc === null ) { |
| 98 | + return false; |
| 99 | + } |
| 100 | + } |
| 101 | + |
| 102 | + if( empty( $sources ) ) { |
| 103 | + // no further "::" separations or expressiveness |
| 104 | + return $eSrc; |
| 105 | + } |
| 106 | + |
| 107 | + $lastSrc = $eSrc; |
| 108 | + $sources = array_reverse( $sources ); //last item first |
| 109 | + |
| 110 | + foreach( $sources as $property ) { |
| 111 | + $property = SMWPropertyValue::makeUserProperty( $property ); |
| 112 | + if( ! $property->isValid() ) { |
| 113 | + return false; |
| 114 | + } |
| 115 | + $lastSrc = new SemExShortQuery( $property, $lastSrc ); |
| 116 | + } |
| 117 | + |
| 118 | + return $lastSrc; |
| 119 | + } |
| 120 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPieceSQ.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 121 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExPFParamsBasedFactory.php |
— | — | @@ -0,0 +1,119 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Interface for classes offering a factory method for creating a new instance from parser function |
| 6 | + * parameters. |
| 7 | + * |
| 8 | + * @since 0.1 |
| 9 | + * |
| 10 | + * @file SemExPFParamsBasedFactory.php |
| 11 | + * @ingroup SemanticExpressiveness |
| 12 | + * |
| 13 | + * @author Daniel Werner < danweetz@web.de > |
| 14 | + */ |
| 15 | +abstract class SemExPFParamsBasedFactory { |
| 16 | + |
| 17 | + protected static $pfParamsValidatorElement; |
| 18 | + |
| 19 | + /** |
| 20 | + * Fabricates a new instance by a set of parser function parameters. |
| 21 | + * If the given parameters were insufficient, false will be returned. Validation errors can be |
| 22 | + * accessed by the $validator parameter. |
| 23 | + * |
| 24 | + * @param array $params raw parameters as given by a parser function |
| 25 | + * @param array $defaultParams see Validator::setFunctionParams() $defaultParams parameter. |
| 26 | + * @param null $validator |
| 27 | + * @param bool $unknownInvalid |
| 28 | + * @return __CLASS__|false |
| 29 | + */ |
| 30 | + public static function newFromPFParams( |
| 31 | + array $params, |
| 32 | + array $defaultParams = array(), |
| 33 | + &$validator = null, |
| 34 | + $unknownInvalid = false |
| 35 | + ) { |
| 36 | + $params = static::getValidatedPFParams( $params, $defaultParams, $validator, $unknownInvalid, true ); |
| 37 | + |
| 38 | + if( $validator->hasFatalError() ) { |
| 39 | + return false; |
| 40 | + } |
| 41 | + return static::newFromValidatedParams( $params, $validator ); |
| 42 | + } |
| 43 | + |
| 44 | + /** |
| 45 | + * Same as newFromPFParams() except that the $params array has to have the parameter names set |
| 46 | + * as key values. |
| 47 | + * If the given parameters were insufficient, false will be returned. Validation errors can be |
| 48 | + * accessed by the $validator parameter. |
| 49 | + * |
| 50 | + * @param array $params raw parameters as values, parameter names as keys |
| 51 | + * @param type $validator |
| 52 | + * @param type $unknownInvalid |
| 53 | + * @return __CLASS__ |
| 54 | + */ |
| 55 | + public static function newFromParamsArray( |
| 56 | + array $params, |
| 57 | + &$validator = null, |
| 58 | + $unknownInvalid = false |
| 59 | + ) { |
| 60 | + $params = static::getValidatedPFParams( $params, array(), $validator, $unknownInvalid, false ); |
| 61 | + |
| 62 | + if( $validator->hasFatalError() ) { |
| 63 | + return false; |
| 64 | + } |
| 65 | + return static::newFromValidatedParams( $params, $validator ); |
| 66 | + } |
| 67 | + |
| 68 | + /** |
| 69 | + * This should be overwritten by classes inheriting this one to fabricate a new instance by a set |
| 70 | + * of parameters. |
| 71 | + * |
| 72 | + * @param array $params |
| 73 | + * @return __CLASS__ |
| 74 | + */ |
| 75 | + public static function newFromValidatedParams( array $params ) { |
| 76 | + return null; |
| 77 | + } |
| 78 | + |
| 79 | + /** |
| 80 | + * Returns the validated parser function parameters by a given set of unprocessed parameters. |
| 81 | + * |
| 82 | + * @param array $params |
| 83 | + * @param array $defaultParams see Validator::setFunctionParams() $defaultParams parameter. |
| 84 | + * this has no effect if $pfStyle is set to false. |
| 85 | + * @param null &$validator allows to get the Validator object used to validate the parameters. |
| 86 | + * @param bool $unknownInvalid |
| 87 | + * @param bool $pfParamsStyle if true this will not expect $params to have parameter keys as |
| 88 | + * name, instead the names will be extracted from the values. |
| 89 | + * |
| 90 | + * @return array |
| 91 | + */ |
| 92 | + public static function getValidatedPFParams( |
| 93 | + array $params, |
| 94 | + array $defaultParams = array(), |
| 95 | + &$validator = null, |
| 96 | + $unknownInvalid = false, |
| 97 | + $pfParamsStyle = true |
| 98 | + ) { |
| 99 | + $validator = new Validator( static::$pfParamsValidatorElement, $unknownInvalid ); |
| 100 | + |
| 101 | + if( $pfParamsStyle ) { |
| 102 | + $validator->setFunctionParams( $params, static::getPFParams(), $defaultParams ); |
| 103 | + } else { |
| 104 | + $validator->setParameters( $params, static::getPFParams() ); |
| 105 | + } |
| 106 | + |
| 107 | + $validator->validateParameters(); |
| 108 | + |
| 109 | + return $validator->getParameterValues(); |
| 110 | + } |
| 111 | + |
| 112 | + /** |
| 113 | + * Returns a description of all allowed function Parameters representing this class. |
| 114 | + * |
| 115 | + * @return array |
| 116 | + */ |
| 117 | + public static function getPFParams() { |
| 118 | + return array(); |
| 119 | + } |
| 120 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExPFParamsBasedFactory.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 121 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/validation/SemExParamManipulationQuerySource.php |
— | — | @@ -0,0 +1,40 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | +* Parameter manipulation converting the value to a SMWStore listed within the global |
| 6 | + * $smwgQuerySources config variable. |
| 7 | + * |
| 8 | + * @since 0.1 |
| 9 | + * |
| 10 | + * @file SemExShortQueryResult.php |
| 11 | + * @ingroup SemanticExpressiveness |
| 12 | + * @ingroup ParameterManipulations |
| 13 | + * |
| 14 | + * @author Daniel Werner < danweetz@web.de > |
| 15 | + */ |
| 16 | +class SemExParamManipulationQuerySource extends ItemParameterManipulation { |
| 17 | + |
| 18 | + /** |
| 19 | + * Constructor. |
| 20 | + * |
| 21 | + * @since 0.4.14 |
| 22 | + */ |
| 23 | + public function __construct() { |
| 24 | + parent::__construct(); |
| 25 | + } |
| 26 | + |
| 27 | + /** |
| 28 | + * @see ItemParameterManipulation::doManipulation |
| 29 | + */ |
| 30 | + public function doManipulation( &$value, Parameter $parameter, array &$parameters ) { |
| 31 | + global $smwgQuerySources; |
| 32 | + |
| 33 | + // get specific store or take default: |
| 34 | + if( array_key_exists( $value, $smwgQuerySources ) ) { |
| 35 | + $value = new $smwgQuerySources[ $value ](); |
| 36 | + } else { |
| 37 | + $value = smwfGetStore(); // take default |
| 38 | + } |
| 39 | + } |
| 40 | + |
| 41 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/validation/SemExParamManipulationQuerySource.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 42 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/validation/SemExCriterionIsProperty.php |
— | — | @@ -0,0 +1,65 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Parameter criterion for 'Validator' stating that the value must be a SMW property. |
| 6 | + * Optionally this will only allow properties of certain types. |
| 7 | + * |
| 8 | + * @since 0.1 |
| 9 | + * |
| 10 | + * @file SemExShortQueryResult.php |
| 11 | + * @ingroup SemanticExpressiveness |
| 12 | + * @ingroup Criteria |
| 13 | + * |
| 14 | + * @author Daniel Werner < danweetz@web.de > |
| 15 | + */ |
| 16 | +class SemExCriterionIsProperty extends ItemParameterCriterion { |
| 17 | + |
| 18 | + protected $allowedTypes; |
| 19 | + |
| 20 | + /** |
| 21 | + * Constructor. |
| 22 | + * |
| 23 | + * @param $allowedTypes string|string[] will only aprove of the property if its type id matches |
| 24 | + * one of the given type ids. For example '_wpg' for properties of type page. |
| 25 | + * |
| 26 | + * @since 0.1 |
| 27 | + */ |
| 28 | + public function __construct( $allowedTypes = null ) { |
| 29 | + if( $allowedTypes !== null && !is_array( $allowedTypes ) ) { |
| 30 | + $allowedTypes = array( $allowedTypes ); |
| 31 | + } |
| 32 | + $this->allowedTypes = $allowedTypes; |
| 33 | + parent::__construct(); |
| 34 | + } |
| 35 | + |
| 36 | + /** |
| 37 | + * @see ItemParameterCriterion::validate |
| 38 | + */ |
| 39 | + protected function doValidation( $value, Parameter $parameter, array $parameters ) { |
| 40 | + // create SMW property from user input: |
| 41 | + $prop = SMWPropertyValue::makeUserProperty( $value ); |
| 42 | + |
| 43 | + if( $this->allowedTypes !== null ) { |
| 44 | + // filter unallowed types for this validation: |
| 45 | + $type = $prop->getPropertyTypeID(); |
| 46 | + if( ! in_array( $type, $this->allowedTypes ) ) { |
| 47 | + return false; |
| 48 | + } |
| 49 | + } |
| 50 | + return $prop->isValid(); |
| 51 | + } |
| 52 | + |
| 53 | + /** |
| 54 | + * @see ItemParameterCriterion::getItemErrorMessage |
| 55 | + */ |
| 56 | + protected function getItemErrorMessage( Parameter $parameter ) { |
| 57 | + return ''; |
| 58 | + } |
| 59 | + |
| 60 | + /** |
| 61 | + * @see ItemParameterCriterion::getFullListErrorMessage |
| 62 | + */ |
| 63 | + protected function getFullListErrorMessage( Parameter $parameter ) { |
| 64 | + return ''; |
| 65 | + } |
| 66 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/validation/SemExCriterionIsProperty.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 67 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/validation/SemExCriterionIsQuerySource.php |
— | — | @@ -0,0 +1,47 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Parameter criterion for 'Validator' stating that the value must be the key of a registered |
| 6 | + * SMWDataStore instance. |
| 7 | + * |
| 8 | + * @since 0.1 |
| 9 | + * |
| 10 | + * @file SemExShortQueryResult.php |
| 11 | + * @ingroup SemanticExpressiveness |
| 12 | + * @ingroup Criteria |
| 13 | + * |
| 14 | + * @author Daniel Werner < danweetz@web.de > |
| 15 | + */ |
| 16 | +class SemExCriterionIsQuerySource extends ItemParameterCriterion { |
| 17 | + |
| 18 | + /** |
| 19 | + * Constructor. |
| 20 | + * |
| 21 | + * @since 0.1 |
| 22 | + */ |
| 23 | + public function __construct() { |
| 24 | + parent::__construct(); |
| 25 | + } |
| 26 | + |
| 27 | + /** |
| 28 | + * @see ItemParameterCriterion::validate |
| 29 | + */ |
| 30 | + protected function doValidation( $value, Parameter $parameter, array $parameters ) { |
| 31 | + global $smwgQuerySources; |
| 32 | + return array_key_exists( $value, $smwgQuerySources ); |
| 33 | + } |
| 34 | + |
| 35 | + /** |
| 36 | + * @see ItemParameterCriterion::getItemErrorMessage |
| 37 | + */ |
| 38 | + protected function getItemErrorMessage( Parameter $parameter ) { |
| 39 | + return ''; |
| 40 | + } |
| 41 | + |
| 42 | + /** |
| 43 | + * @see ItemParameterCriterion::getFullListErrorMessage |
| 44 | + */ |
| 45 | + protected function getFullListErrorMessage( Parameter $parameter ) { |
| 46 | + return ''; |
| 47 | + } |
| 48 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/validation/SemExCriterionIsQuerySource.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 49 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/validation/SemExParamManipulationProperty.php |
— | — | @@ -0,0 +1,32 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | +* Parameter manipulation converting the value to a SMWPropertyValue. |
| 6 | + * |
| 7 | + * @since 0.1 |
| 8 | + * |
| 9 | + * @file SemExShortQueryResult.php |
| 10 | + * @ingroup SemanticExpressiveness |
| 11 | + * @ingroup ParameterManipulations |
| 12 | + * |
| 13 | + * @author Daniel Werner < danweetz@web.de > |
| 14 | + */ |
| 15 | +class SemExParamManipulationProperty extends ItemParameterManipulation { |
| 16 | + |
| 17 | + /** |
| 18 | + * Constructor. |
| 19 | + * |
| 20 | + * @since 0.4.14 |
| 21 | + */ |
| 22 | + public function __construct() { |
| 23 | + parent::__construct(); |
| 24 | + } |
| 25 | + |
| 26 | + /** |
| 27 | + * @see ItemParameterManipulation::doManipulation |
| 28 | + */ |
| 29 | + public function doManipulation( &$value, Parameter $parameter, array &$parameters ) { |
| 30 | + $value = SMWPropertyValue::makeUserProperty( $value ); |
| 31 | + } |
| 32 | + |
| 33 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/validation/SemExParamManipulationProperty.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 34 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExShortQueryAbstractResult.php |
— | — | @@ -0,0 +1,176 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class representing the result of a 'Semantic Expressiveness' short query as abstract value. |
| 6 | + * |
| 7 | + * @since 0.1 |
| 8 | + * |
| 9 | + * @file SemExShortQueryAbstractResult.php |
| 10 | + * @ingroup SemanticExpressiveness |
| 11 | + * |
| 12 | + * @author Daniel Werner < danweetz@web.de > |
| 13 | + */ |
| 14 | +class SemExShortQueryAbstractResult extends SemExShortQueryResult { |
| 15 | + |
| 16 | + public function getAbstractResult() { |
| 17 | + // this is the abstract result already |
| 18 | + return $this; |
| 19 | + } |
| 20 | + |
| 21 | + /** |
| 22 | + * Returns an abstract representation of the result which expresses what exactly the query is all |
| 23 | + * about. Does some extra formatting for pretty wiki text compared to getAbstractRawText(). If all |
| 24 | + * the short query classes and outer wrapping for the context popup functionality is needed, use |
| 25 | + * getWikiText() instead. |
| 26 | + * |
| 27 | + * @param mixed $linked Allows one of |
| 28 | + * SemExShortQueryOutputOptions::LINK_NONE |
| 29 | + * SemExShortQueryOutputOptions::LINK_ALL |
| 30 | + * SemExShortQueryOutputOptions::LINK_TOPIC |
| 31 | + * @param bool $showErrors can be set to true to show errors. Off by default. |
| 32 | + * |
| 33 | + * @return string |
| 34 | + */ |
| 35 | + public function getShortWikiText( |
| 36 | + $linked = SemExShortQueryOutputOptions::LINK_ALL, |
| 37 | + $showErrors = false |
| 38 | + ) { |
| 39 | + $parts = $this->getAbstractParts( false, $linked === SemExShortQueryOutputOptions::LINK_ALL ); |
| 40 | + $source = $parts['source']; |
| 41 | + $fromRef = $parts['fromref']; |
| 42 | + $property = $parts['property']; |
| 43 | + |
| 44 | + $out = |
| 45 | + '<b><</b>' . |
| 46 | + $this->buildAbstractText( $property, $source, $fromRef ) . |
| 47 | + '<b>></b>'; |
| 48 | + |
| 49 | + $out = "<span class=\"abstractShortQueryValue\">$out</span>"; |
| 50 | + |
| 51 | + if( $linked === SemExShortQueryOutputOptions::LINK_TOPIC ) { |
| 52 | + // wrap whole result in one link to the source |
| 53 | + $topic = $this->getSource(); |
| 54 | + $out = "[[:{$topic}|{$out}]]"; |
| 55 | + } |
| 56 | + |
| 57 | + if( $showErrors ) { |
| 58 | + // don't get any error about the queries general success, just about invalid input |
| 59 | + $out .= $this->getErrorTextForFormattedSQ(); |
| 60 | + } |
| 61 | + |
| 62 | + return $out; |
| 63 | + } |
| 64 | + |
| 65 | + public function getWikiText( |
| 66 | + $linked = SemExShortQueryOutputOptions::LINK_ALL, |
| 67 | + $showErrors = true |
| 68 | + ) { |
| 69 | + return $this->getWikiText_internal( $linked, $showErrors, true ); |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * Returns an abstract representation of the result which expresses what exactly the query is all |
| 74 | + * about. |
| 75 | + * |
| 76 | + * @return string |
| 77 | + */ |
| 78 | + public function getRawText() { |
| 79 | + $parts = $this->getAbstractParts( true, false ); |
| 80 | + $text = $this->buildAbstractText( |
| 81 | + $parts['property'], |
| 82 | + $parts['source'], |
| 83 | + $parts['fromref'] |
| 84 | + ); |
| 85 | + return "<$text>"; |
| 86 | + } |
| 87 | + |
| 88 | + /** |
| 89 | + * Helper function to put together the abstract string |
| 90 | + */ |
| 91 | + protected function buildAbstractText( $property, $source, $fromRef = false ) { |
| 92 | + if( $source === null ) { |
| 93 | + // query from current page |
| 94 | + // don't display any further info |
| 95 | + $ret = $property; |
| 96 | + } elseif( $fromRef ) { |
| 97 | + // query 'from ref' |
| 98 | + $ret = wfMsgForContent( 'semex-shortquery-title-from-ref', $property, $source ); |
| 99 | + } else { |
| 100 | + // query from any other known page or expressive string |
| 101 | + $ret = wfMsgForContent( 'semex-shortquery-title', $property, $source ); |
| 102 | + } |
| 103 | + return $ret; |
| 104 | + } |
| 105 | + |
| 106 | + /** |
| 107 | + * Returns all necessary information part of abstract information about the query. |
| 108 | + * |
| 109 | + * @param bool $raw |
| 110 | + * @param bool $linked |
| 111 | + * |
| 112 | + * @return string[] with keys 'property', 'fromref' and 'source' |
| 113 | + */ |
| 114 | + protected function getAbstractParts( $raw, $linked ) { |
| 115 | + $parts = array(); |
| 116 | + $parts['fromref'] = false; |
| 117 | + |
| 118 | + $property = $this->query->getProperty()->getDataItem()->getLabel(); |
| 119 | + if( $linked ) { |
| 120 | + $propTitle = Title::makeTitle( SMW_NS_PROPERTY, $property ); |
| 121 | + $property = "[[:{$propTitle->getPrefixedText()}|$property]]"; |
| 122 | + } |
| 123 | + if( ! $raw ) { |
| 124 | + $property = "<span class=\"property\">$property</span>"; |
| 125 | + } |
| 126 | + $parts['property'] = $property; |
| 127 | + |
| 128 | + if( |
| 129 | + $this->getSource() !== null |
| 130 | + && $this->parser->getTitle()->getPrefixedText() === $this->getSource()->getPrefixedText() |
| 131 | + ) { |
| 132 | + // query from current page |
| 133 | + $parts['source'] = null; |
| 134 | + } |
| 135 | + elseif( $this->query->getSourceType() === SemExShortQuery::SOURCE_FROM_REF ) { |
| 136 | + // query 'from ref' |
| 137 | + $parts['fromref'] = true; |
| 138 | + $parts['source'] = $this->query->getSource()->getDataItem()->getLabel(); |
| 139 | + if( ! $raw ) { |
| 140 | + $parts['source'] = "<u>{$parts['source']}</u>"; |
| 141 | + } |
| 142 | + } |
| 143 | + else { |
| 144 | + if( $this->getSource() === null ) { |
| 145 | + if( $this->sourceResult !== null ) { |
| 146 | + // source from SemExShortQuery object. Put it into an expressive string so we can get |
| 147 | + // the expressive representation without troubles |
| 148 | + $source = new SemExExpressiveString( '', $this->parser, SEMEX_EXPR_PIECE_SQRESULT ); |
| 149 | + $source->addPieces( new SemExExpressiveStringPieceSQResult( |
| 150 | + $this->sourceResult // take cached version so we don't have to query again |
| 151 | + ) ); |
| 152 | + } |
| 153 | + else { |
| 154 | + // source must be from unresolved expressive string |
| 155 | + $source = $this->query->getSource(); |
| 156 | + } |
| 157 | + |
| 158 | + $source = ( $raw ) |
| 159 | + ? $source->getRawText( true ) |
| 160 | + : $source->getWikiText( true, $linked ); |
| 161 | + } |
| 162 | + else { |
| 163 | + // query from any other known page |
| 164 | + $source = $this->getSource()->getPrefixedText(); |
| 165 | + if( $linked ) { |
| 166 | + $source = "[[:$source]]"; |
| 167 | + } |
| 168 | + } |
| 169 | + $parts['source'] = $source; |
| 170 | + } |
| 171 | + if( $parts['source'] !== null && ! $raw ) { |
| 172 | + $parts['source'] = "<span class=\"source\">{$parts['source']}</span>"; |
| 173 | + } |
| 174 | + |
| 175 | + return $parts; |
| 176 | + } |
| 177 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExShortQueryAbstractResult.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 178 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPF.php |
— | — | @@ -0,0 +1,132 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class for the '?to?!' parser function, basically a limited converter for expressive strings. |
| 6 | + * |
| 7 | + * @since 0.1 |
| 8 | + * |
| 9 | + * @file SemExExpressiveStringPF.php |
| 10 | + * @ingroup SemanticExpressiveness |
| 11 | + * |
| 12 | + * @author Daniel Werner < danweetz@web.de > |
| 13 | + */ |
| 14 | +class SemExExpressiveStringPF extends ParserHook { |
| 15 | + |
| 16 | + public function __construct() { |
| 17 | + // make this a parser function extension (no tag extension) only: |
| 18 | + parent::__construct( false, true, ParserHook::FH_NO_HASH ); |
| 19 | + } |
| 20 | + |
| 21 | + /** |
| 22 | + * No LSB in pre-5.3 PHP, to be refactored later |
| 23 | + */ |
| 24 | + public static function staticInit( Parser &$parser ) { |
| 25 | + $instance = new self; |
| 26 | + $instance->init( $parser ); |
| 27 | + return true; |
| 28 | + } |
| 29 | + |
| 30 | + /** |
| 31 | + * Gets the name of the parser hook. |
| 32 | + * @see ParserHook::getName |
| 33 | + * |
| 34 | + * @return string |
| 35 | + */ |
| 36 | + protected function getName() { |
| 37 | + return '?to?!'; |
| 38 | + } |
| 39 | + |
| 40 | + /** |
| 41 | + * Returns an array containing the parameter info. |
| 42 | + * @see ParserHook::getParameterInfo |
| 43 | + * |
| 44 | + * @return array |
| 45 | + */ |
| 46 | + protected function getParameterInfo( $type ) { |
| 47 | + $params = array(); |
| 48 | + |
| 49 | + # input text. |
| 50 | + # since 0.1 |
| 51 | + $params['text'] = new Parameter( 'text' ); |
| 52 | + |
| 53 | + $pieceTypesCriteria = new CriterionInArray( |
| 54 | + array_values( SemExExpressiveString::getRegisteredPieceTypeNames() ) |
| 55 | + ); |
| 56 | + |
| 57 | + $params['detect'] = new ListParameter( 'detect' ); |
| 58 | + $params['detect']->addCriteria( $pieceTypesCriteria ); |
| 59 | + $params['detect']->setDefault( false, false ); |
| 60 | + |
| 61 | + $params['ignore'] = new ListParameter( 'ignore' ); |
| 62 | + $params['ignore']->addCriteria( $pieceTypesCriteria ); |
| 63 | + $params['ignore']->setDefault( array(), false ); |
| 64 | + |
| 65 | + $params = array_merge( $params, SemExExpressiveStringOutputOptions::getPFParams() ); |
| 66 | + |
| 67 | + return $params; |
| 68 | + } |
| 69 | + |
| 70 | + /** |
| 71 | + * Returns the list of default parameters. |
| 72 | + * @see ParserHook::getDefaultParameters |
| 73 | + * |
| 74 | + * @return array |
| 75 | + */ |
| 76 | + protected function getDefaultParameters( $type ) { |
| 77 | + return array( |
| 78 | + array( 'text', Validator::PARAM_UNNAMED ), |
| 79 | + ); |
| 80 | + } |
| 81 | + |
| 82 | + /** |
| 83 | + * Returns the parser function options. |
| 84 | + * @see ParserHook::getFunctionOptions |
| 85 | + * |
| 86 | + * @return array |
| 87 | + */ |
| 88 | + protected function getFunctionOptions() { |
| 89 | + return array( |
| 90 | + 'noparse' => true, |
| 91 | + 'isHTML' => false |
| 92 | + ); |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * Renders and returns the output. |
| 97 | + * @see ParserHook::renderTag |
| 98 | + * |
| 99 | + * @param array $parameters |
| 100 | + * @return string |
| 101 | + */ |
| 102 | + public function render( array $parameters ) { |
| 103 | + // get all types that should be handled by this |
| 104 | + $enabledTypes = array(); |
| 105 | + |
| 106 | + if( $parameters['detect'] !== false ) { |
| 107 | + foreach( $parameters['detect'] as $typeName ) { |
| 108 | + $type = SemExExpressiveString::getRegisteredPieceTypeByName( $typeName ); |
| 109 | + if( $type !== null ) { |
| 110 | + $enabledTypes[] = $type; |
| 111 | + } |
| 112 | + } |
| 113 | + } elseif( empty( $parameters['ignore'] ) ) { |
| 114 | + $enabledTypes = null; // same as next but constructor will process this faster |
| 115 | + } else { |
| 116 | + $enabledTypes = SemExExpressiveString::getRegisteredPieceTypeNames(); |
| 117 | + } |
| 118 | + |
| 119 | + $enabledTypes = array_flip( $enabledTypes ); |
| 120 | + foreach( $parameters['ignore'] as $typeName ) { |
| 121 | + unset( $enabledTypes[ SemExExpressiveString::getRegisteredPieceTypeByName( $typeName ) ] ); |
| 122 | + } |
| 123 | + $enabledTypes = array_flip( $enabledTypes ); |
| 124 | + |
| 125 | + // build expressive string from input with enabled types: |
| 126 | + $exprString = new SemExExpressiveString( $parameters['text'], $this->parser, $enabledTypes ); |
| 127 | + |
| 128 | + /** @ToDo: Make it possible to define options per piece type per parameter prefixes */ |
| 129 | + $options = SemExExpressiveStringOutputOptions::newFromValidatedParams( $parameters ); |
| 130 | + return $exprString->getOutput( $options ); |
| 131 | + } |
| 132 | + |
| 133 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPF.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 134 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPieceByRegex.php |
— | — | @@ -0,0 +1,118 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Abstract class representing one piece of a SemExExpressiveString with abstract features to |
| 6 | + * initialize pieces of a type by a matching regular expression. |
| 7 | + * |
| 8 | + * @since 0.1 |
| 9 | + * |
| 10 | + * @file SemExExpressiveStringPiece.php |
| 11 | + * @ingroup SemanticExpressiveness |
| 12 | + * |
| 13 | + * @author Daniel Werner < danweetz@web.de > |
| 14 | + */ |
| 15 | +abstract class SemExExpressiveStringPieceByRegex extends SemExExpressiveStringPiece { |
| 16 | + |
| 17 | + /** |
| 18 | + * The regular expression to match pieces which will be considered candidates for being pieces of |
| 19 | + * this type and which can be further examined in static::examineRegexMatch() |
| 20 | + * This is only the inner regex, modifiers can be set via static::$regex_modifiers |
| 21 | + * The '/' character has to be escaped '\/' within the expression. |
| 22 | + * @var string |
| 23 | + */ |
| 24 | + protected static $regex; |
| 25 | + |
| 26 | + /** |
| 27 | + * Optional modifiers for the static::$regex regex. |
| 28 | + * @var string |
| 29 | + */ |
| 30 | + protected static $regex_modifiers = ''; |
| 31 | + |
| 32 | + /** |
| 33 | + * Array telling which backreferences of $regex are essential information and which can be ignored. |
| 34 | + * The array index refers to the backreference index within $regex, if it is set to true it means |
| 35 | + * that the value will be made available within static::examineRegexMatch(). |
| 36 | + * The whole matched string will be made available anyway, so it might not be necessary to request |
| 37 | + * further backrefs here. |
| 38 | + * @var bool[] |
| 39 | + */ |
| 40 | + protected static $regex_essentials = array(); |
| 41 | + |
| 42 | + |
| 43 | + protected static function examineString( $string, Parser $parser ) { |
| 44 | + // the regex is built to hold the whole matched string as backref for later |
| 45 | + $regex = '/(' . static::$regex . ')/' . static::$regex_modifiers; |
| 46 | + $rawParts = preg_split( $regex, $string, -1, PREG_SPLIT_DELIM_CAPTURE ); |
| 47 | + |
| 48 | + $count = count( $rawParts ) ; |
| 49 | + if( $count <= 1 ) { |
| 50 | + // no match for this type |
| 51 | + return false; |
| 52 | + } |
| 53 | + |
| 54 | + $parts = array(); |
| 55 | + $backrefs = count( static::$regex_essentials ); |
| 56 | + |
| 57 | + // group backrefs and actual match which belong together, put non-expressive strings inbetween |
| 58 | + // so we have an array full of strings and sub-arrays still in the right order: |
| 59 | + for( $i = 0; $i < $count; $i++ ){ |
| 60 | + $parts[] = $rawParts[ $i ]; // string or empty part inbetween |
| 61 | + $i++; |
| 62 | + if( $i === $count ) { |
| 63 | + break; // last piece |
| 64 | + } |
| 65 | + |
| 66 | + // get all essential backrefs for the matching piece: |
| 67 | + $essentialBackrefs = array( |
| 68 | + $rawParts[ $i ] // the part holding the whole matched string, the raw piece |
| 69 | + ); |
| 70 | + for( $k = 0; $k < $backrefs; $k++ ) { |
| 71 | + $i++; |
| 72 | + if( static::$regex_essentials[ $k ] ) { |
| 73 | + $essentialBackrefs[] = $rawParts[ $i ]; |
| 74 | + } |
| 75 | + } |
| 76 | + $parts[] = $essentialBackrefs; |
| 77 | + } |
| 78 | + |
| 79 | + // walk through the created array and call sub-function for each array element which holds all the |
| 80 | + // information about one potential match for a piece of this type: |
| 81 | + $result = array(); |
| 82 | + $i = -1; |
| 83 | + foreach( $parts as $part ) { |
| 84 | + $i++; |
| 85 | + if( is_string( $part ) ) { |
| 86 | + // only each second element can be a regex match |
| 87 | + if( $part !== '' ) { |
| 88 | + $result[] = new SemExExpressiveStringPiece( $part ); |
| 89 | + } |
| 90 | + continue; |
| 91 | + } |
| 92 | + |
| 93 | + $piece = static::examineRegexMatch( $part, $parser ); |
| 94 | + |
| 95 | + if( $piece === false ) { |
| 96 | + // not a piece of this type, consider it a meaningless string |
| 97 | + $piece = new SemExExpressiveStringPiece( $part[0], $parser ); |
| 98 | + } |
| 99 | + |
| 100 | + $result[] = $piece; |
| 101 | + } |
| 102 | + |
| 103 | + return $result; |
| 104 | + } |
| 105 | + |
| 106 | + /** |
| 107 | + * Function called by examineString() when a static::$regex matching string has been found. |
| 108 | + * Returns the resolved piece or false in case this is not a piece of this type. |
| 109 | + * |
| 110 | + * @param string[] $backRefs all references from static::$regex which are marked as essential |
| 111 | + * by static::$regex_essentials. The index 0 contains the whole match. |
| 112 | + * @param Parser $parser |
| 113 | + * |
| 114 | + * @return SemExExpressiveStringPiece|false |
| 115 | + */ |
| 116 | + protected static function examineRegexMatch( array $backRefs, Parser $parser ) { |
| 117 | + return false; |
| 118 | + } |
| 119 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringPieceByRegex.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 120 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringOutputOptions.php |
— | — | @@ -0,0 +1,305 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class for defining options for expressive strings output. |
| 6 | + * SemExExpressiveString::getOutput() can be used to get the formatted output in the form defined by |
| 7 | + * a SemExExpressiveStringOutputOptions object. |
| 8 | + * |
| 9 | + * @since 0.1 |
| 10 | + * |
| 11 | + * @file SemExExpressiveStringOutputOptions.php |
| 12 | + * @ingroup SemanticExpressiveness |
| 13 | + * |
| 14 | + * @author Daniel Werner < danweetz@web.de > |
| 15 | + */ |
| 16 | +class SemExExpressiveStringOutputOptions extends SemExPFParamsBasedFactory { |
| 17 | + |
| 18 | + protected static $pfParamsValidatorElement = 'expressive string output options'; |
| 19 | + |
| 20 | + /** |
| 21 | + * With this format output will be printed as suitable MediaWiki wikitext markup. |
| 22 | + */ |
| 23 | + const FORMAT_WIKITEXT = 1; |
| 24 | + /** |
| 25 | + * If this is set as format, all links, errors and markup of any kind will not be printed even |
| 26 | + * though the other options are set accordingly. |
| 27 | + */ |
| 28 | + const FORMAT_RAW = 2; |
| 29 | + /* |
| 30 | + * @todo: HTML support not yet implemented in any output printer, include this if it should ever |
| 31 | + * be required. |
| 32 | + */ |
| 33 | + //const FORMAT_HTML = 3; |
| 34 | + |
| 35 | + |
| 36 | + /** |
| 37 | + * Implies that there will be no links at all within the output. |
| 38 | + */ |
| 39 | + const LINK_NONE = false; |
| 40 | + |
| 41 | + /** |
| 42 | + * Implies that links will be printed within the output. |
| 43 | + */ |
| 44 | + const LINK_ALL = true; |
| 45 | + |
| 46 | + |
| 47 | + /** |
| 48 | + * The output will be in its abstract representation if a failure occured. |
| 49 | + */ |
| 50 | + const ABSTRACT_IF_FAILURE = true; |
| 51 | + |
| 52 | + /** |
| 53 | + * The output will never have an abstract representation, even if a failure has occured. Normally |
| 54 | + * an empty string will be returned instead. |
| 55 | + */ |
| 56 | + const NO_ABSTRACT = false; |
| 57 | + |
| 58 | + /** |
| 59 | + * This can be used to enforce abstract output. |
| 60 | + */ |
| 61 | + const ABSTRACT_ONLY = 2; |
| 62 | + |
| 63 | + |
| 64 | + protected $link = self::LINK_ALL; |
| 65 | + protected $showInfo = true; |
| 66 | + protected $showAbstract = null; |
| 67 | + protected $showErrors = null; |
| 68 | + protected $format = self::FORMAT_WIKITEXT; |
| 69 | + |
| 70 | + /** |
| 71 | + * Merges options of another SemExExpressiveStringOutputOptions object with this objects options. |
| 72 | + * |
| 73 | + * @note This is only save when merging the object with an ancestor or equal instance but should |
| 74 | + * not be done with objects of a descendant option class. |
| 75 | + * |
| 76 | + * @param SemExExpressiveStringOutputOptions $options |
| 77 | + */ |
| 78 | + public function mergeOptions( SemExExpressiveStringOutputOptions $options ) { |
| 79 | + $options = get_object_vars( $options ); |
| 80 | + foreach( $options as $var => $val ) { |
| 81 | + $this->{ $var } = $val; |
| 82 | + } |
| 83 | + } |
| 84 | + |
| 85 | + /** |
| 86 | + * Defines whether the output should contain links. The following values are possible: |
| 87 | + * |
| 88 | + * self::LINK_NONE - No links at all. |
| 89 | + * self::LINK_ALL - Links will be used where possible. |
| 90 | + * |
| 91 | + * null - Now the option depends on getShowInfo(). If it is true, then this will behave if as |
| 92 | + * self::LINK_ALL were set, otherwise it will be self::LINK_NONE. |
| 93 | + * |
| 94 | + * @param mixed $val |
| 95 | + * @return string previous value |
| 96 | + */ |
| 97 | + public function setLink( $val ) { |
| 98 | + return wfSetVar( $this->link, $val ); |
| 99 | + } |
| 100 | + |
| 101 | + /** |
| 102 | + * Defines whether the expressive piece should be formatted as such and display all the |
| 103 | + * available abstract information in case it fails. |
| 104 | + * This is sort of a group-option setting default behavior for various other options which |
| 105 | + * consider this option as their default but also can overwrite this explicitly. |
| 106 | + * |
| 107 | + * @param bool $val |
| 108 | + * @return bool previous value |
| 109 | + */ |
| 110 | + public function setShowInfo( $val ) { |
| 111 | + return wfSetVar( $this->showInfo, $val ); |
| 112 | + } |
| 113 | + |
| 114 | + /** |
| 115 | + * Defines whether the abstract representation should be displayed if an error occurs or if |
| 116 | + * perhaps only the abstract value should be returned. The following four options are allowed: |
| 117 | + * |
| 118 | + * self::ABSTRACT_IF_FAILURE - The abstract value will be displayed if an error occurs. |
| 119 | + * self::NO_ABSTRACT - Abstract value will never be displayed, even on failure. |
| 120 | + * self::ABSTRACT_ONLY - Only the abstract value will be returned. |
| 121 | + * |
| 122 | + * null - Now the option depends on getShowInfo(). If it is true, then this will behave as if |
| 123 | + * self::ABSTRACT_IF_FAILURE were set, otherwise it will be self::NO_ABSTRACT. |
| 124 | + * |
| 125 | + * @param mixed|null $val |
| 126 | + * @return mixed|null previous value |
| 127 | + */ |
| 128 | + public function setShowAbstract( $val ) { |
| 129 | + return wfSetVar( $this->showAbstract, $val ); |
| 130 | + } |
| 131 | + |
| 132 | + /** |
| 133 | + * Defines whether the output should reveal any eventual errors as messages. By default and if |
| 134 | + * null is set, the behavior will depend on and equal getShowInfo(). |
| 135 | + * |
| 136 | + * @param bool|null $val |
| 137 | + * @return bool|null previous value |
| 138 | + */ |
| 139 | + public function setShowErrors( $val ) { |
| 140 | + return wfSetVar( $this->showErrors, $val ); |
| 141 | + } |
| 142 | + |
| 143 | + /** |
| 144 | + * Defines the output format. |
| 145 | + * |
| 146 | + * @param integer $val Allows to set one of the follwoing output formats: |
| 147 | + * |
| 148 | + * self::FORMAT_WIKITEXT - The output will be returned as wikitext (default) |
| 149 | + * self::FORMAT_HTML - The output will be formatted and properly escaped to be used |
| 150 | + * directly in HTML (not implemented yet!) |
| 151 | + * |
| 152 | + * @return integer previous value |
| 153 | + */ |
| 154 | + public function setFormat( $val ) { |
| 155 | + return wfSetVar( $this->format, $val ); |
| 156 | + } |
| 157 | + |
| 158 | + public function getShowInfo() { return $this->showInfo; } |
| 159 | + public function getFormat() { return $this->format; } |
| 160 | + |
| 161 | + /** |
| 162 | + * Returns whether links should be generated. By default this equals getShowInfo(). |
| 163 | + * |
| 164 | + * @return mixed previous value |
| 165 | + */ |
| 166 | + public function getLink() { |
| 167 | + if( $this->link !== null ) { |
| 168 | + return $this->link; |
| 169 | + } |
| 170 | + // by default show links when displaying infos |
| 171 | + return $this->showInfo; |
| 172 | + } |
| 173 | + |
| 174 | + /** |
| 175 | + * Returns whether the abstract representation should be displayed if the query goes wrong or |
| 176 | + * if perhaps only the abstract value should be returned without querying at all. |
| 177 | + * By default this depends on and equals the value of getShowInfo() |
| 178 | + * |
| 179 | + * @return mixed |
| 180 | + */ |
| 181 | + public function getShowAbstract() { |
| 182 | + if( $this->showErrors !== null ) { |
| 183 | + return $this->showErrors; |
| 184 | + } |
| 185 | + // by default show abstract when displaying infos |
| 186 | + return $this->showInfo; |
| 187 | + } |
| 188 | + |
| 189 | + /** |
| 190 | + * Returns whether Errors should be displayed for the output. |
| 191 | + * By default this depends on and equals the value of getShowInfo() |
| 192 | + * |
| 193 | + * @return bool |
| 194 | + */ |
| 195 | + public function getShowErrors() { |
| 196 | + if( $this->showErrors !== null ) { |
| 197 | + return $this->showErrors; |
| 198 | + } |
| 199 | + // by default show errors when displaying infos |
| 200 | + return $this->showInfo; |
| 201 | + } |
| 202 | + |
| 203 | + |
| 204 | + /** |
| 205 | + * @see SemExPFParamsBasedFactory::newFromValidatedParams() |
| 206 | + */ |
| 207 | + public static function newFromValidatedParams( array $params ) { |
| 208 | + $sqOpt = new static(); |
| 209 | + |
| 210 | + $format = $params['format']; |
| 211 | + switch( $format ) { |
| 212 | + case 'raw': |
| 213 | + $format = self::FORMAT_RAW; |
| 214 | + break; |
| 215 | + case 'wiki': |
| 216 | + default: |
| 217 | + $format = self::FORMAT_WIKITEXT; |
| 218 | + break; |
| 219 | + } |
| 220 | + |
| 221 | + $link = $params['link']; |
| 222 | + switch( $link ) { |
| 223 | + case 'all': |
| 224 | + case 'show': |
| 225 | + case 'subject': |
| 226 | + $link = self::LINK_ALL; |
| 227 | + break; |
| 228 | + case 'none': |
| 229 | + $link = self::LINK_NONE; |
| 230 | + break; |
| 231 | + case 'auto': |
| 232 | + default: |
| 233 | + // links only when displaying info |
| 234 | + $link = null; |
| 235 | + } |
| 236 | + |
| 237 | + $abstract = $params['abstract']; |
| 238 | + switch( $abstract ) { |
| 239 | + case 'show': |
| 240 | + $abstract = self::ABSTRACT_IF_FAILURE; |
| 241 | + break; |
| 242 | + case 'hide': |
| 243 | + $abstract = self::NO_ABSTRACT; |
| 244 | + break; |
| 245 | + case 'only': |
| 246 | + $abstract = self::ABSTRACT_ONLY; |
| 247 | + break; |
| 248 | + case 'auto': |
| 249 | + default: |
| 250 | + // abstract info only when displaying info |
| 251 | + $abstract = null; |
| 252 | + } |
| 253 | + |
| 254 | + $errors = $params['errors']; |
| 255 | + switch( $errors ) { |
| 256 | + case 'show': |
| 257 | + $errors = true; |
| 258 | + break; |
| 259 | + case 'hide': |
| 260 | + $errors = false; |
| 261 | + break; |
| 262 | + case 'auto': |
| 263 | + default: |
| 264 | + // show errors only when displaying info |
| 265 | + $errors = null; |
| 266 | + } |
| 267 | + |
| 268 | + $sqOpt->setFormat( $format ); |
| 269 | + $sqOpt->setLink( $link ); |
| 270 | + $sqOpt->setShowInfo( $params['info'] ); |
| 271 | + $sqOpt->setShowAbstract( $abstract ); |
| 272 | + $sqOpt->setShowErrors( $errors ); |
| 273 | + |
| 274 | + return $sqOpt; |
| 275 | + } |
| 276 | + |
| 277 | + /** |
| 278 | + * Returns a description of all allowed function Parameters representing SemExShortQueryResultOptions. |
| 279 | + * |
| 280 | + * @return array |
| 281 | + */ |
| 282 | + public static function getPFParams() { |
| 283 | + $params = array(); |
| 284 | + |
| 285 | + $params['format'] = new Parameter( 'format' ); |
| 286 | + $params['format']->addCriteria( new CriterionInArray( 'wiki', 'raw' ) ); |
| 287 | + $params['format']->setDefault( 'wiki' ); |
| 288 | + |
| 289 | + $params['info'] = new Parameter( 'info', Parameter::TYPE_BOOLEAN ); |
| 290 | + $params['info']->setDefault( true ); |
| 291 | + |
| 292 | + $params['link'] = new Parameter( 'link' ); |
| 293 | + $params['link']->addCriteria( new CriterionInArray( 'all', 'show', 'subject', 'none', 'auto' ) ); |
| 294 | + $params['link']->setDefault( 'auto' ); |
| 295 | + |
| 296 | + $params['abstract'] = new Parameter( 'abstract' ); |
| 297 | + $params['abstract']->addCriteria( new CriterionInArray( 'only', 'show', 'hide', 'auto' ) ); |
| 298 | + $params['abstract']->setDefault( 'auto' ); |
| 299 | + |
| 300 | + $params['errors'] = new Parameter( 'errors' ); |
| 301 | + $params['errors']->addCriteria( new CriterionInArray( 'show', 'hide', 'auto' ) ); |
| 302 | + $params['errors']->setDefault( 'auto' ); |
| 303 | + |
| 304 | + return $params; |
| 305 | + } |
| 306 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveStringOutputOptions.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 307 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExShortQueryOutputOptions.php |
— | — | @@ -0,0 +1,92 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class for defining options for a 'Semantic Expressiveness' short query. |
| 6 | + * SemExShortQueryProcessor::getResultFromQuery() can be used to get a short queries result using |
| 7 | + * a SemExShortQuery and these options. |
| 8 | + * SemExShortQueryResult::getOutput() can also be used to get the formatted output specified by a |
| 9 | + * SemExShortQuery object. |
| 10 | + * |
| 11 | + * @since 0.1 |
| 12 | + * |
| 13 | + * @file SemExShortQueryResultOptions.php |
| 14 | + * @ingroup SemanticExpressiveness |
| 15 | + * |
| 16 | + * @author Daniel Werner < danweetz@web.de > |
| 17 | + */ |
| 18 | +class SemExShortQueryOutputOptions extends SemExExpressiveStringOutputOptions { |
| 19 | + |
| 20 | + protected static $pfParamsValidatorElement = 'short query output options'; |
| 21 | + |
| 22 | + /** |
| 23 | + * Link depending on the properties Type. Values coming from properties of Type 'Page' will |
| 24 | + * display a link. If the queried value consists of multiple values or is a set of data |
| 25 | + * bundled in one property, the linking will happen individually for each part if appropriate. |
| 26 | + */ |
| 27 | + const LINK_ALL = true; |
| 28 | + |
| 29 | + /** |
| 30 | + * The output will be wrapped inside a link to the queries source page, even if the property |
| 31 | + * value is a value of type 'Page' which would bring its own link to another page. This makes |
| 32 | + * sense for properties which are not of type 'Page' but kind of represent the whole article, |
| 33 | + * e.g. a 'Name' property. |
| 34 | + */ |
| 35 | + const LINK_TOPIC = 2; |
| 36 | + |
| 37 | + |
| 38 | + /** |
| 39 | + * Defines whether the short query result should contain a link to the queried property |
| 40 | + * or the target page. Following values are possible: |
| 41 | + * |
| 42 | + * self::LINK_NONE - No links at all. |
| 43 | + * self::LINK_ALL - Link depending on the properties Type. Type 'Page' will display link. |
| 44 | + * self::LINK_TOPIC - The property value will be wrapped inside a link to the source page, |
| 45 | + * even if the property value is a value of type 'Page' which would |
| 46 | + * bring its own link to another page. |
| 47 | + * |
| 48 | + * null - Now the option depends on getShowInfo(). If it is true, then this will behave if as |
| 49 | + * self::LINK_ALL were set, otherwise it will be self::LINK_NONE. |
| 50 | + * |
| 51 | + * @param mixed $val |
| 52 | + * @return string previous value |
| 53 | + */ |
| 54 | + public function setLink( $val ) { |
| 55 | + return parent::setLink( $val ); |
| 56 | + } |
| 57 | + |
| 58 | + /** |
| 59 | + * @see SemExPFParamsBasedFactory::newFromValidatedParams() |
| 60 | + */ |
| 61 | + public static function newFromValidatedParams( array $params ) { |
| 62 | + $sqOpt = parent::newFromValidatedParams( $params ); |
| 63 | + |
| 64 | + $link = $params['link']; |
| 65 | + if( $link == 'topic' || $link == 'source' ) { |
| 66 | + $sqOpt->setLink( self::LINK_TOPIC ); |
| 67 | + } |
| 68 | + |
| 69 | + return $sqOpt; |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * @see SemExExpressiveStringOutputOptions::getPFParams() |
| 74 | + * |
| 75 | + * @return array |
| 76 | + */ |
| 77 | + public static function getPFParams() { |
| 78 | + $params = parent::getPFParams(); |
| 79 | + |
| 80 | + // add 'topic' to the allowed 'link' parameter values: |
| 81 | + $linkCriteria = $params['link']->getCriteria(); |
| 82 | + $linkCriteria = array_merge( $linkCriteria[0]->getAllowedValues(), array( 'topic', 'source' ) ); |
| 83 | + |
| 84 | + $newLink = new Parameter( 'link' ); |
| 85 | + $newLink->addCriteria( new CriterionInArray( $linkCriteria ) ); |
| 86 | + $newLink->setDefault( $params['link']->getDefault() ); |
| 87 | + |
| 88 | + // overwrite old parameter definition: |
| 89 | + $params['link'] = $newLink; |
| 90 | + |
| 91 | + return $params; |
| 92 | + } |
| 93 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExShortQueryOutputOptions.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 94 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveString.php |
— | — | @@ -0,0 +1,507 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class which can process a string which potentially contains one or several SemExShortQueryResult |
| 6 | + * representations. Once initialized, this will offer access to all failed and successful short query |
| 7 | + * results and text parts inbetween. Also allows to convert the whole string into plain text or to |
| 8 | + * convert containing |
| 9 | + * |
| 10 | + * @since 0.1 |
| 11 | + * |
| 12 | + * @file SemExExpressiveString.php |
| 13 | + * @ingroup SemanticExpressiveness |
| 14 | + * |
| 15 | + * @author Daniel Werner < danweetz@web.de > |
| 16 | + */ |
| 17 | +class SemExExpressiveString { |
| 18 | + |
| 19 | + protected $enabledPieceTypes; |
| 20 | + protected $parser; |
| 21 | + |
| 22 | + /** |
| 23 | + * All parts the original string $string consists of |
| 24 | + * @var array of SemExShortQueryResult objects and/or strings |
| 25 | + */ |
| 26 | + protected $pieces = array(); |
| 27 | + |
| 28 | + /** |
| 29 | + * Constructor |
| 30 | + * |
| 31 | + * @param string $string |
| 32 | + * @param Parser $parser |
| 33 | + * @param array|string $enabledPieceTypes allows to define which expressive types should be |
| 34 | + * detected. See static::getRegisteredPieceTypes() for all possible types. |
| 35 | + */ |
| 36 | + function __construct( $string, Parser $parser, $enabledPieceTypes = null ) { |
| 37 | + if( $enabledPieceTypes === null ) { |
| 38 | + $enabledPieceTypes = static::getRegisteredPieceTypes(); |
| 39 | + } |
| 40 | + elseif( ! is_array( $enabledPieceTypes ) ) { |
| 41 | + // only one type, don't care about priority |
| 42 | + $enabledPieceTypes = array( $enabledPieceTypes ); |
| 43 | + } |
| 44 | + else { |
| 45 | + // make sure we get the priority as key in user-given array |
| 46 | + $enabledPieceTypes = $this->injectPieceTypePriorities( $enabledPieceTypes ); |
| 47 | + } |
| 48 | + krsort( $enabledPieceTypes ); // highest will be initialized last |
| 49 | + $this->enabledPieceTypes = $enabledPieceTypes; |
| 50 | + $this->parser = $parser; |
| 51 | + |
| 52 | + // add string as non-expressive string... |
| 53 | + $this->addString( $string ); |
| 54 | + |
| 55 | + // ... and examine its expressive meaning one by one: |
| 56 | + foreach( $this->getEnabledPieceTypes() as $pieceType ) { |
| 57 | + $pieceType :: initWithin( $this ); |
| 58 | + } |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * Returns all parts the original string consists of. |
| 63 | + * |
| 64 | + * @return SemExExpressiveStringPiece[] |
| 65 | + */ |
| 66 | + public function getPieces() { |
| 67 | + return $this->pieces; |
| 68 | + } |
| 69 | + |
| 70 | + /** |
| 71 | + * Returns a piece from a given index or null if the index doesn't exist. |
| 72 | + * |
| 73 | + * @param int $index |
| 74 | + * @return SemExExpressiveStringPiece |
| 75 | + */ |
| 76 | + public function getPiece( $index ) { |
| 77 | + if( ! array_key_exists( $index, $this->pieces ) ) { |
| 78 | + return null; |
| 79 | + } |
| 80 | + return $this->pieces[ $index ]; |
| 81 | + } |
| 82 | + |
| 83 | + /** |
| 84 | + * Returns all pieces of the string which which have their own expressive meaning and not just |
| 85 | + * represent a simple string. |
| 86 | + * |
| 87 | + * @return SemExExpressiveStringPiece[] |
| 88 | + */ |
| 89 | + public function getExpressivePieces() { |
| 90 | + $exprPieces = array(); |
| 91 | + foreach( $this->pieces as $piece ) { |
| 92 | + if( $piece->isExpressive() ) { |
| 93 | + $exprPieces[] = $piece; |
| 94 | + } |
| 95 | + } |
| 96 | + return $exprPieces; |
| 97 | + } |
| 98 | + |
| 99 | + /** |
| 100 | + * Returns whether the string has any expressive pieces. |
| 101 | + * |
| 102 | + * @return bool |
| 103 | + */ |
| 104 | + public function hasExpressiveness() { |
| 105 | + foreach( $this->pieces as $piece ) { |
| 106 | + if( $piece->isExpressive() ) { |
| 107 | + return true; |
| 108 | + } |
| 109 | + } |
| 110 | + return false; |
| 111 | + } |
| 112 | + |
| 113 | + /** |
| 114 | + * Returns true if any expressive piece is not resolvable, meaning the piece doesn't have a pure |
| 115 | + * textual representation. |
| 116 | + * |
| 117 | + * @return bool |
| 118 | + */ |
| 119 | + public function hasUnresolvablePiece() { |
| 120 | + foreach( $this->pieces as $piece ) { |
| 121 | + if( $piece->isUnresolvable() ) { |
| 122 | + return true; |
| 123 | + } |
| 124 | + } |
| 125 | + return false; |
| 126 | + } |
| 127 | + |
| 128 | + /** |
| 129 | + * This will examine a string for its expressive meaning and add all parts accordingly. |
| 130 | + * |
| 131 | + * @param string $string |
| 132 | + * @param int $index see self::addPieces() |
| 133 | + */ |
| 134 | + public function addExpressiveString( $string, $index = null ) { |
| 135 | + $newExprString = new static( $string, $this->parser, $this->getEnabledPieceTypes() ); |
| 136 | + $this->addPieces( $newExprString->getPieces(), $index ); |
| 137 | + } |
| 138 | + |
| 139 | + /** |
| 140 | + * Shorthand function for self::addPieces( new SemExExpressiveStringPiece( $stringPiece ) ). |
| 141 | + * |
| 142 | + * @param string $stringPiece |
| 143 | + * @param int $index see self::addPieces() |
| 144 | + */ |
| 145 | + public function addString( $stringPiece, $index = null ) { |
| 146 | + $piece = new SemExExpressiveStringPiece( $stringPiece ); |
| 147 | + $this->addPieces( array( $piece ), $index ); |
| 148 | + } |
| 149 | + |
| 150 | + /** |
| 151 | + * Allows to insert additional pieces to the expressive string. By default at the end |
| 152 | + * or optionally at a certain index. |
| 153 | + * |
| 154 | + * @param SemExExpressiveStringPiece|SemExExpressiveStringPiece[] $pieces |
| 155 | + * @param int $index if this is set, the new pieces will be inserted at this index, |
| 156 | + * the original item at this position will be moved behind the inserted ones. |
| 157 | + * Negative index will insert the items that far from the end. |
| 158 | + */ |
| 159 | + public function addPieces( $pieces, $index = null ) { |
| 160 | + if( ! is_array( $pieces ) ) { |
| 161 | + $pieces = array( $pieces ); |
| 162 | + } |
| 163 | + $this->pieces = array_values( $this->pieces ); // re-numerate to be on the safe side |
| 164 | + $totalPieces = count( $this->pieces ); |
| 165 | + |
| 166 | + if( $index < 0 ) { |
| 167 | + // -1 will insert $pieces before last current piece |
| 168 | + $index = $totalPieces - $index; |
| 169 | + if( $index < 0 ) { |
| 170 | + $index = 0; |
| 171 | + } |
| 172 | + } |
| 173 | + |
| 174 | + if( $index === null || $index >= $totalPieces ) { |
| 175 | + // pieces will be added at the end |
| 176 | + $index = $totalPieces; |
| 177 | + } |
| 178 | + else { |
| 179 | + // pieces will be inserted before an existing one |
| 180 | + // add the piece after new pieces for reduction |
| 181 | + $pieces[] = $this->pieces[ $index ]; |
| 182 | + unset( $this->pieces[ $index ] ); |
| 183 | + } |
| 184 | + |
| 185 | + if( $index > 0 && $totalPieces > 0 ) { |
| 186 | + // add the one before new pieces for reduction |
| 187 | + $index--; |
| 188 | + $pieces = array_merge( |
| 189 | + array( $this->pieces[ $index ] ), |
| 190 | + $pieces |
| 191 | + ); |
| 192 | + unset( $this->pieces[ $index ] ); |
| 193 | + } |
| 194 | + |
| 195 | + static::reducePieces( $pieces ); |
| 196 | + |
| 197 | + array_splice( $this->pieces, $index, 0, $pieces ); // re-numerates keys |
| 198 | + } |
| 199 | + |
| 200 | + /** |
| 201 | + * Reduces an array of SemExExpressiveStringPiece elements where possible. This means if the |
| 202 | + * array contains several non-expressive objects in a row, they will be reduced to one instead. |
| 203 | + * This will also make all keys numeric and close gaps. |
| 204 | + * |
| 205 | + * @param SemExExpressiveStringPiece[] $pieces |
| 206 | + * @return int number of reduced pieces |
| 207 | + */ |
| 208 | + protected static function reducePieces( array &$pieces ) { |
| 209 | + $lastPieceType = null; |
| 210 | + $i = 0; |
| 211 | + foreach( $pieces as $key => $piece ) { |
| 212 | + if( ! $piece instanceof SemExExpressiveStringPiece |
| 213 | + || $piece->getValue() === '' |
| 214 | + ){ |
| 215 | + // remove totally useless empty string or invalid item |
| 216 | + unset( $pieces[ $key ] ); |
| 217 | + $i++; |
| 218 | + continue; |
| 219 | + } |
| 220 | + |
| 221 | + $thisPieceType = $piece->getType(); |
| 222 | + |
| 223 | + if( |
| 224 | + $lastPieceType === SEMEX_EXPR_PIECE_STRING |
| 225 | + && $thisPieceType === SEMEX_EXPR_PIECE_STRING |
| 226 | + ) { |
| 227 | + // if two elements in a row are strings, merge them: |
| 228 | + $pieces[ $lastPieceKey ] = new $lastPieceType( |
| 229 | + $pieces[ $lastPieceKey ]->getValue() . $pieces[ $key ]->getValue() |
| 230 | + ); |
| 231 | + unset( $pieces[ $key ] ); |
| 232 | + $i++; |
| 233 | + } else { |
| 234 | + $lastPieceKey = $key; |
| 235 | + $lastPieceType = $thisPieceType; |
| 236 | + } |
| 237 | + } |
| 238 | + $pieces = array_values( $pieces ); // re-numerate |
| 239 | + return $i; |
| 240 | + } |
| 241 | + |
| 242 | + /** |
| 243 | + * Removes pieces of the string starting from a given index to the end or a predefined |
| 244 | + * number of pieces. |
| 245 | + * |
| 246 | + * @param int $offset |
| 247 | + * @param int $length how many pieces to remove. null means all pieces from the $offset |
| 248 | + * to the end. A negative value will preserve pieces that far from the end. |
| 249 | + */ |
| 250 | + public function removePieces( $offset, $length = null ) { |
| 251 | + if( empty( $length ) ) { |
| 252 | + $length = count( $offset ); |
| 253 | + } |
| 254 | + array_splice( $this->pieces, $offset, $length ); |
| 255 | + static::reducePieces( $this->pieces ); |
| 256 | + } |
| 257 | + |
| 258 | + /** |
| 259 | + * Returns the parser used for certain transformations |
| 260 | + * @return Parser |
| 261 | + */ |
| 262 | + public function getParser() { |
| 263 | + return $this->parser; |
| 264 | + } |
| 265 | + |
| 266 | + public function setParser( Parser $parser ) { |
| 267 | + $this->parser = $parser; |
| 268 | + } |
| 269 | + |
| 270 | + /** |
| 271 | + * Returns the expressive string as wiki text with all expressive pieces resolved but without any |
| 272 | + * further markup, just plain text. |
| 273 | + * |
| 274 | + * @param bool $expressiveIfEmpty whether an expressive textual placeholder should be placed for |
| 275 | + * pieces which have no value. false by default. |
| 276 | + * @return string |
| 277 | + */ |
| 278 | + public function getRawText( $expressiveIfEmpty = false ) { |
| 279 | + $result = ''; |
| 280 | + |
| 281 | + foreach( $this->pieces as $piece ) { |
| 282 | + if( $expressiveIfEmpty && $piece->isUnresolvable() ) { |
| 283 | + $pieceText = $piece->getAbstractRawText(); |
| 284 | + } else { |
| 285 | + $pieceText = $piece->getRawText(); |
| 286 | + } |
| 287 | + $result .= $pieceText; |
| 288 | + } |
| 289 | + return $result; |
| 290 | + } |
| 291 | + |
| 292 | + /** |
| 293 | + * Returns the expressive string as wiki text with all expressive pieces resolved, perhaps with |
| 294 | + * markup built around some pieces. |
| 295 | + * |
| 296 | + * @param bool $expressiveIfEmpty whether an expressive textual placeholder should be placed for |
| 297 | + * pieces which have no value. true by default. |
| 298 | + * |
| 299 | + * @param bool $expressiveIfEmpty |
| 300 | + */ |
| 301 | + public function getWikiText( |
| 302 | + $expressiveIfEmpty = true, |
| 303 | + $linked = SemExExpressiveStringOutputOptions::LINK_ALL, |
| 304 | + $showErrors = false |
| 305 | + ) { |
| 306 | + $result = ''; |
| 307 | + |
| 308 | + foreach( $this->pieces as $piece ) { |
| 309 | + if( ! $expressiveIfEmpty && $piece->isUnresolvable() ) { |
| 310 | + $pieceText = $piece->getAbstractWikiText( $linked, $showErrors ); |
| 311 | + } else { |
| 312 | + $pieceText = $piece->getWikiText( $linked, $showErrors ); |
| 313 | + } |
| 314 | + $result .= $pieceText; |
| 315 | + } |
| 316 | + return $result; |
| 317 | + } |
| 318 | + |
| 319 | + /** |
| 320 | + * same as getRawText() but instead of the resolved meaning of the expressive pieces this will |
| 321 | + * include the abstract representation of all pieces as long as an abstract version is available |
| 322 | + * for the piece type. |
| 323 | + * |
| 324 | + * @return string |
| 325 | + */ |
| 326 | + public function getAbstractRawText() { |
| 327 | + $result = ''; |
| 328 | + |
| 329 | + foreach( $this->pieces as $piece ) { |
| 330 | + $result .= $piece->getAbstractRawText(); |
| 331 | + } |
| 332 | + return $result; |
| 333 | + } |
| 334 | + |
| 335 | + /** |
| 336 | + * same as getWikiText() but instead of the resolved meaning of the expressive pieces this will |
| 337 | + * include the abstract representation of all pieces as long as an abstract version is available |
| 338 | + * for the piece type. |
| 339 | + * |
| 340 | + * @return string |
| 341 | + */ |
| 342 | + public function getAbstractWikiText( |
| 343 | + $linked = SemExExpressiveStringOutputOptions::LINK_ALL, |
| 344 | + $showErrors = false |
| 345 | + ) { |
| 346 | + $result = ''; |
| 347 | + |
| 348 | + foreach( $this->pieces as $piece ) { |
| 349 | + $result .= $piece->getAbstractWikiText( $linked, $showErrors ); |
| 350 | + } |
| 351 | + return $result; |
| 352 | + } |
| 353 | + |
| 354 | + /** |
| 355 | + * Returns an output generated by one or several SemExExpressiveStringOutputOptions objects. |
| 356 | + * |
| 357 | + * @param SemExExpressiveStringOutputOptions|null $defaultOption allows to set a option used |
| 358 | + * as default. If set to null the piece types own default options will be used. |
| 359 | + * @param SemExExpressiveStringOutputOptions[]|null[] $options If one option is given, it will |
| 360 | + * be taken for all types of pieces, otherwise an array is expected which holds keys |
| 361 | + * which refer to certain piece types to define a certain option per type. If the |
| 362 | + * value for one type is set to null, it will fall back to its default option. If a |
| 363 | + * type is completely omitted, the $defaultOption will be used for the type, except it |
| 364 | + * is set to null, in this case the types default option will be used. |
| 365 | + * |
| 366 | + * @return string |
| 367 | + */ |
| 368 | + public function getOutput( $defaultOption = null, $options = array() ) { |
| 369 | + $result = ''; |
| 370 | + |
| 371 | + foreach( $this->pieces as $piece ) { |
| 372 | + $pieceType = $piece->getType(); |
| 373 | + |
| 374 | + if( array_key_exists( $pieceType, $options ) ) { |
| 375 | + // option/fallback for this piece type specified |
| 376 | + $pieceOption = $options[ $pieceType ]; |
| 377 | + } |
| 378 | + else { |
| 379 | + // no specific option for this type, use specified default option |
| 380 | + $pieceOption = $defaultOption; |
| 381 | + } |
| 382 | + |
| 383 | + if( $pieceOption === null ) { |
| 384 | + // option wasn't set! use default option for this piece type |
| 385 | + $pieceOption = $pieceOption :: getDefaultOutputOptions(); |
| 386 | + $options[ $pieceType ] = $pieceOption; // remember for next pice of this type! |
| 387 | + } |
| 388 | + |
| 389 | + $result .= $piece->getOutput( $pieceOption ); |
| 390 | + } |
| 391 | + return $result; |
| 392 | + } |
| 393 | + |
| 394 | + /** |
| 395 | + * Returns which types of expressive string pieces exist. The key number defines the priority |
| 396 | + * of the type within parsing. The highest will be initialized last during the parser process. |
| 397 | + * |
| 398 | + * @return array |
| 399 | + */ |
| 400 | + public static function getRegisteredPieceTypes() { |
| 401 | + static $types = null; |
| 402 | + if( $types !== null ) { |
| 403 | + return $types; |
| 404 | + } |
| 405 | + |
| 406 | + $types = array(); |
| 407 | + |
| 408 | + foreach( static::pieceTypeRegistration() as $priority => $typeDef ) { |
| 409 | + $types[ $priority ] = is_array( $typeDef ) |
| 410 | + ? $typeDef[0] |
| 411 | + : $typeDef; |
| 412 | + } |
| 413 | + |
| 414 | + return $types; |
| 415 | + } |
| 416 | + |
| 417 | + /** |
| 418 | + * Returns all registered types in an array as keys and their public names as values. If a |
| 419 | + * registered type doesn't have a name, the type won't be in this list. |
| 420 | + * Use getRegisteredPieceTypes() for getting all types by priority instead. |
| 421 | + * |
| 422 | + * @return array |
| 423 | + */ |
| 424 | + public static function getRegisteredPieceTypeNames() { |
| 425 | + static $types = null; |
| 426 | + if( $types !== null ) { |
| 427 | + return $types; |
| 428 | + } |
| 429 | + |
| 430 | + $types = array(); |
| 431 | + |
| 432 | + foreach( static::pieceTypeRegistration() as $typeDef ) { |
| 433 | + if( is_array( $typeDef ) |
| 434 | + && ! empty( $typeDef[1] ) |
| 435 | + ) { |
| 436 | + $types[ $typeDef[0] ] = $typeDef[1]; |
| 437 | + } |
| 438 | + } |
| 439 | + |
| 440 | + return $types; |
| 441 | + } |
| 442 | + |
| 443 | + /** |
| 444 | + * Returns the class name of a certain registered piece type by the name it's been registered to |
| 445 | + * this class. Some types might not be registered by a name at all. |
| 446 | + * |
| 447 | + * @param name |
| 448 | + * |
| 449 | + * @return string|null piece type class name or null if there is no name identifier for it. |
| 450 | + */ |
| 451 | + public static function getRegisteredPieceTypeByName( $name ) { |
| 452 | + $types = static::getRegisteredPieceTypeNames(); |
| 453 | + $index = array_search( $name, $types ); |
| 454 | + if( $index !== false ) { |
| 455 | + return $index; // the index is the types class name |
| 456 | + } |
| 457 | + return null; |
| 458 | + } |
| 459 | + |
| 460 | + protected static function pieceTypeRegistration() { |
| 461 | + static $types = null; |
| 462 | + if( $types !== null ) { |
| 463 | + return $types; |
| 464 | + } |
| 465 | + |
| 466 | + $types = array( |
| 467 | + // key defines priority |
| 468 | + 0 => SEMEX_EXPR_PIECE_STRING, // will always be initialized since there is nothing to initialize |
| 469 | + 100 => array( SEMEX_EXPR_PIECE_WIKILINK, 'wikilink' ), |
| 470 | + 1000 => array( SEMEX_EXPR_PIECE_SQRESULT, 'shortqueryresult' ), |
| 471 | + 2000 => array( SEMEX_EXPR_PIECE_SQ, 'shortquery' ) |
| 472 | + ); |
| 473 | + |
| 474 | + // allow other extensions to handle further expressive string pieces |
| 475 | + wfRunHooks( __CLASS__ . 'PieceTypesRegistration' , array( &$types ) ); |
| 476 | + |
| 477 | + return $types; |
| 478 | + } |
| 479 | + |
| 480 | + /** |
| 481 | + * Takes an array with piece types as values and sets their keys according to the registered piece |
| 482 | + * types priorities. |
| 483 | + * |
| 484 | + * @param array $types |
| 485 | + * @return array |
| 486 | + */ |
| 487 | + protected static function injectPieceTypePriorities( array $types ) { |
| 488 | + $result = array(); |
| 489 | + // go through all registered types and check whether they are within the input array, |
| 490 | + // if so, include it with its original priority |
| 491 | + foreach( static::getRegisteredPieceTypes() as $priority => $type ) { |
| 492 | + if( array_search( $type, $types ) !== false ) { |
| 493 | + $result[ $priority ] = $type; |
| 494 | + } |
| 495 | + } |
| 496 | + return $result; |
| 497 | + } |
| 498 | + |
| 499 | + /** |
| 500 | + * Returns which types of expressive string pieces are enabled for this object. |
| 501 | + * This can differ from static::getRegisteredPieceTypes() if specified within the constructor. |
| 502 | + * |
| 503 | + * @return array |
| 504 | + */ |
| 505 | + public function getEnabledPieceTypes() { |
| 506 | + return $this->enabledPieceTypes; |
| 507 | + } |
| 508 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExExpressiveString.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 509 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExShortQueryResult.php |
— | — | @@ -0,0 +1,603 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class describing the result of a 'Semantic Expressiveness' short query. The result can be a |
| 6 | + * Semantic MediaWiki property value of a page or a abstract value in case the requested value |
| 7 | + * doesn't exist. |
| 8 | + * @ToDo: Expand this for having HTML output as well if required |
| 9 | + * |
| 10 | + * @since 0.1 |
| 11 | + * |
| 12 | + * @file SemExShortQueryResult.php |
| 13 | + * @ingroup SemanticExpressiveness |
| 14 | + * |
| 15 | + * @licence GNU GPL v3+ |
| 16 | + * @author Daniel Werner < danweetz@web.de > |
| 17 | + */ |
| 18 | +class SemExShortQueryResult { |
| 19 | + |
| 20 | + /** |
| 21 | + * @var SemExShortQuery |
| 22 | + */ |
| 23 | + protected $query; |
| 24 | + /** |
| 25 | + * @var Parser |
| 26 | + */ |
| 27 | + protected $parser; |
| 28 | + |
| 29 | + protected $errors = array(); |
| 30 | + protected $result = null; |
| 31 | + protected $source = false; // null means missing source, false means not yet datermined |
| 32 | + protected $sourceResult = null; // in case the source is another query, this is its cached result |
| 33 | + |
| 34 | + /** |
| 35 | + * Constructor |
| 36 | + * |
| 37 | + * @param SemExShortQuery $query the short query the result should be datermined for. Once a |
| 38 | + * result is datermined, the query itself must not be modified. |
| 39 | + * @param Parser $parser specifies the Parser context in which the result will be released as |
| 40 | + * a more human readable final output over various output functions of the object. |
| 41 | + * @param SMWDataItem[] $result optionally allows to pre-define the result. If not set, the |
| 42 | + * result of the query will be queried on demand. To start the query the result |
| 43 | + * immediately, getRawResult() can be called after construction. |
| 44 | + */ |
| 45 | + function __construct( SemExShortQuery $query, Parser $parser, $result = null ) { |
| 46 | + $this->query = $query; |
| 47 | + $this->parser = $parser; |
| 48 | + $this->result = $result; |
| 49 | + // we query the result on demand to save resources! |
| 50 | + } |
| 51 | + |
| 52 | + /** |
| 53 | + * Returns whether the result was datermined already. This is false if the result was not accessed |
| 54 | + * yet. This might be of interest if the object gets passed around and the context/time the actual |
| 55 | + * query process happens potentially influences the result. |
| 56 | + * |
| 57 | + * @return bool |
| 58 | + */ |
| 59 | + public function queryExecuted() { |
| 60 | + return $this->result !== null; |
| 61 | + } |
| 62 | + |
| 63 | + /** |
| 64 | + * Returns an SemExShortQueryAbstractResult object representing the same query. |
| 65 | + * |
| 66 | + * @return SemExShortQueryAbstractResult |
| 67 | + */ |
| 68 | + public function getAbstractResult() { |
| 69 | + return new SemExShortQueryAbstractResult( $this->query, $this->parser, $this->result ); |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * Returns the raw result as array of SMWDataItems. In case the source is not clearly |
| 74 | + * specified, this will return null. |
| 75 | + * |
| 76 | + * @param bool $forceRefresh if set to true, the result will be queried even though it was queried |
| 77 | + * before. Once queried, the result will be cached. |
| 78 | + * @return SMWDataItem[]|null |
| 79 | + */ |
| 80 | + public function getRawResult( $forceRefresh = false ) { |
| 81 | + if( ! $forceRefresh && $this->queryExecuted() ) { |
| 82 | + return $this->result; |
| 83 | + } |
| 84 | + |
| 85 | + $source = $this->getSource(); |
| 86 | + if( $source === null ) { |
| 87 | + return null; |
| 88 | + } |
| 89 | + |
| 90 | + $result = null; |
| 91 | + $subject = SMWDIWikiPage::newFromTitle( $source ); |
| 92 | + $property = $this->query->getProperty()->getDataItem(); |
| 93 | + |
| 94 | + // @ToDo: bad idea to use cache AND query, is the cache even needed after recent SMW changes? |
| 95 | + |
| 96 | + if( $this->query->getUseCache() |
| 97 | + && $source === $this->parser->getTitle() |
| 98 | + ) { |
| 99 | + // try to get data from current parser process: |
| 100 | + $output = $this->parser->getOutput(); |
| 101 | + |
| 102 | + // only possible if store is set for page yet: |
| 103 | + if( isset( $output->mSMWData ) ) { |
| 104 | + $result = $output->mSMWData->getPropertyValues( $property ); |
| 105 | + } |
| 106 | + } |
| 107 | + |
| 108 | + if( empty ( $result ) ) { |
| 109 | + // get the result from a defined SMW data store: |
| 110 | + $result = $this->query->getStore()->getPropertyValues( $subject, $property ); |
| 111 | + } |
| 112 | + |
| 113 | + $this->result = $result; |
| 114 | + return $result; |
| 115 | + } |
| 116 | + |
| 117 | + /** |
| 118 | + * Same as SemExShortQuery::getSource() except this will resolve 'by ref' and current page source |
| 119 | + * types. In case the source is an invalid 'by ref' source null will be returned. |
| 120 | + * |
| 121 | + * @return Title|null |
| 122 | + */ |
| 123 | + public function getSource() { |
| 124 | + if( $this->source !== false ) { |
| 125 | + return $this->source; |
| 126 | + } |
| 127 | + |
| 128 | + $q = $this->query; |
| 129 | + switch( $q->getSourceType() ) { |
| 130 | + case SemExShortQuery::SOURCE_IS_TITLE: |
| 131 | + $source = $q->getSource(); |
| 132 | + break; |
| 133 | + |
| 134 | + case SemExShortQuery::SOURCE_FROM_REF: |
| 135 | + // query the source properties value which is the actual source: |
| 136 | + $subQ = clone( $q ); // use same options for caching and store |
| 137 | + $subQ->setProperty( $q->getSource() ); |
| 138 | + $subQ->setSource( null ); // current page is source |
| 139 | + /* NO BREAK! */ |
| 140 | + |
| 141 | + case SemExShortQuery::SOURCE_IS_SHORTQUERY: |
| 142 | + if( ! isset( $subQ ) ) { |
| 143 | + $subQ = $q->getSource(); |
| 144 | + } |
| 145 | + $subQR = new self( $subQ, $this->parser ); |
| 146 | + $di = $subQR->getRawResult(); // returns all SMWDataItems |
| 147 | + $this->sourceResult = $subQR; // cache this extra |
| 148 | + |
| 149 | + if( ! empty( $di ) ) { |
| 150 | + if( count( $di > 1 ) ) { |
| 151 | + // There should only be one DataItem for a short query to make sense! |
| 152 | + $this->addError( 'semex-shortquery-error-byref-has-many-values' ); |
| 153 | + } |
| 154 | + $di = $di[0]; |
| 155 | + } else { |
| 156 | + $source = null; |
| 157 | + break; |
| 158 | + } |
| 159 | + |
| 160 | + if( $di->getDIType() !== SMWDataItem::TYPE_WIKIPAGE ) { |
| 161 | + // should be of type 'Page' to be a proper reference |
| 162 | + $this->addError( 'semex-shortquery-error-byref-has-wrong-type' ); |
| 163 | + $source = null; |
| 164 | + break; |
| 165 | + } |
| 166 | + $source = $di->getTitle(); |
| 167 | + break; |
| 168 | + |
| 169 | + case SemExShortQuery::SOURCE_IS_ESTRING: |
| 170 | + // expressive string as source, e.g. "<?a::<?b::c>>" |
| 171 | + $expressiveSrc = $q->getSource(); |
| 172 | + |
| 173 | + if( $expressiveSrc->hasUnresolvablePiece() ) { |
| 174 | + // e.g. in case of "<?a::<?b::c>>" whereas "c" doesn't exist. |
| 175 | + // in this case the whole query would be falsified |
| 176 | + $this->addError( 'semex-shortquery-error-failed-nested-queries' ); |
| 177 | + $source = null; |
| 178 | + } else { |
| 179 | + $source = Title::newFromText( $expressiveSrc->getRawText() ); |
| 180 | + } |
| 181 | + break; |
| 182 | + |
| 183 | + case SemExShortQuery::SOURCE_FROM_CONTEXT: |
| 184 | + $source = $this->parser->getTitle(); |
| 185 | + break; |
| 186 | + } |
| 187 | + |
| 188 | + $this->source = $source; |
| 189 | + return $source; |
| 190 | + } |
| 191 | + |
| 192 | + public function getQuery() { |
| 193 | + return $this->query; |
| 194 | + } |
| 195 | + |
| 196 | + public function getParser() { |
| 197 | + return $this->parser; |
| 198 | + } |
| 199 | + |
| 200 | + /** |
| 201 | + * Returns whether the short query has no result because the requests target page or the |
| 202 | + * requested property on that page do not exist. This is also true if the query definition |
| 203 | + * is faulty and prevents a proper query execution. |
| 204 | + * |
| 205 | + * @return bool |
| 206 | + */ |
| 207 | + public function isEmpty() { |
| 208 | + $result = $this->getRawResult(); |
| 209 | + return empty( $result ); |
| 210 | + } |
| 211 | + |
| 212 | + /** |
| 213 | + * Returns whether there have occurred errors of any kind wile processing the query. |
| 214 | + * Note that even though this can have some errors, it isn't automatically a failure. Check |
| 215 | + * isEmpty() to gain information about the queries success. |
| 216 | + * |
| 217 | + * @return bool |
| 218 | + */ |
| 219 | + public function hasErrors() { |
| 220 | + $errors = $this->getErrors(); |
| 221 | + return !empty( $errors ); |
| 222 | + } |
| 223 | + |
| 224 | + /** |
| 225 | + * Returns all errors occurred so far |
| 226 | + * |
| 227 | + * @return string[] |
| 228 | + */ |
| 229 | + public function getErrors() { |
| 230 | + $errors = $this->errors; |
| 231 | + if( $this->isEmpty() ) { |
| 232 | + // We don't use this message internally since its a ShortQuery feature to change output |
| 233 | + // in case this one occurs |
| 234 | + $errors = array_merge( array( 'semex-shortquery-error-missing-property' ), $errors ); |
| 235 | + } |
| 236 | + return $errors; |
| 237 | + } |
| 238 | + |
| 239 | + /** |
| 240 | + * This will add a new error or a set of error descriptions to the object. |
| 241 | + * |
| 242 | + * @param string|string[] addError |
| 243 | + */ |
| 244 | + protected function addError( $error ) { |
| 245 | + if( is_array( $error ) ) { |
| 246 | + $this->errors = array_merge( $this->errors, $error ); |
| 247 | + } else { |
| 248 | + $this->errors[] = $error; |
| 249 | + } |
| 250 | + } |
| 251 | + |
| 252 | + /** |
| 253 | + * Returns a string containing all error messages as a tooltip, or an empty string if no |
| 254 | + * errors occurred. |
| 255 | + * |
| 256 | + * @return string |
| 257 | + */ |
| 258 | + public function getErrorText() { |
| 259 | + return smwfEncodeMessages( $this->getErrors() ); |
| 260 | + } |
| 261 | + |
| 262 | + /** |
| 263 | + * Same as getErrorText() except this won't output the message about the requested property not |
| 264 | + * existing on the page. |
| 265 | + */ |
| 266 | + protected function getErrorTextForFormattedSQ() { |
| 267 | + smwfEncodeMessages( $this->errors ); |
| 268 | + } |
| 269 | + |
| 270 | + /** |
| 271 | + * Returns the result as unformatted plain text. In case the result consists of several data values, |
| 272 | + * all of them will be put together separated by a comma. |
| 273 | + * |
| 274 | + * @return string |
| 275 | + */ |
| 276 | + public function getRawText() { |
| 277 | + if( $this->isEmpty() ) { |
| 278 | + return ''; |
| 279 | + } |
| 280 | + $values = array(); |
| 281 | + foreach( $this->getRawResult() as $dataItem ) { |
| 282 | + $dataValue = SMWDataValueFactory::newDataItemValue( $dataItem, null ); |
| 283 | + $values[] = trim( $dataValue->getWikiValue() ); |
| 284 | + } |
| 285 | + return implode( ', ', $values ); |
| 286 | + } |
| 287 | + |
| 288 | + /** |
| 289 | + * Returns the result as a short wiki text representation without informational HTML markup, |
| 290 | + * even though it would be usable within wiki markup. |
| 291 | + * getWikiText() can be used to get the completely formatted wiki markup |
| 292 | + * |
| 293 | + * @param mixed $linked Allows one of |
| 294 | + * SemExShortQueryOutputOptions::LINK_NONE |
| 295 | + * SemExShortQueryOutputOptions::LINK_ALL |
| 296 | + * SemExShortQueryOutputOptions::LINK_TOPIC |
| 297 | + * @param bool $showErrors can be set to true to show errors. Off by default. |
| 298 | + * |
| 299 | + * @return string |
| 300 | + */ |
| 301 | + public function getShortWikiText( |
| 302 | + $linked = SemExShortQueryOutputOptions::LINK_ALL, |
| 303 | + $showErrors = false |
| 304 | + ) { |
| 305 | + if( $this->isEmpty() ) { |
| 306 | + return ''; |
| 307 | + } |
| 308 | + $values = array(); |
| 309 | + foreach( $this->getRawResult() as $dataItem ) { |
| 310 | + $dataValue = SMWDataValueFactory::newDataItemValue( $dataItem, null ); |
| 311 | + $values[] = trim( $dataValue->getShortWikiText( $linked === SemExShortQueryOutputOptions::LINK_ALL ) ); |
| 312 | + } |
| 313 | + $out = implode( ', ', $values ); |
| 314 | + |
| 315 | + if( $out !== '' && $linked === SemExShortQueryOutputOptions::LINK_TOPIC ) { |
| 316 | + // wrap whole result in one link to the source |
| 317 | + $topic = $this->getSource(); |
| 318 | + $out = "[[:{$topic}|{$out}]]"; |
| 319 | + } |
| 320 | + |
| 321 | + if( $showErrors ) { |
| 322 | + // show all errors, also the one saying property doesn't exist ($out === '') |
| 323 | + $out .= $this->getErrorText(); |
| 324 | + } |
| 325 | + |
| 326 | + return $out; |
| 327 | + } |
| 328 | + |
| 329 | + /** |
| 330 | + * Returns the full wiki text output with full markup, normally wrapped in some lightweight HTML |
| 331 | + * tags marked as successful Short Query. In case the query failed, there will be some similar |
| 332 | + * output with an abstract representation of the requested value. |
| 333 | + * In any case, the output will be including all information for later JavaScript processing or |
| 334 | + * use with '?to?!' parser function. |
| 335 | + * |
| 336 | + * @param mixed $linked Allows one of |
| 337 | + * SemExShortQueryOutputOptions::LINK_NONE |
| 338 | + * SemExShortQueryOutputOptions::LINK_ALL |
| 339 | + * SemExShortQueryOutputOptions::LINK_TOPIC |
| 340 | + * @param bool $showErrors |
| 341 | + * |
| 342 | + * @return string |
| 343 | + * |
| 344 | + * @todo: rename 'value' in 'rawResult' and 'abstractValue' in 'abstractResult' |
| 345 | + */ |
| 346 | + public function getWikiText( |
| 347 | + $linked = SemExShortQueryOutputOptions::LINK_ALL, |
| 348 | + $showErrors = true |
| 349 | + ) { |
| 350 | + return $this->getWikiText_internal( $linked, $showErrors, false ); |
| 351 | + } |
| 352 | + |
| 353 | + // $enforceAbstract parameter to reduce code in 'SemExShortQueryAbstractResult' sub-class |
| 354 | + protected function getWikiText_internal( $linked, $showErrors, $enforceAbstract = false ) { |
| 355 | + $out = ''; |
| 356 | + |
| 357 | + // if abstract is enforced, we won't query at all! |
| 358 | + $showAbstract = $enforceAbstract || $this->isEmpty(); |
| 359 | + $sqClasses = array( 'shortQuery' ); |
| 360 | + |
| 361 | + if( $showAbstract ) { |
| 362 | + $sqClasses[] = 'abstractShortQuery'; |
| 363 | + if( ! $enforceAbstract ) { |
| 364 | + $sqClasses[] = 'failedShortQuery'; |
| 365 | + } |
| 366 | + } |
| 367 | + |
| 368 | + $out .= HTML::openElement( 'span', array( 'class' => implode( ' ', $sqClasses ) ) ); |
| 369 | + |
| 370 | + // get all important information to re-create this object: |
| 371 | + $out .= $this->getSerialization(); |
| 372 | + |
| 373 | + if( ! $showAbstract ) { |
| 374 | + // data for formatted result: |
| 375 | + // ( can't quote this since it might contain html data! TODO: perhaps we could just strip this as HTML ) |
| 376 | + // ( this is a problem when using ?to?! having some invalid stuff in here for any reason ) |
| 377 | + $out .= HTML::rawElement( 'span', array( 'class' => 'result'), $this->getShortWikiText( $linked, $showErrors ) ); |
| 378 | + } |
| 379 | + else { |
| 380 | + $out .= $this->getAbstractResult()->getShortWikiText( $linked, $showErrors ); |
| 381 | + } |
| 382 | + |
| 383 | + if( $showErrors && !empty( $this->errors ) ) { |
| 384 | + // add errors, except the one saying that the whole thing is a failure: |
| 385 | + $out .= HTML::rawElement( 'span', array( 'class' => 'errors' ), $this->getErrorTextForFormattedSQ() ); |
| 386 | + } |
| 387 | + |
| 388 | + $out .= HTML::closeElement( 'span' ); |
| 389 | + return $out; |
| 390 | + } |
| 391 | + |
| 392 | + /** |
| 393 | + * Returns a serialized string optimazied for usage as WikiText or as HTML markup without actually |
| 394 | + * producing any visible output when used properly. |
| 395 | + * |
| 396 | + * @Note: This could be done nicer with HTML5 |
| 397 | + * |
| 398 | + * @return string |
| 399 | + */ |
| 400 | + public function getSerialization() { |
| 401 | + // query target page: |
| 402 | + $source = ( $this->getSource() === null ) ? '' : $this->getSource()->getPrefixedText(); |
| 403 | + $out = HTML::element( 'span', array( 'class' => 'source', 'title' => $source ) ); |
| 404 | + |
| 405 | + // queried property: |
| 406 | + $out .= HTML::element( 'span', array( 'class' => 'type', 'title' => $this->query->getProperty()->getDataItem()->getLabel() ) ); |
| 407 | + |
| 408 | + $storeName = $this->query->getStoreName(); |
| 409 | + if( $storeName !== '' ) { |
| 410 | + // only add information about store if default store not in use |
| 411 | + $out .= HTML::element( 'span', array( 'class' => 'storeSource', 'title' => $storeName ) ); |
| 412 | + } |
| 413 | + |
| 414 | + if( ! $this->isEmpty() ) { |
| 415 | + // data for raw result: |
| 416 | + $rawValues = ''; |
| 417 | + foreach( $this->getRawResult() as $dataItem ) { |
| 418 | + // separate all data values by putting them in their own span each |
| 419 | + $dataValue = SMWDataValueFactory::newDataItemValue( $dataItem, null ); |
| 420 | + $dataValue = trim( $dataValue->getWikiValue() ); |
| 421 | + $rawValues .= HTML::element( 'span', array( 'title' => $dataValue ) ); |
| 422 | + /* |
| 423 | + * @ToDo: FIXME: Might be a good idea to simply use DataItem default serialization, |
| 424 | + * on the other hand, this would be kind of useless for JavaScript. |
| 425 | + */ |
| 426 | + } |
| 427 | + $out .= HTML::rawElement( 'span', array( 'class' => 'value' ), $rawValues ); |
| 428 | + } |
| 429 | + |
| 430 | + return $out; |
| 431 | + } |
| 432 | + |
| 433 | + /** |
| 434 | + * Returns the output in a pre-defined exactly specified way by a SemExShortQueryResultOptions |
| 435 | + * object. |
| 436 | + * |
| 437 | + * @ToDo: implement SemExShortQueryOutputOptions::getFormat() if required |
| 438 | + * |
| 439 | + * @return string |
| 440 | + */ |
| 441 | + public function getOutput( SemExShortQueryOutputOptions $options ) { |
| 442 | + $useRaw = $options->getFormat() === SemExShortQueryOutputOptions::FORMAT_RAW; |
| 443 | + $showInfo = $options->getShowInfo(); |
| 444 | + $linked = $options->getLink(); |
| 445 | + $errors = $options->getShowErrors(); |
| 446 | + $abstract = $options->getShowAbstract(); |
| 447 | + |
| 448 | + if( $abstract === SemExShortQueryOutputOptions::NO_ABSTRACT |
| 449 | + && $this->isEmpty() |
| 450 | + ) { |
| 451 | + // don't display abstract values, so nothing to display except... |
| 452 | + if( $errors && !$useRaw ) { |
| 453 | + // ...display errors at least, including information why this "failed" |
| 454 | + return $this->getErrorText(); |
| 455 | + } else { |
| 456 | + return ''; |
| 457 | + } |
| 458 | + } |
| 459 | + |
| 460 | + // if only abstract info is required, get this results abstract representation |
| 461 | + $abstractInUse = |
| 462 | + $abstract === SemExShortQueryOutputOptions::ABSTRACT_ONLY |
| 463 | + || ( $this->isEmpty() && $abstract === SemExShortQueryOutputOptions::ABSTRACT_IF_FAILURE ); |
| 464 | + |
| 465 | + $result = $abstractInUse |
| 466 | + ? $this->getAbstractResult() |
| 467 | + : $this; |
| 468 | + |
| 469 | + if( $useRaw ) { |
| 470 | + return ( $result->getRawText() ); |
| 471 | + } |
| 472 | + |
| 473 | + if( $showInfo ) { |
| 474 | + // output result wrapped with max markup and information |
| 475 | + return $result->getWikiText( $linked, $errors ); |
| 476 | + } |
| 477 | + else { |
| 478 | + // light version |
| 479 | + return $result->getShortWikiText( $linked, $errors ); |
| 480 | + } |
| 481 | + } |
| 482 | + |
| 483 | + /** |
| 484 | + * Factory function to get an existing result from its full wiki or HTML output by reading the |
| 485 | + * produced tag information. |
| 486 | + * |
| 487 | + * @param DOMNode $node |
| 488 | + * @param Parser $parser |
| 489 | + * @param bool $refreshData whether the result should be re-queried even though the original result |
| 490 | + * is available from the given DOM information. |
| 491 | + * |
| 492 | + * @return SemExShortQueryResult |
| 493 | + */ |
| 494 | + public static function newFromDOM( DOMNode $node, Parser $parser, $refreshData = false ) { |
| 495 | + $prop = self::extractInfoFromDOM( $node, 'type' ); |
| 496 | + $source = self::extractInfoFromDOM( $node, 'source' ); |
| 497 | + |
| 498 | + if( $prop === null || $source === null ) { |
| 499 | + // ERROR |
| 500 | + throw new SemExShortQueryResultException( 'Insufficient input data.' ); |
| 501 | + } |
| 502 | + |
| 503 | + $origQuery = SemExShortQuery::newFromParamsArray( array( |
| 504 | + 'property' => $prop, |
| 505 | + 'from' => $source, |
| 506 | + 'source' => self::extractInfoFromDOM( $node, 'storeSource' ), |
| 507 | + ) ); |
| 508 | + |
| 509 | + $result = null; |
| 510 | + |
| 511 | + if( ! $refreshData ) { |
| 512 | + $result = array(); |
| 513 | + |
| 514 | + // fill result from DOM information: |
| 515 | + $origResultContainer = self::extractInfoFromDOM( $node, 'value', true ); |
| 516 | + |
| 517 | + if( $origResultContainer->hasChildNodes() ) { |
| 518 | + $propDi = $origQuery->getProperty()->getDataItem(); |
| 519 | + |
| 520 | + // each DataValue inside its own <span title="data" /> |
| 521 | + foreach( $origResultContainer->child_nodes() as $resultNode ) { |
| 522 | + if( ! $resultNode->hasAttributes() ) { |
| 523 | + continue; |
| 524 | + } |
| 525 | + $result = trim( $resultNode->attributes->getNamedItem( 'title' ) ); |
| 526 | + if( $result === '' ) { |
| 527 | + continue; |
| 528 | + } |
| 529 | + $sqResult->result[] = SMWDataValueFactory::newPropertyObjectValue( |
| 530 | + $propDi, $result, $caption |
| 531 | + ); |
| 532 | + } |
| 533 | + } |
| 534 | + } |
| 535 | + |
| 536 | + return new self( $origQuery, $parser, $result ); |
| 537 | + } |
| 538 | + |
| 539 | + /** |
| 540 | + * Creates a new SemExShortQueryResult from a serialized string given by |
| 541 | + * SemExShortQueryResult::getSerialization(). |
| 542 | + * |
| 543 | + * @param string $serialization |
| 544 | + * @param Parser $parser |
| 545 | + * |
| 546 | + * @return SemExShortQueryResult |
| 547 | + */ |
| 548 | + public static function newFromSerialization( $serialization, Parser $parser ) { |
| 549 | + $strHtml = "<body>$serialization</body>"; |
| 550 | + |
| 551 | + $xmlDoc = new DOMDocument(); |
| 552 | + $xmlDoc->strictErrorChecking = false; |
| 553 | + |
| 554 | + wfSuppressWarnings(); |
| 555 | + $validDom = $xmlDoc->loadXML( $part ); |
| 556 | + wfRestoreWarnings(); |
| 557 | + |
| 558 | + if( ! $validDom ) { |
| 559 | + // ERROR |
| 560 | + throw new SemExShortQueryResultException( "Invalid serialized string '$serialization' given." ); |
| 561 | + } |
| 562 | + |
| 563 | + return SemExShortQueryResult::newFromDOM( $xmlDoc->documentElement, $parser ); |
| 564 | + } |
| 565 | + |
| 566 | + /** |
| 567 | + * Helper for getting information about the short query result from its DOM representation. |
| 568 | + * |
| 569 | + * @param DOMNode $node |
| 570 | + * @param string $info |
| 571 | + * @param bool $getNode if set to true, this will return the DOMNode containing the |
| 572 | + * requested information instead of just returning the 'title' attribute content. |
| 573 | + * |
| 574 | + * @return string|DOMNodeList|null |
| 575 | + */ |
| 576 | + protected static function extractInfoFromDOM( DOMNode $node, $info, $getNode = false ) { |
| 577 | + if( ! $node->hasChildNodes() ) { |
| 578 | + return null; |
| 579 | + } |
| 580 | + $xpath = new DOMXpath( $node ); |
| 581 | + $nodes = $xpath->query( "/*/*[@class=\"{$info}\"][@title][1]" ); |
| 582 | + |
| 583 | + if( $nodes->length < 1 ) { |
| 584 | + return null; |
| 585 | + } |
| 586 | + |
| 587 | + $node = $nodes->item( 0 ); |
| 588 | + if( $getNode ) { |
| 589 | + return $node; |
| 590 | + } |
| 591 | + |
| 592 | + $result = trim( $node->attributes->getNamedItem( 'title' ) ); |
| 593 | + if( $result === '' ) { |
| 594 | + return null; |
| 595 | + } |
| 596 | + return $result; |
| 597 | + } |
| 598 | +} |
| 599 | + |
| 600 | +/** |
| 601 | + * Exception to be thrown when short query result creation fails due to bad input. |
| 602 | + */ |
| 603 | +class SemExShortQueryResultException extends MWException { |
| 604 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExShortQueryResult.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 605 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExShortQuery.php |
— | — | @@ -0,0 +1,230 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Class describing a 'Semantic Expressiveness' short query. |
| 6 | + * SemExShortQueryProcessor::getResultFromQuery() can be used to get a short queries result. |
| 7 | + * |
| 8 | + * @since 0.1 |
| 9 | + * |
| 10 | + * @file SemExShortQuery.php |
| 11 | + * @ingroup SemanticExpressiveness |
| 12 | + * |
| 13 | + * @author Daniel Werner < danweetz@web.de > |
| 14 | + */ |
| 15 | +class SemExShortQuery extends SemExPFParamsBasedFactory { |
| 16 | + |
| 17 | + protected static $pfParamsValidatorElement = 'SemEx Short Query'; |
| 18 | + |
| 19 | + protected $property; |
| 20 | + protected $source; |
| 21 | + protected $store = null; |
| 22 | + protected $useCache = true; |
| 23 | + |
| 24 | + const SOURCE_IS_TITLE = 1; |
| 25 | + const SOURCE_FROM_CONTEXT = 2; // source from current page (depending on Parser object) |
| 26 | + const SOURCE_FROM_REF = 3; // source from another property of the current page |
| 27 | + const SOURCE_IS_SHORTQUERY = 4; |
| 28 | + const SOURCE_IS_ESTRING = 5; // ESTRING = ExpressiveString |
| 29 | + |
| 30 | + /** |
| 31 | + * Constructor |
| 32 | + * |
| 33 | + * @param SMWPropertyValue $property the property which should be queried |
| 34 | + * @param Title|SMWPropertyValue|SemExExpressiveString|null where the property should be queried from. |
| 35 | + * See setSource() for details. |
| 36 | + */ |
| 37 | + public function __construct( SMWPropertyValue $property, $source = null ) { |
| 38 | + $this->property = $property; |
| 39 | + $this->source = $source; // null implies current page |
| 40 | + } |
| 41 | + |
| 42 | + /** |
| 43 | + * Sets the source from where a specific property should be queried from. This can consist of different |
| 44 | + * types of values. The possible types and their meanings: |
| 45 | + * Title: The titles will be searched for the source property. |
| 46 | + * SMWPropertyValue: SMW property which should be of type 'Page'. In that case the current pages |
| 47 | + * property value will be taken as source for the query. |
| 48 | + * SemExShortQuery: The result of another short query is taken as source. |
| 49 | + * SemExExpressiveString: Source is a expressive string which can contain further short queries. This |
| 50 | + * makes the short query highly expressive as it's possible to trace the source |
| 51 | + * of what should be queried. |
| 52 | + * null: implies that the property should be queried from the query processors current |
| 53 | + * context page. |
| 54 | + * |
| 55 | + * @param Title|SMWPropertyValue|SemExShortQuery|SemExExpressiveString|null $source |
| 56 | + */ |
| 57 | + public function setSource( $source ) { |
| 58 | + $this->source = $source; |
| 59 | + } |
| 60 | + |
| 61 | + /** |
| 62 | + * Returns the source the specific property should be queried from. |
| 63 | + * @return Title|SMWPropertyValue|SemExExpressiveString|null |
| 64 | + */ |
| 65 | + public function getSource() { |
| 66 | + return $this->source; |
| 67 | + } |
| 68 | + |
| 69 | + /** |
| 70 | + * Returns the kind of source the query will get the requested property from. the following types |
| 71 | + * are possible: |
| 72 | + * |
| 73 | + * self::SOURCE_IS_TITLE - Implies that the property will be taken from a certain page |
| 74 | + * self::SOURCE_FROM_REF - Implies that the property will be taken from a page where another |
| 75 | + * property on the queries context page refers to. |
| 76 | + * self::SOURCE_FROM_CONTEXT - Implies that the property will be taken from the page where the |
| 77 | + * query is defined at. |
| 78 | + * self::SOURCE_IS_ESTRING - Implies that the property will be taken from an expressive string, |
| 79 | + * possibly containing further short queries. |
| 80 | + * self::SOURCE_IS_SHORTQUERY - Implies that the property will be taken from the result of another |
| 81 | + * short query. |
| 82 | + * |
| 83 | + * @return boolean |
| 84 | + */ |
| 85 | + public function getSourceType() { |
| 86 | + if( $this->source === null ) { |
| 87 | + return self::SOURCE_FROM_CONTEXT; |
| 88 | + } |
| 89 | + if( $this->source instanceof SMWPropertyValue ) { |
| 90 | + return self::SOURCE_FROM_REF; |
| 91 | + } |
| 92 | + if( $this->source instanceof self ) { |
| 93 | + return self::SOURCE_IS_SHORTQUERY; |
| 94 | + } |
| 95 | + if( $this->source instanceof SemExExpressiveString ) { |
| 96 | + return self::SOURCE_IS_ESTRING; |
| 97 | + } |
| 98 | + return self::SOURCE_IS_TITLE; |
| 99 | + } |
| 100 | + |
| 101 | + /** |
| 102 | + * Function to define for which property should be queried. |
| 103 | + * @param SMWPropertyValue $property |
| 104 | + */ |
| 105 | + public function setProperty( SMWPropertyValue $property ) { |
| 106 | + $this->property = $property; |
| 107 | + } |
| 108 | + |
| 109 | + /** |
| 110 | + * Returns the property for which the query is asking. |
| 111 | + * @return SMWPropertyValue |
| 112 | + */ |
| 113 | + public function getProperty() { |
| 114 | + return $this->property; |
| 115 | + } |
| 116 | + |
| 117 | + /** |
| 118 | + * Defines whether queries having the same source as the page they are defined on should |
| 119 | + * consider properties collected during the page rendering which are not stored within the |
| 120 | + * database yet. |
| 121 | + * |
| 122 | + * @param bool $val |
| 123 | + * @return bool previous value |
| 124 | + */ |
| 125 | + public function setUseCache( $val ) { |
| 126 | + return wfSetVar( $this->useCache, $val ); |
| 127 | + } |
| 128 | + |
| 129 | + /** |
| 130 | + * @see SemExShortQuery::setUseCache() |
| 131 | + * @return bool |
| 132 | + */ |
| 133 | + public function getUseCache() { |
| 134 | + return $this->useCache; |
| 135 | + } |
| 136 | + |
| 137 | + /** |
| 138 | + * Sets the Store which should be the source for the query. |
| 139 | + * Consider that depending on the cache option, the store won't even have an effect. |
| 140 | + * |
| 141 | + * @param SMWStore $val |
| 142 | + * @return SMWStore |
| 143 | + */ |
| 144 | + public function setStore( SMWStore $val ) { |
| 145 | + return wfSetVar( $this->store, $val ); |
| 146 | + } |
| 147 | + |
| 148 | + /** |
| 149 | + * @see SemExShortQuery::setStore() |
| 150 | + * @return SMWStore |
| 151 | + */ |
| 152 | + public function getStore() { |
| 153 | + if( $this->store === null ) { |
| 154 | + $this->store = smwfGetStore(); |
| 155 | + } |
| 156 | + return $this->store; |
| 157 | + } |
| 158 | + |
| 159 | + /** |
| 160 | + * Returns the associated store name which identifies the store within $smwgQuerySources |
| 161 | + * A empty string refers to the default store. Returns false in case the store in use is |
| 162 | + * not known to $smwgQuerySources (which should not happen normally) |
| 163 | + * |
| 164 | + * @return string|false |
| 165 | + */ |
| 166 | + public function getStoreName() { |
| 167 | + if( $this->store === null |
| 168 | + || $this->store === smwfGetStore() |
| 169 | + ) { |
| 170 | + return ''; // default store |
| 171 | + } |
| 172 | + |
| 173 | + global $smwgQuerySources; |
| 174 | + |
| 175 | + $storeClass = get_class( $this->store ); |
| 176 | + $index = array_search( $storeClass, $smwgQuerySources ); // false if unknown |
| 177 | + |
| 178 | + return $index; |
| 179 | + } |
| 180 | + |
| 181 | + /** |
| 182 | + * @see SemExPFParamsBasedFactory::newFromValidatedParams() |
| 183 | + */ |
| 184 | + public static function newFromValidatedParams( array $params ) { |
| 185 | + $query = new self( $params['property'] ); |
| 186 | + |
| 187 | + if( $params['from ref'] ) { |
| 188 | + $query->setSource( $params['from ref'] ); |
| 189 | + } |
| 190 | + elseif( $params['from'] ) { |
| 191 | + $query->setSource( $params['from'] ); |
| 192 | + } |
| 193 | + |
| 194 | + $query->setUseCache( $params['cache'] ); |
| 195 | + $query->setStore( $params['source'] ); |
| 196 | + |
| 197 | + return $query; |
| 198 | + } |
| 199 | + |
| 200 | + /** |
| 201 | + * Returns a description of all allowed function Parameters representing a SemExShortQuery. |
| 202 | + */ |
| 203 | + public static function getPFParams() { |
| 204 | + $params = array(); |
| 205 | + |
| 206 | + $params['property'] = new Parameter( 'property' ); |
| 207 | + $params['property']->addCriteria( new SemExCriterionIsProperty() ); |
| 208 | + $params['property']->addManipulations( new SemExParamManipulationProperty() ); |
| 209 | + |
| 210 | + $params['from'] = new Parameter( 'from', Parameter::TYPE_TITLE ); |
| 211 | + $params['from']->setDefault( false, false ); |
| 212 | + |
| 213 | + $params['from ref'] = new Parameter( 'from ref' ); |
| 214 | + $params['from ref']->addCriteria( // only allow properties of type 'Page' for this! |
| 215 | + new SemExCriterionIsProperty( '_wpg' ) |
| 216 | + ); |
| 217 | + $params['from ref']->addManipulations( new SemExParamManipulationProperty() ); |
| 218 | + $params['from ref']->setDefault( false, false ); |
| 219 | + |
| 220 | + $params['cache'] = new Parameter( 'cache', Parameter::TYPE_BOOLEAN ); |
| 221 | + $params['cache']->setDefault( true ); |
| 222 | + |
| 223 | + // this has nothing to do with set/getSource but delivers the value for set/getStore: |
| 224 | + $params['source'] = new Parameter( 'source' ); |
| 225 | + $params['source']->addCriteria( new SemExCriterionIsQuerySource() ); |
| 226 | + $params['source']->addManipulations( new SemExParamManipulationQuerySource() ); |
| 227 | + $params['source']->setDefault( smwfGetStore(), false ); |
| 228 | + |
| 229 | + return $params; |
| 230 | + } |
| 231 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExShortQuery.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 232 | + native |
Index: trunk/extensions/SemanticExpressiveness/includes/SemExShortQueryProcessor.php |
— | — | @@ -0,0 +1,60 @@ |
| 2 | +<?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Factory class to generate and execute 'Semantic Expressiveness' short queries and return their |
| 6 | + * result as SemExShortQueryResult object or in directly in a serialized form. |
| 7 | + * |
| 8 | + * @since 0.1 |
| 9 | + * |
| 10 | + * @file SemExShortQueryProcessor.php |
| 11 | + * @ingroup SemanticExpressiveness |
| 12 | + * |
| 13 | + * @author Daniel Werner < danweetz@web.de > |
| 14 | + */ |
| 15 | +class SemExShortQueryProcessor { |
| 16 | + |
| 17 | + /** |
| 18 | + * Processes a 'Semantic Expressiveness' Short Qery as given by an array of parameters as usually |
| 19 | + * given by the '?' and '?!' parser functions. |
| 20 | + * |
| 21 | + * @param parser Parser |
| 22 | + * @param rawParams array unprocessed parameters |
| 23 | + * |
| 24 | + * @return array |
| 25 | + */ |
| 26 | + public static function getResultFromFunctionParams( Parser $parser, array $rawParams ) { |
| 27 | + |
| 28 | + $query = SemExShortQuery::newFromPFParams( $rawParams ); |
| 29 | + $options = SemExShortQueryOutputOptions::newFromPFParams( $rawParams ); |
| 30 | + |
| 31 | + // @ToDo: Check for validation errors at some point |
| 32 | + |
| 33 | + return self::getResultFromQuery( $parser, $query, $options ); |
| 34 | + } |
| 35 | + |
| 36 | + /** |
| 37 | + * Processes a 'Semantic Expressiveness' Short Query and returns the result which can contain |
| 38 | + * either a valid result or an abstract value. |
| 39 | + * Optionally there can be a SemExShortQueryResultOptions object passed to retain a certain |
| 40 | + * kind of output from the short query. |
| 41 | + * |
| 42 | + * @param Parser $parser |
| 43 | + * @param SemExShortQuery $query |
| 44 | + * @param SemExShortQueryOutputOptions $options |
| 45 | + * |
| 46 | + * @return SemExShortQueryResult|String |
| 47 | + */ |
| 48 | + public static function getResultFromQuery( |
| 49 | + Parser $parser, |
| 50 | + SemExShortQuery $query, |
| 51 | + $options = null |
| 52 | + ) { |
| 53 | + $result = new SemExShortQueryResult( $query, $parser ); |
| 54 | + |
| 55 | + if( $options !== null ) { |
| 56 | + return $result->getOutput( $options ); |
| 57 | + } |
| 58 | + |
| 59 | + return $result; |
| 60 | + } |
| 61 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/includes/SemExShortQueryProcessor.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 62 | + native |
Index: trunk/extensions/SemanticExpressiveness/COPYING |
— | — | @@ -0,0 +1,679 @@ |
| 2 | +Semantic Expressiveness
|
| 3 | +Copyright (C) 2012 by Daniel Werner
|
| 4 | +
|
| 5 | +The license text below "----" applies to all files within this distribution
|
| 6 | +----
|
| 7 | + GNU GENERAL PUBLIC LICENSE
|
| 8 | + Version 3, 29 June 2007
|
| 9 | +
|
| 10 | + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
| 11 | + Everyone is permitted to copy and distribute verbatim copies
|
| 12 | + of this license document, but changing it is not allowed.
|
| 13 | +
|
| 14 | + Preamble
|
| 15 | +
|
| 16 | + The GNU General Public License is a free, copyleft license for
|
| 17 | +software and other kinds of works.
|
| 18 | +
|
| 19 | + The licenses for most software and other practical works are designed
|
| 20 | +to take away your freedom to share and change the works. By contrast,
|
| 21 | +the GNU General Public License is intended to guarantee your freedom to
|
| 22 | +share and change all versions of a program--to make sure it remains free
|
| 23 | +software for all its users. We, the Free Software Foundation, use the
|
| 24 | +GNU General Public License for most of our software; it applies also to
|
| 25 | +any other work released this way by its authors. You can apply it to
|
| 26 | +your programs, too.
|
| 27 | +
|
| 28 | + When we speak of free software, we are referring to freedom, not
|
| 29 | +price. Our General Public Licenses are designed to make sure that you
|
| 30 | +have the freedom to distribute copies of free software (and charge for
|
| 31 | +them if you wish), that you receive source code or can get it if you
|
| 32 | +want it, that you can change the software or use pieces of it in new
|
| 33 | +free programs, and that you know you can do these things.
|
| 34 | +
|
| 35 | + To protect your rights, we need to prevent others from denying you
|
| 36 | +these rights or asking you to surrender the rights. Therefore, you have
|
| 37 | +certain responsibilities if you distribute copies of the software, or if
|
| 38 | +you modify it: responsibilities to respect the freedom of others.
|
| 39 | +
|
| 40 | + For example, if you distribute copies of such a program, whether
|
| 41 | +gratis or for a fee, you must pass on to the recipients the same
|
| 42 | +freedoms that you received. You must make sure that they, too, receive
|
| 43 | +or can get the source code. And you must show them these terms so they
|
| 44 | +know their rights.
|
| 45 | +
|
| 46 | + Developers that use the GNU GPL protect your rights with two steps:
|
| 47 | +(1) assert copyright on the software, and (2) offer you this License
|
| 48 | +giving you legal permission to copy, distribute and/or modify it.
|
| 49 | +
|
| 50 | + For the developers' and authors' protection, the GPL clearly explains
|
| 51 | +that there is no warranty for this free software. For both users' and
|
| 52 | +authors' sake, the GPL requires that modified versions be marked as
|
| 53 | +changed, so that their problems will not be attributed erroneously to
|
| 54 | +authors of previous versions.
|
| 55 | +
|
| 56 | + Some devices are designed to deny users access to install or run
|
| 57 | +modified versions of the software inside them, although the manufacturer
|
| 58 | +can do so. This is fundamentally incompatible with the aim of
|
| 59 | +protecting users' freedom to change the software. The systematic
|
| 60 | +pattern of such abuse occurs in the area of products for individuals to
|
| 61 | +use, which is precisely where it is most unacceptable. Therefore, we
|
| 62 | +have designed this version of the GPL to prohibit the practice for those
|
| 63 | +products. If such problems arise substantially in other domains, we
|
| 64 | +stand ready to extend this provision to those domains in future versions
|
| 65 | +of the GPL, as needed to protect the freedom of users.
|
| 66 | +
|
| 67 | + Finally, every program is threatened constantly by software patents.
|
| 68 | +States should not allow patents to restrict development and use of
|
| 69 | +software on general-purpose computers, but in those that do, we wish to
|
| 70 | +avoid the special danger that patents applied to a free program could
|
| 71 | +make it effectively proprietary. To prevent this, the GPL assures that
|
| 72 | +patents cannot be used to render the program non-free.
|
| 73 | +
|
| 74 | + The precise terms and conditions for copying, distribution and
|
| 75 | +modification follow.
|
| 76 | +
|
| 77 | + TERMS AND CONDITIONS
|
| 78 | +
|
| 79 | + 0. Definitions.
|
| 80 | +
|
| 81 | + "This License" refers to version 3 of the GNU General Public License.
|
| 82 | +
|
| 83 | + "Copyright" also means copyright-like laws that apply to other kinds of
|
| 84 | +works, such as semiconductor masks.
|
| 85 | +
|
| 86 | + "The Program" refers to any copyrightable work licensed under this
|
| 87 | +License. Each licensee is addressed as "you". "Licensees" and
|
| 88 | +"recipients" may be individuals or organizations.
|
| 89 | +
|
| 90 | + To "modify" a work means to copy from or adapt all or part of the work
|
| 91 | +in a fashion requiring copyright permission, other than the making of an
|
| 92 | +exact copy. The resulting work is called a "modified version" of the
|
| 93 | +earlier work or a work "based on" the earlier work.
|
| 94 | +
|
| 95 | + A "covered work" means either the unmodified Program or a work based
|
| 96 | +on the Program.
|
| 97 | +
|
| 98 | + To "propagate" a work means to do anything with it that, without
|
| 99 | +permission, would make you directly or secondarily liable for
|
| 100 | +infringement under applicable copyright law, except executing it on a
|
| 101 | +computer or modifying a private copy. Propagation includes copying,
|
| 102 | +distribution (with or without modification), making available to the
|
| 103 | +public, and in some countries other activities as well.
|
| 104 | +
|
| 105 | + To "convey" a work means any kind of propagation that enables other
|
| 106 | +parties to make or receive copies. Mere interaction with a user through
|
| 107 | +a computer network, with no transfer of a copy, is not conveying.
|
| 108 | +
|
| 109 | + An interactive user interface displays "Appropriate Legal Notices"
|
| 110 | +to the extent that it includes a convenient and prominently visible
|
| 111 | +feature that (1) displays an appropriate copyright notice, and (2)
|
| 112 | +tells the user that there is no warranty for the work (except to the
|
| 113 | +extent that warranties are provided), that licensees may convey the
|
| 114 | +work under this License, and how to view a copy of this License. If
|
| 115 | +the interface presents a list of user commands or options, such as a
|
| 116 | +menu, a prominent item in the list meets this criterion.
|
| 117 | +
|
| 118 | + 1. Source Code.
|
| 119 | +
|
| 120 | + The "source code" for a work means the preferred form of the work
|
| 121 | +for making modifications to it. "Object code" means any non-source
|
| 122 | +form of a work.
|
| 123 | +
|
| 124 | + A "Standard Interface" means an interface that either is an official
|
| 125 | +standard defined by a recognized standards body, or, in the case of
|
| 126 | +interfaces specified for a particular programming language, one that
|
| 127 | +is widely used among developers working in that language.
|
| 128 | +
|
| 129 | + The "System Libraries" of an executable work include anything, other
|
| 130 | +than the work as a whole, that (a) is included in the normal form of
|
| 131 | +packaging a Major Component, but which is not part of that Major
|
| 132 | +Component, and (b) serves only to enable use of the work with that
|
| 133 | +Major Component, or to implement a Standard Interface for which an
|
| 134 | +implementation is available to the public in source code form. A
|
| 135 | +"Major Component", in this context, means a major essential component
|
| 136 | +(kernel, window system, and so on) of the specific operating system
|
| 137 | +(if any) on which the executable work runs, or a compiler used to
|
| 138 | +produce the work, or an object code interpreter used to run it.
|
| 139 | +
|
| 140 | + The "Corresponding Source" for a work in object code form means all
|
| 141 | +the source code needed to generate, install, and (for an executable
|
| 142 | +work) run the object code and to modify the work, including scripts to
|
| 143 | +control those activities. However, it does not include the work's
|
| 144 | +System Libraries, or general-purpose tools or generally available free
|
| 145 | +programs which are used unmodified in performing those activities but
|
| 146 | +which are not part of the work. For example, Corresponding Source
|
| 147 | +includes interface definition files associated with source files for
|
| 148 | +the work, and the source code for shared libraries and dynamically
|
| 149 | +linked subprograms that the work is specifically designed to require,
|
| 150 | +such as by intimate data communication or control flow between those
|
| 151 | +subprograms and other parts of the work.
|
| 152 | +
|
| 153 | + The Corresponding Source need not include anything that users
|
| 154 | +can regenerate automatically from other parts of the Corresponding
|
| 155 | +Source.
|
| 156 | +
|
| 157 | + The Corresponding Source for a work in source code form is that
|
| 158 | +same work.
|
| 159 | +
|
| 160 | + 2. Basic Permissions.
|
| 161 | +
|
| 162 | + All rights granted under this License are granted for the term of
|
| 163 | +copyright on the Program, and are irrevocable provided the stated
|
| 164 | +conditions are met. This License explicitly affirms your unlimited
|
| 165 | +permission to run the unmodified Program. The output from running a
|
| 166 | +covered work is covered by this License only if the output, given its
|
| 167 | +content, constitutes a covered work. This License acknowledges your
|
| 168 | +rights of fair use or other equivalent, as provided by copyright law.
|
| 169 | +
|
| 170 | + You may make, run and propagate covered works that you do not
|
| 171 | +convey, without conditions so long as your license otherwise remains
|
| 172 | +in force. You may convey covered works to others for the sole purpose
|
| 173 | +of having them make modifications exclusively for you, or provide you
|
| 174 | +with facilities for running those works, provided that you comply with
|
| 175 | +the terms of this License in conveying all material for which you do
|
| 176 | +not control copyright. Those thus making or running the covered works
|
| 177 | +for you must do so exclusively on your behalf, under your direction
|
| 178 | +and control, on terms that prohibit them from making any copies of
|
| 179 | +your copyrighted material outside their relationship with you.
|
| 180 | +
|
| 181 | + Conveying under any other circumstances is permitted solely under
|
| 182 | +the conditions stated below. Sublicensing is not allowed; section 10
|
| 183 | +makes it unnecessary.
|
| 184 | +
|
| 185 | + 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
| 186 | +
|
| 187 | + No covered work shall be deemed part of an effective technological
|
| 188 | +measure under any applicable law fulfilling obligations under article
|
| 189 | +11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
| 190 | +similar laws prohibiting or restricting circumvention of such
|
| 191 | +measures.
|
| 192 | +
|
| 193 | + When you convey a covered work, you waive any legal power to forbid
|
| 194 | +circumvention of technological measures to the extent such circumvention
|
| 195 | +is effected by exercising rights under this License with respect to
|
| 196 | +the covered work, and you disclaim any intention to limit operation or
|
| 197 | +modification of the work as a means of enforcing, against the work's
|
| 198 | +users, your or third parties' legal rights to forbid circumvention of
|
| 199 | +technological measures.
|
| 200 | +
|
| 201 | + 4. Conveying Verbatim Copies.
|
| 202 | +
|
| 203 | + You may convey verbatim copies of the Program's source code as you
|
| 204 | +receive it, in any medium, provided that you conspicuously and
|
| 205 | +appropriately publish on each copy an appropriate copyright notice;
|
| 206 | +keep intact all notices stating that this License and any
|
| 207 | +non-permissive terms added in accord with section 7 apply to the code;
|
| 208 | +keep intact all notices of the absence of any warranty; and give all
|
| 209 | +recipients a copy of this License along with the Program.
|
| 210 | +
|
| 211 | + You may charge any price or no price for each copy that you convey,
|
| 212 | +and you may offer support or warranty protection for a fee.
|
| 213 | +
|
| 214 | + 5. Conveying Modified Source Versions.
|
| 215 | +
|
| 216 | + You may convey a work based on the Program, or the modifications to
|
| 217 | +produce it from the Program, in the form of source code under the
|
| 218 | +terms of section 4, provided that you also meet all of these conditions:
|
| 219 | +
|
| 220 | + a) The work must carry prominent notices stating that you modified
|
| 221 | + it, and giving a relevant date.
|
| 222 | +
|
| 223 | + b) The work must carry prominent notices stating that it is
|
| 224 | + released under this License and any conditions added under section
|
| 225 | + 7. This requirement modifies the requirement in section 4 to
|
| 226 | + "keep intact all notices".
|
| 227 | +
|
| 228 | + c) You must license the entire work, as a whole, under this
|
| 229 | + License to anyone who comes into possession of a copy. This
|
| 230 | + License will therefore apply, along with any applicable section 7
|
| 231 | + additional terms, to the whole of the work, and all its parts,
|
| 232 | + regardless of how they are packaged. This License gives no
|
| 233 | + permission to license the work in any other way, but it does not
|
| 234 | + invalidate such permission if you have separately received it.
|
| 235 | +
|
| 236 | + d) If the work has interactive user interfaces, each must display
|
| 237 | + Appropriate Legal Notices; however, if the Program has interactive
|
| 238 | + interfaces that do not display Appropriate Legal Notices, your
|
| 239 | + work need not make them do so.
|
| 240 | +
|
| 241 | + A compilation of a covered work with other separate and independent
|
| 242 | +works, which are not by their nature extensions of the covered work,
|
| 243 | +and which are not combined with it such as to form a larger program,
|
| 244 | +in or on a volume of a storage or distribution medium, is called an
|
| 245 | +"aggregate" if the compilation and its resulting copyright are not
|
| 246 | +used to limit the access or legal rights of the compilation's users
|
| 247 | +beyond what the individual works permit. Inclusion of a covered work
|
| 248 | +in an aggregate does not cause this License to apply to the other
|
| 249 | +parts of the aggregate.
|
| 250 | +
|
| 251 | + 6. Conveying Non-Source Forms.
|
| 252 | +
|
| 253 | + You may convey a covered work in object code form under the terms
|
| 254 | +of sections 4 and 5, provided that you also convey the
|
| 255 | +machine-readable Corresponding Source under the terms of this License,
|
| 256 | +in one of these ways:
|
| 257 | +
|
| 258 | + a) Convey the object code in, or embodied in, a physical product
|
| 259 | + (including a physical distribution medium), accompanied by the
|
| 260 | + Corresponding Source fixed on a durable physical medium
|
| 261 | + customarily used for software interchange.
|
| 262 | +
|
| 263 | + b) Convey the object code in, or embodied in, a physical product
|
| 264 | + (including a physical distribution medium), accompanied by a
|
| 265 | + written offer, valid for at least three years and valid for as
|
| 266 | + long as you offer spare parts or customer support for that product
|
| 267 | + model, to give anyone who possesses the object code either (1) a
|
| 268 | + copy of the Corresponding Source for all the software in the
|
| 269 | + product that is covered by this License, on a durable physical
|
| 270 | + medium customarily used for software interchange, for a price no
|
| 271 | + more than your reasonable cost of physically performing this
|
| 272 | + conveying of source, or (2) access to copy the
|
| 273 | + Corresponding Source from a network server at no charge.
|
| 274 | +
|
| 275 | + c) Convey individual copies of the object code with a copy of the
|
| 276 | + written offer to provide the Corresponding Source. This
|
| 277 | + alternative is allowed only occasionally and noncommercially, and
|
| 278 | + only if you received the object code with such an offer, in accord
|
| 279 | + with subsection 6b.
|
| 280 | +
|
| 281 | + d) Convey the object code by offering access from a designated
|
| 282 | + place (gratis or for a charge), and offer equivalent access to the
|
| 283 | + Corresponding Source in the same way through the same place at no
|
| 284 | + further charge. You need not require recipients to copy the
|
| 285 | + Corresponding Source along with the object code. If the place to
|
| 286 | + copy the object code is a network server, the Corresponding Source
|
| 287 | + may be on a different server (operated by you or a third party)
|
| 288 | + that supports equivalent copying facilities, provided you maintain
|
| 289 | + clear directions next to the object code saying where to find the
|
| 290 | + Corresponding Source. Regardless of what server hosts the
|
| 291 | + Corresponding Source, you remain obligated to ensure that it is
|
| 292 | + available for as long as needed to satisfy these requirements.
|
| 293 | +
|
| 294 | + e) Convey the object code using peer-to-peer transmission, provided
|
| 295 | + you inform other peers where the object code and Corresponding
|
| 296 | + Source of the work are being offered to the general public at no
|
| 297 | + charge under subsection 6d.
|
| 298 | +
|
| 299 | + A separable portion of the object code, whose source code is excluded
|
| 300 | +from the Corresponding Source as a System Library, need not be
|
| 301 | +included in conveying the object code work.
|
| 302 | +
|
| 303 | + A "User Product" is either (1) a "consumer product", which means any
|
| 304 | +tangible personal property which is normally used for personal, family,
|
| 305 | +or household purposes, or (2) anything designed or sold for incorporation
|
| 306 | +into a dwelling. In determining whether a product is a consumer product,
|
| 307 | +doubtful cases shall be resolved in favor of coverage. For a particular
|
| 308 | +product received by a particular user, "normally used" refers to a
|
| 309 | +typical or common use of that class of product, regardless of the status
|
| 310 | +of the particular user or of the way in which the particular user
|
| 311 | +actually uses, or expects or is expected to use, the product. A product
|
| 312 | +is a consumer product regardless of whether the product has substantial
|
| 313 | +commercial, industrial or non-consumer uses, unless such uses represent
|
| 314 | +the only significant mode of use of the product.
|
| 315 | +
|
| 316 | + "Installation Information" for a User Product means any methods,
|
| 317 | +procedures, authorization keys, or other information required to install
|
| 318 | +and execute modified versions of a covered work in that User Product from
|
| 319 | +a modified version of its Corresponding Source. The information must
|
| 320 | +suffice to ensure that the continued functioning of the modified object
|
| 321 | +code is in no case prevented or interfered with solely because
|
| 322 | +modification has been made.
|
| 323 | +
|
| 324 | + If you convey an object code work under this section in, or with, or
|
| 325 | +specifically for use in, a User Product, and the conveying occurs as
|
| 326 | +part of a transaction in which the right of possession and use of the
|
| 327 | +User Product is transferred to the recipient in perpetuity or for a
|
| 328 | +fixed term (regardless of how the transaction is characterized), the
|
| 329 | +Corresponding Source conveyed under this section must be accompanied
|
| 330 | +by the Installation Information. But this requirement does not apply
|
| 331 | +if neither you nor any third party retains the ability to install
|
| 332 | +modified object code on the User Product (for example, the work has
|
| 333 | +been installed in ROM).
|
| 334 | +
|
| 335 | + The requirement to provide Installation Information does not include a
|
| 336 | +requirement to continue to provide support service, warranty, or updates
|
| 337 | +for a work that has been modified or installed by the recipient, or for
|
| 338 | +the User Product in which it has been modified or installed. Access to a
|
| 339 | +network may be denied when the modification itself materially and
|
| 340 | +adversely affects the operation of the network or violates the rules and
|
| 341 | +protocols for communication across the network.
|
| 342 | +
|
| 343 | + Corresponding Source conveyed, and Installation Information provided,
|
| 344 | +in accord with this section must be in a format that is publicly
|
| 345 | +documented (and with an implementation available to the public in
|
| 346 | +source code form), and must require no special password or key for
|
| 347 | +unpacking, reading or copying.
|
| 348 | +
|
| 349 | + 7. Additional Terms.
|
| 350 | +
|
| 351 | + "Additional permissions" are terms that supplement the terms of this
|
| 352 | +License by making exceptions from one or more of its conditions.
|
| 353 | +Additional permissions that are applicable to the entire Program shall
|
| 354 | +be treated as though they were included in this License, to the extent
|
| 355 | +that they are valid under applicable law. If additional permissions
|
| 356 | +apply only to part of the Program, that part may be used separately
|
| 357 | +under those permissions, but the entire Program remains governed by
|
| 358 | +this License without regard to the additional permissions.
|
| 359 | +
|
| 360 | + When you convey a copy of a covered work, you may at your option
|
| 361 | +remove any additional permissions from that copy, or from any part of
|
| 362 | +it. (Additional permissions may be written to require their own
|
| 363 | +removal in certain cases when you modify the work.) You may place
|
| 364 | +additional permissions on material, added by you to a covered work,
|
| 365 | +for which you have or can give appropriate copyright permission.
|
| 366 | +
|
| 367 | + Notwithstanding any other provision of this License, for material you
|
| 368 | +add to a covered work, you may (if authorized by the copyright holders of
|
| 369 | +that material) supplement the terms of this License with terms:
|
| 370 | +
|
| 371 | + a) Disclaiming warranty or limiting liability differently from the
|
| 372 | + terms of sections 15 and 16 of this License; or
|
| 373 | +
|
| 374 | + b) Requiring preservation of specified reasonable legal notices or
|
| 375 | + author attributions in that material or in the Appropriate Legal
|
| 376 | + Notices displayed by works containing it; or
|
| 377 | +
|
| 378 | + c) Prohibiting misrepresentation of the origin of that material, or
|
| 379 | + requiring that modified versions of such material be marked in
|
| 380 | + reasonable ways as different from the original version; or
|
| 381 | +
|
| 382 | + d) Limiting the use for publicity purposes of names of licensors or
|
| 383 | + authors of the material; or
|
| 384 | +
|
| 385 | + e) Declining to grant rights under trademark law for use of some
|
| 386 | + trade names, trademarks, or service marks; or
|
| 387 | +
|
| 388 | + f) Requiring indemnification of licensors and authors of that
|
| 389 | + material by anyone who conveys the material (or modified versions of
|
| 390 | + it) with contractual assumptions of liability to the recipient, for
|
| 391 | + any liability that these contractual assumptions directly impose on
|
| 392 | + those licensors and authors.
|
| 393 | +
|
| 394 | + All other non-permissive additional terms are considered "further
|
| 395 | +restrictions" within the meaning of section 10. If the Program as you
|
| 396 | +received it, or any part of it, contains a notice stating that it is
|
| 397 | +governed by this License along with a term that is a further
|
| 398 | +restriction, you may remove that term. If a license document contains
|
| 399 | +a further restriction but permits relicensing or conveying under this
|
| 400 | +License, you may add to a covered work material governed by the terms
|
| 401 | +of that license document, provided that the further restriction does
|
| 402 | +not survive such relicensing or conveying.
|
| 403 | +
|
| 404 | + If you add terms to a covered work in accord with this section, you
|
| 405 | +must place, in the relevant source files, a statement of the
|
| 406 | +additional terms that apply to those files, or a notice indicating
|
| 407 | +where to find the applicable terms.
|
| 408 | +
|
| 409 | + Additional terms, permissive or non-permissive, may be stated in the
|
| 410 | +form of a separately written license, or stated as exceptions;
|
| 411 | +the above requirements apply either way.
|
| 412 | +
|
| 413 | + 8. Termination.
|
| 414 | +
|
| 415 | + You may not propagate or modify a covered work except as expressly
|
| 416 | +provided under this License. Any attempt otherwise to propagate or
|
| 417 | +modify it is void, and will automatically terminate your rights under
|
| 418 | +this License (including any patent licenses granted under the third
|
| 419 | +paragraph of section 11).
|
| 420 | +
|
| 421 | + However, if you cease all violation of this License, then your
|
| 422 | +license from a particular copyright holder is reinstated (a)
|
| 423 | +provisionally, unless and until the copyright holder explicitly and
|
| 424 | +finally terminates your license, and (b) permanently, if the copyright
|
| 425 | +holder fails to notify you of the violation by some reasonable means
|
| 426 | +prior to 60 days after the cessation.
|
| 427 | +
|
| 428 | + Moreover, your license from a particular copyright holder is
|
| 429 | +reinstated permanently if the copyright holder notifies you of the
|
| 430 | +violation by some reasonable means, this is the first time you have
|
| 431 | +received notice of violation of this License (for any work) from that
|
| 432 | +copyright holder, and you cure the violation prior to 30 days after
|
| 433 | +your receipt of the notice.
|
| 434 | +
|
| 435 | + Termination of your rights under this section does not terminate the
|
| 436 | +licenses of parties who have received copies or rights from you under
|
| 437 | +this License. If your rights have been terminated and not permanently
|
| 438 | +reinstated, you do not qualify to receive new licenses for the same
|
| 439 | +material under section 10.
|
| 440 | +
|
| 441 | + 9. Acceptance Not Required for Having Copies.
|
| 442 | +
|
| 443 | + You are not required to accept this License in order to receive or
|
| 444 | +run a copy of the Program. Ancillary propagation of a covered work
|
| 445 | +occurring solely as a consequence of using peer-to-peer transmission
|
| 446 | +to receive a copy likewise does not require acceptance. However,
|
| 447 | +nothing other than this License grants you permission to propagate or
|
| 448 | +modify any covered work. These actions infringe copyright if you do
|
| 449 | +not accept this License. Therefore, by modifying or propagating a
|
| 450 | +covered work, you indicate your acceptance of this License to do so.
|
| 451 | +
|
| 452 | + 10. Automatic Licensing of Downstream Recipients.
|
| 453 | +
|
| 454 | + Each time you convey a covered work, the recipient automatically
|
| 455 | +receives a license from the original licensors, to run, modify and
|
| 456 | +propagate that work, subject to this License. You are not responsible
|
| 457 | +for enforcing compliance by third parties with this License.
|
| 458 | +
|
| 459 | + An "entity transaction" is a transaction transferring control of an
|
| 460 | +organization, or substantially all assets of one, or subdividing an
|
| 461 | +organization, or merging organizations. If propagation of a covered
|
| 462 | +work results from an entity transaction, each party to that
|
| 463 | +transaction who receives a copy of the work also receives whatever
|
| 464 | +licenses to the work the party's predecessor in interest had or could
|
| 465 | +give under the previous paragraph, plus a right to possession of the
|
| 466 | +Corresponding Source of the work from the predecessor in interest, if
|
| 467 | +the predecessor has it or can get it with reasonable efforts.
|
| 468 | +
|
| 469 | + You may not impose any further restrictions on the exercise of the
|
| 470 | +rights granted or affirmed under this License. For example, you may
|
| 471 | +not impose a license fee, royalty, or other charge for exercise of
|
| 472 | +rights granted under this License, and you may not initiate litigation
|
| 473 | +(including a cross-claim or counterclaim in a lawsuit) alleging that
|
| 474 | +any patent claim is infringed by making, using, selling, offering for
|
| 475 | +sale, or importing the Program or any portion of it.
|
| 476 | +
|
| 477 | + 11. Patents.
|
| 478 | +
|
| 479 | + A "contributor" is a copyright holder who authorizes use under this
|
| 480 | +License of the Program or a work on which the Program is based. The
|
| 481 | +work thus licensed is called the contributor's "contributor version".
|
| 482 | +
|
| 483 | + A contributor's "essential patent claims" are all patent claims
|
| 484 | +owned or controlled by the contributor, whether already acquired or
|
| 485 | +hereafter acquired, that would be infringed by some manner, permitted
|
| 486 | +by this License, of making, using, or selling its contributor version,
|
| 487 | +but do not include claims that would be infringed only as a
|
| 488 | +consequence of further modification of the contributor version. For
|
| 489 | +purposes of this definition, "control" includes the right to grant
|
| 490 | +patent sublicenses in a manner consistent with the requirements of
|
| 491 | +this License.
|
| 492 | +
|
| 493 | + Each contributor grants you a non-exclusive, worldwide, royalty-free
|
| 494 | +patent license under the contributor's essential patent claims, to
|
| 495 | +make, use, sell, offer for sale, import and otherwise run, modify and
|
| 496 | +propagate the contents of its contributor version.
|
| 497 | +
|
| 498 | + In the following three paragraphs, a "patent license" is any express
|
| 499 | +agreement or commitment, however denominated, not to enforce a patent
|
| 500 | +(such as an express permission to practice a patent or covenant not to
|
| 501 | +sue for patent infringement). To "grant" such a patent license to a
|
| 502 | +party means to make such an agreement or commitment not to enforce a
|
| 503 | +patent against the party.
|
| 504 | +
|
| 505 | + If you convey a covered work, knowingly relying on a patent license,
|
| 506 | +and the Corresponding Source of the work is not available for anyone
|
| 507 | +to copy, free of charge and under the terms of this License, through a
|
| 508 | +publicly available network server or other readily accessible means,
|
| 509 | +then you must either (1) cause the Corresponding Source to be so
|
| 510 | +available, or (2) arrange to deprive yourself of the benefit of the
|
| 511 | +patent license for this particular work, or (3) arrange, in a manner
|
| 512 | +consistent with the requirements of this License, to extend the patent
|
| 513 | +license to downstream recipients. "Knowingly relying" means you have
|
| 514 | +actual knowledge that, but for the patent license, your conveying the
|
| 515 | +covered work in a country, or your recipient's use of the covered work
|
| 516 | +in a country, would infringe one or more identifiable patents in that
|
| 517 | +country that you have reason to believe are valid.
|
| 518 | +
|
| 519 | + If, pursuant to or in connection with a single transaction or
|
| 520 | +arrangement, you convey, or propagate by procuring conveyance of, a
|
| 521 | +covered work, and grant a patent license to some of the parties
|
| 522 | +receiving the covered work authorizing them to use, propagate, modify
|
| 523 | +or convey a specific copy of the covered work, then the patent license
|
| 524 | +you grant is automatically extended to all recipients of the covered
|
| 525 | +work and works based on it.
|
| 526 | +
|
| 527 | + A patent license is "discriminatory" if it does not include within
|
| 528 | +the scope of its coverage, prohibits the exercise of, or is
|
| 529 | +conditioned on the non-exercise of one or more of the rights that are
|
| 530 | +specifically granted under this License. You may not convey a covered
|
| 531 | +work if you are a party to an arrangement with a third party that is
|
| 532 | +in the business of distributing software, under which you make payment
|
| 533 | +to the third party based on the extent of your activity of conveying
|
| 534 | +the work, and under which the third party grants, to any of the
|
| 535 | +parties who would receive the covered work from you, a discriminatory
|
| 536 | +patent license (a) in connection with copies of the covered work
|
| 537 | +conveyed by you (or copies made from those copies), or (b) primarily
|
| 538 | +for and in connection with specific products or compilations that
|
| 539 | +contain the covered work, unless you entered into that arrangement,
|
| 540 | +or that patent license was granted, prior to 28 March 2007.
|
| 541 | +
|
| 542 | + Nothing in this License shall be construed as excluding or limiting
|
| 543 | +any implied license or other defenses to infringement that may
|
| 544 | +otherwise be available to you under applicable patent law.
|
| 545 | +
|
| 546 | + 12. No Surrender of Others' Freedom.
|
| 547 | +
|
| 548 | + If conditions are imposed on you (whether by court order, agreement or
|
| 549 | +otherwise) that contradict the conditions of this License, they do not
|
| 550 | +excuse you from the conditions of this License. If you cannot convey a
|
| 551 | +covered work so as to satisfy simultaneously your obligations under this
|
| 552 | +License and any other pertinent obligations, then as a consequence you may
|
| 553 | +not convey it at all. For example, if you agree to terms that obligate you
|
| 554 | +to collect a royalty for further conveying from those to whom you convey
|
| 555 | +the Program, the only way you could satisfy both those terms and this
|
| 556 | +License would be to refrain entirely from conveying the Program.
|
| 557 | +
|
| 558 | + 13. Use with the GNU Affero General Public License.
|
| 559 | +
|
| 560 | + Notwithstanding any other provision of this License, you have
|
| 561 | +permission to link or combine any covered work with a work licensed
|
| 562 | +under version 3 of the GNU Affero General Public License into a single
|
| 563 | +combined work, and to convey the resulting work. The terms of this
|
| 564 | +License will continue to apply to the part which is the covered work,
|
| 565 | +but the special requirements of the GNU Affero General Public License,
|
| 566 | +section 13, concerning interaction through a network will apply to the
|
| 567 | +combination as such.
|
| 568 | +
|
| 569 | + 14. Revised Versions of this License.
|
| 570 | +
|
| 571 | + The Free Software Foundation may publish revised and/or new versions of
|
| 572 | +the GNU General Public License from time to time. Such new versions will
|
| 573 | +be similar in spirit to the present version, but may differ in detail to
|
| 574 | +address new problems or concerns.
|
| 575 | +
|
| 576 | + Each version is given a distinguishing version number. If the
|
| 577 | +Program specifies that a certain numbered version of the GNU General
|
| 578 | +Public License "or any later version" applies to it, you have the
|
| 579 | +option of following the terms and conditions either of that numbered
|
| 580 | +version or of any later version published by the Free Software
|
| 581 | +Foundation. If the Program does not specify a version number of the
|
| 582 | +GNU General Public License, you may choose any version ever published
|
| 583 | +by the Free Software Foundation.
|
| 584 | +
|
| 585 | + If the Program specifies that a proxy can decide which future
|
| 586 | +versions of the GNU General Public License can be used, that proxy's
|
| 587 | +public statement of acceptance of a version permanently authorizes you
|
| 588 | +to choose that version for the Program.
|
| 589 | +
|
| 590 | + Later license versions may give you additional or different
|
| 591 | +permissions. However, no additional obligations are imposed on any
|
| 592 | +author or copyright holder as a result of your choosing to follow a
|
| 593 | +later version.
|
| 594 | +
|
| 595 | + 15. Disclaimer of Warranty.
|
| 596 | +
|
| 597 | + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
| 598 | +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
| 599 | +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
| 600 | +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
| 601 | +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
| 602 | +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
| 603 | +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
| 604 | +ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
| 605 | +
|
| 606 | + 16. Limitation of Liability.
|
| 607 | +
|
| 608 | + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
| 609 | +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
| 610 | +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
| 611 | +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
| 612 | +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
| 613 | +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
| 614 | +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
| 615 | +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
| 616 | +SUCH DAMAGES.
|
| 617 | +
|
| 618 | + 17. Interpretation of Sections 15 and 16.
|
| 619 | +
|
| 620 | + If the disclaimer of warranty and limitation of liability provided
|
| 621 | +above cannot be given local legal effect according to their terms,
|
| 622 | +reviewing courts shall apply local law that most closely approximates
|
| 623 | +an absolute waiver of all civil liability in connection with the
|
| 624 | +Program, unless a warranty or assumption of liability accompanies a
|
| 625 | +copy of the Program in return for a fee.
|
| 626 | +
|
| 627 | + END OF TERMS AND CONDITIONS
|
| 628 | +
|
| 629 | + How to Apply These Terms to Your New Programs
|
| 630 | +
|
| 631 | + If you develop a new program, and you want it to be of the greatest
|
| 632 | +possible use to the public, the best way to achieve this is to make it
|
| 633 | +free software which everyone can redistribute and change under these terms.
|
| 634 | +
|
| 635 | + To do so, attach the following notices to the program. It is safest
|
| 636 | +to attach them to the start of each source file to most effectively
|
| 637 | +state the exclusion of warranty; and each file should have at least
|
| 638 | +the "copyright" line and a pointer to where the full notice is found.
|
| 639 | +
|
| 640 | + <one line to give the program's name and a brief idea of what it does.>
|
| 641 | + Copyright (C) <year> <name of author>
|
| 642 | +
|
| 643 | + This program is free software: you can redistribute it and/or modify
|
| 644 | + it under the terms of the GNU General Public License as published by
|
| 645 | + the Free Software Foundation, either version 3 of the License, or
|
| 646 | + (at your option) any later version.
|
| 647 | +
|
| 648 | + This program is distributed in the hope that it will be useful,
|
| 649 | + but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 650 | + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 651 | + GNU General Public License for more details.
|
| 652 | +
|
| 653 | + You should have received a copy of the GNU General Public License
|
| 654 | + along with this program. If not, see <http://www.gnu.org/licenses/>.
|
| 655 | +
|
| 656 | +Also add information on how to contact you by electronic and paper mail.
|
| 657 | +
|
| 658 | + If the program does terminal interaction, make it output a short
|
| 659 | +notice like this when it starts in an interactive mode:
|
| 660 | +
|
| 661 | + <program> Copyright (C) <year> <name of author>
|
| 662 | + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
| 663 | + This is free software, and you are welcome to redistribute it
|
| 664 | + under certain conditions; type `show c' for details.
|
| 665 | +
|
| 666 | +The hypothetical commands `show w' and `show c' should show the appropriate
|
| 667 | +parts of the General Public License. Of course, your program's commands
|
| 668 | +might be different; for a GUI interface, you would use an "about box".
|
| 669 | +
|
| 670 | + You should also get your employer (if you work as a programmer) or school,
|
| 671 | +if any, to sign a "copyright disclaimer" for the program, if necessary.
|
| 672 | +For more information on this, and how to apply and follow the GNU GPL, see
|
| 673 | +<http://www.gnu.org/licenses/>.
|
| 674 | +
|
| 675 | + The GNU General Public License does not permit incorporating your program
|
| 676 | +into proprietary programs. If your program is a subroutine library, you
|
| 677 | +may consider it more useful to permit linking proprietary applications with
|
| 678 | +the library. If this is what you want to do, use the GNU Lesser General
|
| 679 | +Public License instead of this License. But first, please read
|
| 680 | +<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ShortQueryHover.initialize.js |
— | — | @@ -0,0 +1,77 @@ |
| 2 | +/** |
| 3 | + * JavasSript for context popup initialization of the 'Semantic Expresiveness' extension. |
| 4 | + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 5 | + * |
| 6 | + * @since 0.1 |
| 7 | + * @ingroup Semantic Expresiveness |
| 8 | + * |
| 9 | + * @licence GNU GPL v3+ |
| 10 | + * @author Daniel Werner < danweetz at web dot de > |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * Adds ui popup functionality to all short query results within a specified range of the document. |
| 15 | + * In case the popup would refer to the same page as it is positioned on, it will only show basic |
| 16 | + * information about the short query instead of loading its own content. In that case also the |
| 17 | + * pastCfgFunc callback won't be called and the popups instance is a TitledContextPopup instead of |
| 18 | + * a ShortQueryHover. |
| 19 | + * @param range jQuery if not set, initialization will be done for the whole document. |
| 20 | + * @param preCfgFunc Function callback which will be called before initialization. The uninitialized |
| 21 | + * semanticExpresiveness.ui.ShortQueryHover will be passed as first argument. |
| 22 | + * @param pastCfgFunc Function callback which will be called after each successful initialization. The |
| 23 | + * newly created semanticExpresiveness.ui.ShortQueryHover will be passed as first argument. |
| 24 | + */ |
| 25 | +window.semanticExpresiveness.ui.ShortQueryHover.initialize = function( range, preCfgFunc, pastCfgFunc ) { |
| 26 | + if( typeof range == 'undefined' ) { |
| 27 | + range = $( 'body' ); |
| 28 | + } |
| 29 | + if( typeof preCfgFunc == 'undefined' ) { |
| 30 | + configFunc = function(){}; |
| 31 | + } |
| 32 | + if( typeof pastCfgFunc == 'undefined' ) { |
| 33 | + pastCfgFunc = function(){}; |
| 34 | + } |
| 35 | + range |
| 36 | + .find( 'span.shortQuery' ) |
| 37 | + .each( function() { |
| 38 | + // create popup but don't initialize yet by not passing any arguments |
| 39 | + var queryHover = new window.semanticExpresiveness.ui.ShortQueryHover(); |
| 40 | + |
| 41 | + // run callback for advanced configuration |
| 42 | + preCfgFunc( queryHover ); |
| 43 | + |
| 44 | + try { |
| 45 | + // in case the short query markup is invalid, initialization will trigger an error! |
| 46 | + $sqResult = new window.semanticExpresiveness.ShortQueryResult( this ); |
| 47 | + |
| 48 | + if( $sqResult.isAbstractResult() ) { |
| 49 | + return; // no popup for abstract (failed) queries |
| 50 | + } |
| 51 | + } |
| 52 | + catch( e ) { |
| 53 | + // initialize some simple context popup which at least communicates that this is |
| 54 | + // some kind of invalid short query result |
| 55 | + var errorHover = new window.semanticExpresiveness.ui.TitledContextPopup( this ); |
| 56 | + errorHover.setTitle( |
| 57 | + $( '<strong class="semex-invalid-shortquery-format"/>' ) |
| 58 | + .text( 'Invalid short query format!' ) |
| 59 | + ); |
| 60 | + errorHover.setContent( null ); |
| 61 | + $( this ).addClass( 'semex-invalid-shortquery-format' ); |
| 62 | + |
| 63 | + return; |
| 64 | + } |
| 65 | + |
| 66 | + // init context popup after options are set |
| 67 | + queryHover._init( $sqResult ); |
| 68 | + |
| 69 | + if( queryHover.getQueryResult().getSource() === window.wgTitle ) { |
| 70 | + // first-level popup to the same page as it is placed on should only display the basic |
| 71 | + // short query information instead of getting its own pages content via AJAX. |
| 72 | + queryHover = queryHover.initializeSimilarTitledPopup(); |
| 73 | + } |
| 74 | + else { |
| 75 | + pastCfgFunc( queryHover ); |
| 76 | + } |
| 77 | + } ); |
| 78 | +}; |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ShortQueryHover.initialize.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 79 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ShortQueryHover.js |
— | — | @@ -0,0 +1,281 @@ |
| 2 | +/** |
| 3 | + * JavasSript for context popup of the 'Semantic Expresiveness' extension. |
| 4 | + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 5 | + * |
| 6 | + * @since 0.1 |
| 7 | + * @ingroup Semantic Expresiveness |
| 8 | + * |
| 9 | + * @licence GNU GPL v3+ |
| 10 | + * @author Daniel Werner < danweetz at web dot de > |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * Constructor for context Popup container adjusted for 'Semantic Expressiveness' extension needs |
| 15 | + * |
| 16 | + * @param subject semanticExpresiveness.ShortQueryResult |
| 17 | + */ |
| 18 | +window.semanticExpresiveness.ui.ShortQueryHover = function( subject ) { |
| 19 | + window.semanticExpresiveness.ui.TitledContextPopup.call( this, subject ); |
| 20 | +}; |
| 21 | + |
| 22 | +/* |
| 23 | + * Inherit and overwrite base class members: |
| 24 | + */ |
| 25 | +window.semanticExpresiveness.ui.ShortQueryHover.prototype = new window.semanticExpresiveness.ui.TitledContextPopup(); |
| 26 | +$.extend( window.semanticExpresiveness.ui.ShortQueryHover.prototype, { |
| 27 | + |
| 28 | + constructor: window.semanticExpresiveness.ui.ShortQueryHover, |
| 29 | + |
| 30 | + // overwrite original content: |
| 31 | + _content: $( |
| 32 | + '<div class="semex-shortqueryinfo-loading">' + |
| 33 | + mw.msg( 'semex-shortquery-hover-loading' ) + '...' + |
| 34 | + '</div>' |
| 35 | + ), |
| 36 | + |
| 37 | + /** |
| 38 | + * Associated short query result which belongs to the popups subject. |
| 39 | + * @var: semanticExpresiveness.ShortQueryResult |
| 40 | + */ |
| 41 | + _queryResult: null, |
| 42 | + |
| 43 | + /** |
| 44 | + * Whether the query information has been dynamically loaded or taken from cache (if in use). |
| 45 | + * If that is the case, this._content contains the information. |
| 46 | + * @var boolean |
| 47 | + */ |
| 48 | + _queryInfoLoaded: false, |
| 49 | + |
| 50 | + _init: function( subject ) { |
| 51 | + if( ! ( subject instanceof window.semanticExpresiveness.ShortQueryResult ) ) { |
| 52 | + throw new Error( |
| 53 | + '"' + this.constructor + |
| 54 | + '" initialization expects an instance of "ShortQueryResult" as first parameter.' |
| 55 | + ); |
| 56 | + } |
| 57 | + if( subject.isAbstractResult() ) { |
| 58 | + throw new Error( |
| 59 | + '"' + this.constructor + '" can not be built from an abstract "ShortQueryResult".' |
| 60 | + ); |
| 61 | + } |
| 62 | + this._queryResult = subject; |
| 63 | + |
| 64 | + this.$package.TitledContextPopup.prototype._init.call( this, subject.getDOMNode() ); |
| 65 | + this._buildTitleInfo(); |
| 66 | + }, |
| 67 | + |
| 68 | + /** |
| 69 | + * @see semanticExpresiveness.ui.TitledContextPopup._draw_buildPopup() |
| 70 | + */ |
| 71 | + _draw_buildPopup: function() { |
| 72 | + // call parent function... |
| 73 | + divPopup = this.$package.TitledContextPopup.prototype._draw_buildPopup.call( this ); |
| 74 | + // add class to identify this as short query hover popup |
| 75 | + divPopup.addClass( this.POPUP_CLASS + '-shortqueryhover' ); |
| 76 | + |
| 77 | + return divPopup; |
| 78 | + }, |
| 79 | + |
| 80 | + /** |
| 81 | + * destroys the short query hover popup and creates and initializes a simple TitledContextPopup |
| 82 | + * with basic information about the short query target and without AJAX functionality instead. |
| 83 | + * The new popup will be returned. |
| 84 | + * @return semanticExpresiveness.ui.TitledContextPopup |
| 85 | + */ |
| 86 | + initializeSimilarTitledPopup: function() { |
| 87 | + var oldTitle = this.getTitle().clone(); |
| 88 | + var subject = this.getSubject().get( 0 ); |
| 89 | + this.destroy(); // destroy old popup before initializing any new one! |
| 90 | + |
| 91 | + // create new popup with same values but with title only: |
| 92 | + var newPopup = new window.semanticExpresiveness.ui.TitledContextPopup( subject ); |
| 93 | + newPopup.setTitle( oldTitle ); |
| 94 | + newPopup.setContent( null ); |
| 95 | + |
| 96 | + return newPopup; |
| 97 | + }, |
| 98 | + |
| 99 | + /** |
| 100 | + * Generates the information displayed as title |
| 101 | + */ |
| 102 | + _buildTitleInfo: function() { |
| 103 | + var sq = this._queryResult; |
| 104 | + |
| 105 | + var prop = sq.getProperty(); |
| 106 | + prop = '<a href="' + mw.util.wikiGetlink( 'Property:' + prop ) + '">' + prop + '</a>'; |
| 107 | + |
| 108 | + var source = sq.getSource(); |
| 109 | + source = '<a href="' + mw.util.wikiGetlink( source ) + '">' + source + '</a>'; |
| 110 | + |
| 111 | + // put links into the message: |
| 112 | + this.setTitle( |
| 113 | + $( mw.msg( 'semex-shortquery-title', prop, source ) ) |
| 114 | + ); |
| 115 | + }, |
| 116 | + |
| 117 | + /** |
| 118 | + * @see window.semanticExpresiveness.ui.ContextPopup.setContent() |
| 119 | + */ |
| 120 | + setContent: function( content ) { |
| 121 | + // Initialize short query popups within inserted code: |
| 122 | + if( this.recursiveInitialization |
| 123 | + && content instanceof jQuery // could be null or string as well! |
| 124 | + ) { |
| 125 | + this._doRecursiveInitialization( content ); |
| 126 | + } |
| 127 | + this.$package.TitledContextPopup.prototype.setContent.call( this, content ) |
| 128 | + }, |
| 129 | + |
| 130 | + /** |
| 131 | + * @see window.semanticExpresiveness.ui.ContextPopup.show() |
| 132 | + */ |
| 133 | + show: function() { |
| 134 | + if( ! this.$package.TitledContextPopup.prototype.show.call( this ) ) { |
| 135 | + // no state change, do nothing |
| 136 | + return false; |
| 137 | + } |
| 138 | + |
| 139 | + if( this.queryInfoCache && this.queryInfoCache.hasInfo( this ) ) { |
| 140 | + // use cache |
| 141 | + this._queryInfoLoaded = true; |
| 142 | + // clone original information so recursively displaying same information won't do crazy things |
| 143 | + this.setContent( this.queryInfoCache.getInfo( this ).clone() ); |
| 144 | + } |
| 145 | + else { |
| 146 | + // load information |
| 147 | + this._loadQueryInfo(); |
| 148 | + } |
| 149 | + return true; |
| 150 | + }, |
| 151 | + |
| 152 | + /** |
| 153 | + * Returns the link from where the popup should get its information. |
| 154 | + * @return string |
| 155 | + */ |
| 156 | + getQueryInfoSource: function() { |
| 157 | + var source = this._queryResult.getSource(); |
| 158 | + return mw.util.wikiGetlink( source ) + '&action=render&action=purge'; |
| 159 | + }, |
| 160 | + |
| 161 | + /** |
| 162 | + * Requests and extracts the information from the short query results source page. |
| 163 | + */ |
| 164 | + _loadQueryInfo: function() { |
| 165 | + var self = this; |
| 166 | + var dummy = $( '<div/>' ); |
| 167 | + |
| 168 | + var request = this.getQueryInfoSource(); |
| 169 | + request += ' ' + this.queryInfoSelector; |
| 170 | + |
| 171 | + dummy.load( |
| 172 | + request, |
| 173 | + function( rawData, status, jqXHR ) { |
| 174 | + if( jqXHR.status == 0 ) { |
| 175 | + dummy = false; |
| 176 | + } |
| 177 | + self._applyQueryInfo( dummy, rawData, jqXHR ); |
| 178 | + } |
| 179 | + ); |
| 180 | + }, |
| 181 | + |
| 182 | + /** |
| 183 | + * Applies the retrieved short query information. |
| 184 | + * Also handles the caching and callback handling. |
| 185 | + */ |
| 186 | + _applyQueryInfo: function( data, rawData, jqXHR ) { |
| 187 | + if( this.beforeApplyQueryInfo !== null ) { |
| 188 | + data = this.beforeApplyQueryInfo( data ) |
| 189 | + } |
| 190 | + if( data === false ) { |
| 191 | + /** @ToDo: right now the message gets treated as if it were the right value, might be |
| 192 | + * of interest to notify the cache that this information is just a message |
| 193 | + */ |
| 194 | + data = $( |
| 195 | + '<div class="semex-shortqueryinfo-loading-failed">' + |
| 196 | + mw.msg( 'semex-shortquery-hover-loading-failed' ) + '</div>' |
| 197 | + ); |
| 198 | + } |
| 199 | + |
| 200 | + // cache information if enabled: |
| 201 | + if( this.queryInfoCache ) { |
| 202 | + this.queryInfoCache.addInfo( this, data ); |
| 203 | + } |
| 204 | + // apply new content: |
| 205 | + this._queryInfoLoaded = true; |
| 206 | + this.setContent( data.clone() ); |
| 207 | + }, |
| 208 | + |
| 209 | + /** |
| 210 | + * Checks new popup content for further short queries and initializes their ui functionality. |
| 211 | + * @param content jQuery |
| 212 | + */ |
| 213 | + _doRecursiveInitialization: function( content ) { |
| 214 | + var self = this; |
| 215 | + this.$package.ShortQueryHover.initialize( |
| 216 | + content, |
| 217 | + function( queryHover ) { // configuration per ShortQueryHover element |
| 218 | + queryHover.queryInfoCache = self.queryInfoCache; |
| 219 | + queryHover.queryInfoSelector = self.queryInfoSelector; |
| 220 | + queryHover.recursiveInitialization = true; |
| 221 | + }, |
| 222 | + function( queryHover ) { |
| 223 | + if( self.getQueryResult().getSource() !== queryHover.getQueryResult().getSource() ) { |
| 224 | + return queryHover; |
| 225 | + } |
| 226 | + // this popups content would be the same as the parent popups content, so display |
| 227 | + // necessary information only to avoid endless chains of the same popup |
| 228 | + queryHover = queryHover.initializeSimilarTitledPopup(); |
| 229 | + } |
| 230 | + ); |
| 231 | + }, |
| 232 | + |
| 233 | + /** |
| 234 | + * Returns the associated Querry Result object |
| 235 | + * @returns semanticExpresiveness.ShortQueryResult |
| 236 | + */ |
| 237 | + getQueryResult: function() { |
| 238 | + return this._queryResult; |
| 239 | + }, |
| 240 | + |
| 241 | + /////////// |
| 242 | + // EVENTS: |
| 243 | + /////////// |
| 244 | + |
| 245 | + /** |
| 246 | + * Callback called once after the information from the short queries source page has been loaded, |
| 247 | + * just before the information will be set as the context popups content. The return value of the |
| 248 | + * callback allows to return a modified jQuery object which will be set as the popups content then. |
| 249 | + * If false is returned, it indicates that no information was found. |
| 250 | + * @param data jQuery|false the original extracted information from the short queries target page. |
| 251 | + * If set to false, this implies that loading the information has failed. |
| 252 | + * @return jQuery|false |
| 253 | + */ |
| 254 | + beforeApplyQueryInfo: null, |
| 255 | + |
| 256 | + ///////////////// |
| 257 | + // CONFIGURABLE: |
| 258 | + ///////////////// |
| 259 | + |
| 260 | + /** |
| 261 | + * If set to false, there is no cache and each displaying of a short query popup will lead to loading |
| 262 | + * the required information again. If set to an Cache object, the information will be stored within. |
| 263 | + * This allows a global cache to share information once retrieved between short queries which have the |
| 264 | + * same target page. |
| 265 | + * @var false|semanticExpresiveness.ui.ShortQueryHover.Cache |
| 266 | + */ |
| 267 | + queryInfoCache: false, |
| 268 | + |
| 269 | + /** |
| 270 | + * A valid jQuery selector to choose which elements from the short query target page should be |
| 271 | + * selected as popup content. |
| 272 | + * @var string |
| 273 | + */ |
| 274 | + queryInfoSelector: '.NavFrame, .freeInfoBox', |
| 275 | + |
| 276 | + /** |
| 277 | + * If set to true, any content displayed within the popup will be checked for further short queries which |
| 278 | + * will then be initialized as well. |
| 279 | + * @var boolean |
| 280 | + */ |
| 281 | + recursiveInitialization: true |
| 282 | +} ); |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ShortQueryHover.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 283 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.TitledContextPopup.css |
— | — | @@ -0,0 +1,30 @@ |
| 2 | +#ui-titledcontextpopup-store { position: absolute; top: 0; left: 0; margin: 0; padding: 0; } |
| 3 | + |
| 4 | +.ui-contextpopup-titlepopup-title { |
| 5 | + background-color: #f2f2f2; |
| 6 | + border: none; |
| 7 | + padding: 4px; |
| 8 | + font-weight: bold; |
| 9 | +} |
| 10 | + |
| 11 | +.ui-contextpopup-titlepopup-container { |
| 12 | + padding: 0; |
| 13 | +} |
| 14 | +.ui-contextpopup-titlepopup-content { |
| 15 | + padding: 2px; |
| 16 | +} |
| 17 | + |
| 18 | +.ui-contextpopup-onbottom .ui-contextpopup-titlepopup-content { |
| 19 | + border-top: 1px solid #b8b8b8; |
| 20 | +} |
| 21 | + |
| 22 | +.ui-contextpopup-ontop .ui-contextpopup-titlepopup-content { |
| 23 | + border-bottom: 1px solid #b8b8b8; |
| 24 | +} |
| 25 | + |
| 26 | +.ui-contextpopup-titlepopup .ui-contextpopup-pointer-onbottom { |
| 27 | + background-image: url('./images/pointer-up-titledpopup.png'); |
| 28 | +} |
| 29 | +.ui-contextpopup-titlepopup .ui-contextpopup-pointer-ontop { |
| 30 | + background-image: url('./images/pointer-down-titledpopup.png'); |
| 31 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.TitledContextPopup.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 32 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ShortQueryHover.Cache.js |
— | — | @@ -0,0 +1,79 @@ |
| 2 | +/** |
| 3 | + * JavasSript for context popup of the 'Semantic Expresiveness' extension. |
| 4 | + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 5 | + * |
| 6 | + * @since 0.1 |
| 7 | + * @ingroup Semantic Expresiveness |
| 8 | + * |
| 9 | + * @licence GNU GPL v3+ |
| 10 | + * @author Daniel Werner < danweetz at web dot de > |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * Constructor for AJAX short query information cache which can be used to share retrieved |
| 15 | + * information between several ShortQueryHover elements. |
| 16 | + */ |
| 17 | +window.semanticExpresiveness.ui.ShortQueryHover.Cache = function(){ |
| 18 | +} |
| 19 | + |
| 20 | +window.semanticExpresiveness.ui.ShortQueryHover.Cache.prototype = { |
| 21 | + /* |
| 22 | + * Internal store for cached elements |
| 23 | + */ |
| 24 | + _cache: new Object, |
| 25 | + |
| 26 | + _resolveContext: function( context ) { |
| 27 | + if( context instanceof String ) { |
| 28 | + return context; |
| 29 | + } |
| 30 | + return context.getQueryResult().getSource(); |
| 31 | + }, |
| 32 | + |
| 33 | + /** |
| 34 | + * Returns an information which has been cached before. |
| 35 | + * @param context semanticExpresiveness.ui.ShortQueryHover|string |
| 36 | + * @return mixed |
| 37 | + */ |
| 38 | + getInfo: function( context ) { |
| 39 | + return this._cache[ '__' + this._resolveContext( context ) ]; |
| 40 | + }, |
| 41 | + |
| 42 | + /* |
| 43 | + * Cache something. |
| 44 | + * @param context semanticExpresiveness.ui.ShortQueryHover|string |
| 45 | + * @param value mixed information to cache |
| 46 | + */ |
| 47 | + addInfo: function( context, value ) { |
| 48 | + this._cache[ '__' + this._resolveContext( context ) ] = value; |
| 49 | + }, |
| 50 | + |
| 51 | + /* |
| 52 | + * Removes one information from the cache. |
| 53 | + * @param context semanticExpresiveness.ui.ShortQueryHover|string |
| 54 | + * @return boolean whether the information existed |
| 55 | + */ |
| 56 | + removeInfo: function( context ) { |
| 57 | + var key = this._resolveContext( context ); |
| 58 | + if( this.hasInfo( key ) ) { |
| 59 | + delete this._cache[ '__' + key ]; |
| 60 | + return true; |
| 61 | + } |
| 62 | + return false; |
| 63 | + }, |
| 64 | + |
| 65 | + /* |
| 66 | + * Returns whether the information is cached already. |
| 67 | + * @param context semanticExpresiveness.ui.ShortQueryHover|string |
| 68 | + * @return boolean |
| 69 | + */ |
| 70 | + hasInfo: function( context ) { |
| 71 | + return this._cache.hasOwnProperty( '__' + this._resolveContext( context ) ) |
| 72 | + }, |
| 73 | + |
| 74 | + /* |
| 75 | + * Removes all cached informations from the cache. |
| 76 | + */ |
| 77 | + clear: function() { |
| 78 | + this._cache = new Object(); |
| 79 | + } |
| 80 | +}; |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ShortQueryHover.Cache.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 81 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.TitledContextPopup.js |
— | — | @@ -0,0 +1,133 @@ |
| 2 | +/** |
| 3 | + * JavasSript for context popup of the 'Semantic Expresiveness' extension. |
| 4 | + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 5 | + * |
| 6 | + * @since 0.1 |
| 7 | + * @ingroup Semantic Expresiveness |
| 8 | + * |
| 9 | + * @licence GNU GPL v3+ |
| 10 | + * @author Daniel Werner < danweetz at web dot de > |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * Constructor for context popup container which allows to display some title section |
| 15 | + * next to the subject but within the context popup box. This means if the popup gets |
| 16 | + * displayed above its triggering subject, the title will be displayed at the popups |
| 17 | + * bottom, if the popup will be beyond the subject, the title will be displayed on top. |
| 18 | + */ |
| 19 | +window.semanticExpresiveness.ui.TitledContextPopup = function( subject ){ |
| 20 | + window.semanticExpresiveness.ui.ContextPopup.call( this, subject ); |
| 21 | +}; |
| 22 | + |
| 23 | +/* |
| 24 | + * Inherit and overwrite base class members: |
| 25 | + */ |
| 26 | +window.semanticExpresiveness.ui.TitledContextPopup.prototype = new window.semanticExpresiveness.ui.ContextPopup(); |
| 27 | +$.extend( window.semanticExpresiveness.ui.TitledContextPopup.prototype, { |
| 28 | + |
| 29 | + /** |
| 30 | + * Title which should be displayed next to the popups content. |
| 31 | + * @var jQuery |
| 32 | + */ |
| 33 | + _title: null, |
| 34 | + |
| 35 | + /** |
| 36 | + * @see semanticExpresiveness.ui.TitledContextPopup.POPUP_STORE_ID |
| 37 | + */ |
| 38 | + //POPUP_STORE_ID: 'ui-titledcontextpopup-store', |
| 39 | + |
| 40 | + /** |
| 41 | + * Allows to set the content of the title. |
| 42 | + * @param $content jQuery|String |
| 43 | + */ |
| 44 | + setTitle: function( content ) { |
| 45 | + if( typeof content == 'undefined' ) { |
| 46 | + content = null |
| 47 | + } |
| 48 | + if( content instanceof String ) { |
| 49 | + content = $( document.createTextNode( content ) ); |
| 50 | + } |
| 51 | + this._title = content; |
| 52 | + }, |
| 53 | + |
| 54 | + /** |
| 55 | + * Returns the content which should be displayed as title within the popup container. |
| 56 | + * @return jQuery |
| 57 | + */ |
| 58 | + getTitle: function() { |
| 59 | + return this._title; |
| 60 | + }, |
| 61 | + |
| 62 | + /** |
| 63 | + * @see semanticExpresiveness.ui.ContextPopup._draw_buildPopup() |
| 64 | + */ |
| 65 | + _draw_buildPopup: function() { |
| 66 | + // call parent function... |
| 67 | + divPopup = this.$package.ContextPopup.prototype._draw_buildPopup.call( this ); |
| 68 | + |
| 69 | + if( this._title === null ) { |
| 70 | + // TitleContextPopup without title set is not much more than normal ContextPopup |
| 71 | + return divPopup; |
| 72 | + } |
| 73 | + |
| 74 | + var boxClass = this.POPUP_CLASS + '-box'; |
| 75 | + |
| 76 | + // ...to get the content part from DOM |
| 77 | + divContent = divPopup.children( '.' + boxClass ); |
| 78 | + divContent |
| 79 | + .addClass( this.POPUP_CLASS + '-titlepopup-content' ) |
| 80 | + .removeClass( boxClass ); |
| 81 | + |
| 82 | + var divContainer = $( '<div/>', { // parent for title and content, replaces old content node |
| 83 | + 'class': this.POPUP_CLASS + '-titlepopup-container ' + boxClass |
| 84 | + } ); |
| 85 | + var divTitle = $( '<div/>', { // title, next to content node |
| 86 | + 'class': this.POPUP_CLASS + '-titlepopup-title' |
| 87 | + } ); |
| 88 | + divTitle.append( this._title ); |
| 89 | + |
| 90 | + // set content div next to title div within a new container: |
| 91 | + divContainer.append( divTitle ); |
| 92 | + if( this._content !== null ) { |
| 93 | + divContainer.append( divContent ); |
| 94 | + } else { |
| 95 | + // Title popup can have empty content (if title is set) |
| 96 | + divContent.empty().remove(); |
| 97 | + } |
| 98 | + divPopup |
| 99 | + .append( divContainer ) |
| 100 | + .addClass( this.POPUP_CLASS + '-titlepopup' ); |
| 101 | + |
| 102 | + return divPopup; |
| 103 | + }, |
| 104 | + |
| 105 | + /** |
| 106 | + * @see semanticExpresiveness.ui.TitledContextPopup._draw_doPositioning() |
| 107 | + */ |
| 108 | + _draw_doPositioning: function() { |
| 109 | + // we have positioned the title on top before, check whether it should be at the bottom: |
| 110 | + if( this.getTitlePosition() === this.ORIENTATION.BOTTOM ) { |
| 111 | + // find titles div and put it at the end |
| 112 | + var divTitle = this._popup.find( '.' + this.POPUP_CLASS + '-titlepopup-title' ); |
| 113 | + divTitle.parent().append( divTitle.detach() ); |
| 114 | + } |
| 115 | + this.$package.ContextPopup.prototype._draw_doPositioning.call( this ); |
| 116 | + }, |
| 117 | + |
| 118 | + /** |
| 119 | + * Returns the designated position of the title part of the popup. If the popup is not visible |
| 120 | + * at the moment or no title is set, null will be returned. |
| 121 | + * @return integer|null |
| 122 | + */ |
| 123 | + getTitlePosition: function() { |
| 124 | + if( this._orientation == null || this._title == null ) { |
| 125 | + return null; |
| 126 | + } |
| 127 | + if( this._orientation.vertical == this.ORIENTATION.TOP ) { |
| 128 | + return this.ORIENTATION.BOTTOM; |
| 129 | + } else { |
| 130 | + return this.ORIENTATION.TOP; |
| 131 | + } |
| 132 | + } |
| 133 | + |
| 134 | +} ); |
\ No newline at end of file |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.TitledContextPopup.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 135 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/images/pointer-down-titledpopup.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/images/pointer-down-titledpopup.png |
___________________________________________________________________ |
Added: svn:mime-type |
2 | 136 | + image/png |
Index: trunk/extensions/SemanticExpressiveness/resources/images/pointer-up.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/images/pointer-up.png |
___________________________________________________________________ |
Added: svn:mime-type |
3 | 137 | + image/png |
Index: trunk/extensions/SemanticExpressiveness/resources/images/pointer.psd |
Cannot display: file marked as a binary type. |
svn:mime-type = application/octet-stream |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/images/pointer.psd |
___________________________________________________________________ |
Added: svn:mime-type |
4 | 138 | + application/octet-stream |
Index: trunk/extensions/SemanticExpressiveness/resources/images/pointer-down.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/images/pointer-down.png |
___________________________________________________________________ |
Added: svn:mime-type |
5 | 139 | + image/png |
Index: trunk/extensions/SemanticExpressiveness/resources/images/pointer-up-titledpopup.png |
Cannot display: file marked as a binary type. |
svn:mime-type = image/png |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/images/pointer-up-titledpopup.png |
___________________________________________________________________ |
Added: svn:mime-type |
6 | 140 | + image/png |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.css |
— | — | @@ -0,0 +1,29 @@ |
| 2 | +.shortQuery .result { |
| 3 | + border-bottom: 1px dotted grey; |
| 4 | +} |
| 5 | +.shortQuery > .source, |
| 6 | +.shortQuery > .type, |
| 7 | +.shortQuery > .value { |
| 8 | + display: none; |
| 9 | +} |
| 10 | + |
| 11 | +.abstractShortQueryValue { |
| 12 | + font-style: italic!important; |
| 13 | + background-color: rgba( 235, 90, 90, 0.1 ); |
| 14 | + border: 1px solid rgba( 235, 90, 90, 0.1 ); |
| 15 | +} |
| 16 | +.abstractShortQueryValue * { |
| 17 | + font-style: normal; |
| 18 | +} |
| 19 | +.abstractShortQueryValue .result { |
| 20 | + background-color: #edf9d8; |
| 21 | + border-top: 1px solid #dff0bf; |
| 22 | + padding: 0 2px; |
| 23 | + margin-left: -2px; |
| 24 | +} |
| 25 | + |
| 26 | +.abstractShortQuery .property a:not( :hover ):not( .new ) { |
| 27 | + /* don't show link color if property exists, but show it on :hover */ |
| 28 | + color: inherit; |
| 29 | + text-decoration: underline; |
| 30 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 31 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.js |
— | — | @@ -0,0 +1,15 @@ |
| 2 | +/** |
| 3 | + * JavasSript for context popup of the 'Semantic Expresiveness' extension. |
| 4 | + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 5 | + * |
| 6 | + * @since 0.1 |
| 7 | + * @ingroup Semantic Expresiveness |
| 8 | + * |
| 9 | + * @licence GNU GPL v3+ |
| 10 | + * @author Daniel Werner < danweetz at web dot de > |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * Module for 'Semantic Expresiveness' extensions user interface elements. |
| 15 | + */ |
| 16 | +window.semanticExpresiveness.ui = {}; |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 17 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.InlineMeasurer.js |
— | — | @@ -0,0 +1,84 @@ |
| 2 | +/** |
| 3 | + * JavasSript to measure some multi-line inline element. |
| 4 | + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 5 | + * |
| 6 | + * @since 0.1 |
| 7 | + * @ingroup Semantic Expresiveness |
| 8 | + * |
| 9 | + * @licence GNU GPL v3+ |
| 10 | + * @author Daniel Werner < danweetz at web dot de > |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * The InlineMeasurer helps to get some information about multi-line inline elements, |
| 15 | + * like where does the element start in the first line, where does it end in the last |
| 16 | + * line and how many lines does it have. |
| 17 | + */ |
| 18 | +window.semanticExpresiveness.ui.InlineMeasurer = {}; |
| 19 | + |
| 20 | +/** |
| 21 | + * Function to meassure some inline element. The function has to temporarily modify the |
| 22 | + * element and add some <span/> at its beginning and end. |
| 23 | + * @returns semanticExpresiveness.ui.InlineMeasurer.Measurement |
| 24 | + * |
| 25 | + * @ToDo: Add support and test this for right-to-left languages |
| 26 | + * |
| 27 | + * Note: This would be possible with getClientRects() as well. But it has poor browser |
| 28 | + * support (IE6+7 zoom behavior). |
| 29 | + */ |
| 30 | +window.semanticExpresiveness.ui.InlineMeasurer.measure = function( element ) { |
| 31 | + var elem = $( element ); |
| 32 | + var result = new window.semanticExpresiveness.ui.InlineMeasurer.Measurement( element ); |
| 33 | + |
| 34 | + // add helpers into dom: |
| 35 | + var helper1 = $( '<span/>' ); |
| 36 | + var helper2 = $( '<span/>' ); |
| 37 | + elem.prepend( helper1 ); |
| 38 | + elem.append( helper2 ); |
| 39 | + |
| 40 | + // measure: |
| 41 | + result.isOneLiner = helper1.position().top === helper2.position().top; |
| 42 | + result.firstLineWidth = elem.outerWidth() - ( helper1.offset().left - elem.offset().left ); |
| 43 | + result.lastLineOffset = helper2.offset().left - elem.offset().left; |
| 44 | + |
| 45 | + // destroy helper objects: |
| 46 | + helper1.empty().remove() |
| 47 | + helper2.empty().remove() |
| 48 | + |
| 49 | + return result; |
| 50 | +} |
| 51 | + |
| 52 | +/** |
| 53 | + * Constructor for Object returned by measure() function. |
| 54 | + */ |
| 55 | +window.semanticExpresiveness.ui.InlineMeasurer.Measurement = function( element ) { |
| 56 | + this.element = element; |
| 57 | +}; |
| 58 | +window.semanticExpresiveness.ui.InlineMeasurer.Measurement.prototype = { |
| 59 | + /** |
| 60 | + * The element the other informations relate to. Be aware that the related informations |
| 61 | + * could be 'wrong' due to some DOM updates or other influences already. |
| 62 | + */ |
| 63 | + element: null, |
| 64 | + |
| 65 | + /* |
| 66 | + * Whether the inline-element spreads over several lines. This can change after text or DOM |
| 67 | + * have been modified or even when re-sizing the browsers viewport. |
| 68 | + * @var boolean |
| 69 | + */ |
| 70 | + isOneLiner: true, |
| 71 | + |
| 72 | + /** |
| 73 | + * Width of the first line. In case the element spreads over several lines, the first and the |
| 74 | + * last line could be shorter as the whole elements width. |
| 75 | + * @var integer |
| 76 | + */ |
| 77 | + firstLineWidth: 0, |
| 78 | + |
| 79 | + /** |
| 80 | + * Width of the last line. In case the element spreads over several lines, the first and the |
| 81 | + * last line could be shorter as the whole elements width. |
| 82 | + * @var integer |
| 83 | + */ |
| 84 | + lastLineWidth: 0 |
| 85 | +}; |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.InlineMeasurer.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 86 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ContextPopup.css |
— | — | @@ -0,0 +1,75 @@ |
| 2 | + |
| 3 | +#ui-contextpopup-store { position: absolute; top: 0; left: 0; margin: 0; padding: 0; } |
| 4 | + |
| 5 | +/* The actual visible popup */ |
| 6 | +.ui-contextpopup { |
| 7 | + position: absolute; |
| 8 | + z-index: 999; |
| 9 | + padding: 0; |
| 10 | +} |
| 11 | + |
| 12 | +.ui-contextpopup-subject { |
| 13 | +} |
| 14 | + |
| 15 | +.ui-contextpopup-subject-active { |
| 16 | + background-color: #f2f2f2; |
| 17 | +} |
| 18 | + |
| 19 | +.ui-contextpopup-ontop { |
| 20 | + padding-bottom: 10px; |
| 21 | +} |
| 22 | + |
| 23 | +.ui-contextpopup-onbottom { |
| 24 | + padding-top: 10px; |
| 25 | +} |
| 26 | + |
| 27 | +.ui-contextpopup-box { |
| 28 | + box-shadow: 0px 3px 6px rgba(0,0,0,0.4); |
| 29 | + -moz-box-shadow: 0px 3px 6px rgba(0,0,0,0.4); |
| 30 | + -webkit-box-shadow: 0px 3px 6px rgba(0,0,0,0.4); |
| 31 | + -khtml-box-shadow: 0px 3px 6px rgba(0,0,0,0.4); |
| 32 | + |
| 33 | + border-radius: 2px; |
| 34 | + -moz-border-radius: 2px; |
| 35 | + -webkit-border-radius: 2px; |
| 36 | + -khtml-border-radius: 2px; |
| 37 | + |
| 38 | + background-color: white; |
| 39 | + border: 1px #545454 solid; |
| 40 | + padding: 4px; |
| 41 | + height: auto; |
| 42 | + width: auto; |
| 43 | + min-width: 28px; |
| 44 | + min-height: 4px; |
| 45 | + z-index: auto; |
| 46 | +} |
| 47 | + |
| 48 | +.ui-contextpopup-pointer { |
| 49 | + position:absolute; |
| 50 | + height: 10px; |
| 51 | + width: 20px; |
| 52 | +} |
| 53 | + |
| 54 | +.ui-contextpopup-pointer { |
| 55 | + font-size:0px; /* for IE6 */ |
| 56 | + margin: 0; |
| 57 | + padding: 0; |
| 58 | +} |
| 59 | +.ui-contextpopup-onbottom .ui-contextpopup-pointer { |
| 60 | + background-image: url('./images/pointer-up.png'); |
| 61 | + top: 1px; |
| 62 | +} |
| 63 | +.ui-contextpopup-ontop .ui-contextpopup-pointer { |
| 64 | + background-image: url('./images/pointer-down.png'); |
| 65 | + bottom: 1px; |
| 66 | +} |
| 67 | +.ui-contextpopup-fromright .ui-contextpopup-pointer { |
| 68 | + left: 7px; |
| 69 | +} |
| 70 | +.ui-contextpopup-fromleft .ui-contextpopup-pointer { |
| 71 | + right: 7px; |
| 72 | +} |
| 73 | + |
| 74 | +.ui-contextpopup .ui-contextpopup-box * { |
| 75 | + float: none; |
| 76 | +} |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ContextPopup.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 77 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.js |
— | — | @@ -0,0 +1,36 @@ |
| 2 | +/** |
| 3 | + * JavasSript for the 'Semantic Expresiveness' extension. |
| 4 | + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 5 | + * |
| 6 | + * @since 0.1 |
| 7 | + * @ingroup Semantic Expresiveness |
| 8 | + * |
| 9 | + * @licence GNU GPL v3+ |
| 10 | + * @author Daniel Werner < danweetz at web dot de > |
| 11 | + */ |
| 12 | +window.semanticExpresiveness = new( function() { |
| 13 | + |
| 14 | + this.log = function( message ) { |
| 15 | + if( typeof mediaWiki === 'undefined' ) { |
| 16 | + if( typeof console !== 'undefined' ) { |
| 17 | + console.log( 'SemEx: ' + message ); |
| 18 | + } |
| 19 | + } |
| 20 | + else { |
| 21 | + return mediaWiki.log.call( mediaWiki.log, 'SemEx: ' + message ); |
| 22 | + } |
| 23 | + } |
| 24 | + |
| 25 | + // Initialize user interface stuff when ready |
| 26 | + jQuery( function( $ ) { |
| 27 | + // add popup ui functionality to short query results: |
| 28 | + var globalShortQueryInfoCache = new window.semanticExpresiveness.ui.ShortQueryHover.Cache; |
| 29 | + window.semanticExpresiveness.ui.ShortQueryHover.initialize( |
| 30 | + $( 'body' ), |
| 31 | + function( queryHover ) { // configuration per ShortQueryHover element |
| 32 | + queryHover.queryInfoCache = globalShortQueryInfoCache; |
| 33 | + } |
| 34 | + ); |
| 35 | + } ); |
| 36 | + |
| 37 | +} )(); |
\ No newline at end of file |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 38 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ShortQueryHover.css |
— | — | @@ -0,0 +1,29 @@ |
| 2 | +/** @TODO: make this all configurable instead of using those two classes */ |
| 3 | +.ui-contextpopup-shortqueryhover .freeInfoBox, |
| 4 | +.ui-contextpopup-shortqueryhover .NavFrame { |
| 5 | + margin: 0; |
| 6 | + border: none; |
| 7 | + min-width: 300px; |
| 8 | +} |
| 9 | + |
| 10 | +.ui-contextpopup-shortqueryhover .ui-contextpopup-titlepopup-title { |
| 11 | + font-weight: bold; |
| 12 | + white-space: nowrap; |
| 13 | +} |
| 14 | + |
| 15 | +.ui-contextpopup .semex-invalid-shortquery-format { |
| 16 | + color: red; |
| 17 | +} |
| 18 | + |
| 19 | +.ui-contextpopup-shortqueryhover .ui-contextpopup-titlepopup-content { |
| 20 | + font-size: 0.82em; |
| 21 | + font-family: verdana, sans-serif; |
| 22 | +} |
| 23 | + |
| 24 | +.semex-shortqueryinfo-loading, |
| 25 | +.semex-shortqueryinfo-loading-failed { |
| 26 | + font-style: italic; |
| 27 | +} |
| 28 | +.semex-shortqueryinfo-loading-failed { |
| 29 | + color: red; |
| 30 | +} |
\ No newline at end of file |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ShortQueryHover.css |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 31 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ShortQueryResult.js |
— | — | @@ -0,0 +1,145 @@ |
| 2 | +/** |
| 3 | + * JavasSript for representing some short query result |
| 4 | + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 5 | + * |
| 6 | + * @since 0.1 |
| 7 | + * @ingroup Semantic Expresiveness |
| 8 | + * |
| 9 | + * @licence GNU GPL v3+ |
| 10 | + * @author Daniel Werner < danweetz at web dot de > |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * Constructor for short query result representation within JavaScript. |
| 15 | + * @param Node element representing the short Query. |
| 16 | + * @throws Error in case the Short Query Result structure is invalid. |
| 17 | + */ |
| 18 | +window.semanticExpresiveness.ShortQueryResult = function( element ) { |
| 19 | + this._elem = $( element ); |
| 20 | + |
| 21 | + // validation for the short query result: |
| 22 | + if( |
| 23 | + this.getSource() === false |
| 24 | + || this.getProperty() === false |
| 25 | + || this.isAbstractResult() === false |
| 26 | + && ( this.getRawResult() === null || this.getResult() === null ) |
| 27 | + ) { |
| 28 | + throw new Error( 'Invalid Short Query Result structure detected' ); |
| 29 | + } |
| 30 | +}; |
| 31 | +window.semanticExpresiveness.ShortQueryResult.prototype = { |
| 32 | + /** |
| 33 | + * @var jQuery |
| 34 | + */ |
| 35 | + _elem: null, |
| 36 | + _querySource: null, |
| 37 | + _queryProperty: null, |
| 38 | + _queryRawResult: null, |
| 39 | + |
| 40 | + /** |
| 41 | + * Returns the node in the DOM representing this short query result. |
| 42 | + * @return Node |
| 43 | + */ |
| 44 | + getDOMNode: function() { |
| 45 | + return this._elem; |
| 46 | + }, |
| 47 | + |
| 48 | + /** |
| 49 | + * Returns whether this short query result is an abstract result for some reason, most likely |
| 50 | + * the query failed in this case. |
| 51 | + * @return bool |
| 52 | + */ |
| 53 | + isAbstractResult: function() { |
| 54 | + return this._elem.hasClass( 'abstractShortQuery' ); |
| 55 | + }, |
| 56 | + |
| 57 | + /** |
| 58 | + * Returns the local page name of the page the displayed query information was taken from. |
| 59 | + * In case this is an abstract short query result, it is possible that the source was another |
| 60 | + * unsuccessful short query. In this case, null will be returned. |
| 61 | + * @return string|null |
| 62 | + */ |
| 63 | + getSource: function() { |
| 64 | + if( this._querySource !== null ) { |
| 65 | + return this._querySource; |
| 66 | + } |
| 67 | + this._querySource = this._getShortQueryInfo( 'source' ); |
| 68 | + |
| 69 | + if( this._querySource === false |
| 70 | + && this.isAbstractResult() |
| 71 | + && this._elem.children( '.source' ).length == 1 |
| 72 | + ) { |
| 73 | + // abstract result and another short query as source! |
| 74 | + this._querySource = null; |
| 75 | + } |
| 76 | + return this._querySource; |
| 77 | + }, |
| 78 | + |
| 79 | + /** |
| 80 | + * Returns the property name of the queried value. |
| 81 | + * @return string |
| 82 | + */ |
| 83 | + getProperty: function() { |
| 84 | + if( this._queryProperty !== null ) { |
| 85 | + return this._queryProperty; |
| 86 | + } |
| 87 | + this._queryProperty = this._getShortQueryInfo( 'type' ); |
| 88 | + return this._queryProperty; |
| 89 | + }, |
| 90 | + |
| 91 | + /** |
| 92 | + * Returns the unformatted, raw result of the query. Returns null in case the query went wrong. |
| 93 | + * @return string[]|null |
| 94 | + */ |
| 95 | + getRawResult: function() { |
| 96 | + if( this._queryRawResult !== null ) { |
| 97 | + return this._queryRawResult; |
| 98 | + } |
| 99 | + |
| 100 | + // query result can have several values which are stored within the title of child elements |
| 101 | + // of the short queries direct child with class 'value' |
| 102 | + values = this._elem.children( '.value' ).children( '*[title]' ); |
| 103 | + if( values.length < 1 ) { |
| 104 | + return null; |
| 105 | + } |
| 106 | + |
| 107 | + // put all values into an array: |
| 108 | + var titles = new Array( values.length ); |
| 109 | + |
| 110 | + values.each( function( index, elem ) { |
| 111 | + titles[index] = $( elem ).attr( 'title' ) |
| 112 | + } ); |
| 113 | + |
| 114 | + this._queryRawResult = titles; |
| 115 | + return titles; |
| 116 | + }, |
| 117 | + |
| 118 | + /** |
| 119 | + * Returns the DOM elements which are part of the formatted result. Returns null in case the query |
| 120 | + * went wrong. For unformatted result see getRawResult() function. |
| 121 | + * @return jQuery|null |
| 122 | + */ |
| 123 | + getResult: function() { |
| 124 | + var result = this._elem.children( '.result' ); |
| 125 | + if( result.length != 1 ) { |
| 126 | + return null |
| 127 | + } |
| 128 | + return result.contents(); |
| 129 | + }, |
| 130 | + |
| 131 | + /** |
| 132 | + * Generic helper to get attached information from the short queries DOM. |
| 133 | + * @param info string class name of the element where the information lays within the 'title' |
| 134 | + */ |
| 135 | + _getShortQueryInfo: function( info ) { |
| 136 | + var title = this._elem.children( '.' + info + '[title]' ); |
| 137 | + if( title.length != 1 ) { |
| 138 | + return false; |
| 139 | + } |
| 140 | + title = $.trim( title.attr( 'title' ) ); |
| 141 | + if( title === '' ) { |
| 142 | + return false; |
| 143 | + } |
| 144 | + return title; |
| 145 | + } |
| 146 | +}; |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ShortQueryResult.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 147 | + native |
Index: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ContextPopup.js |
— | — | @@ -0,0 +1,810 @@ |
| 2 | +/** |
| 3 | + * JavasSript for context popup of the 'Semantic Expresiveness' extension. |
| 4 | + * @see https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness |
| 5 | + * |
| 6 | + * @since 0.1 |
| 7 | + * @ingroup Semantic Expresiveness |
| 8 | + * |
| 9 | + * @licence GNU GPL v3+ |
| 10 | + * @author Daniel Werner < danweetz at web dot de > |
| 11 | + */ |
| 12 | + |
| 13 | +/** |
| 14 | + * Constructor for context popup container which pops up whenever hovering over a defined |
| 15 | + * inline-element. |
| 16 | + * The context popups content can contain further popups. This works as long as the popups |
| 17 | + * POPUP_CLASS and POPUP_STORE_ID are the same. Having several popups assigned to the same |
| 18 | + * element or to sub-elements is very buggy and needs fixing if required for some reason. |
| 19 | + * |
| 20 | + * The Popups themselves are not part of the the subjects DOM. They are stored within a |
| 21 | + * store for all popups. There were several reasons for this decission, adding the popup |
| 22 | + * to the subjects DOM only worked until a certain point, it practically got too buggy. |
| 23 | + * |
| 24 | + * Known Bugs (all minor): |
| 25 | + * ======================= |
| 26 | + * Opera/IE: Mouse-Events (mostly) don't get triggered for an element when the mouse didn't do |
| 27 | + * anything but the element dynamically appears/disappeary under the mouse. This might |
| 28 | + * lead to some bugs we don't have in Firefox. |
| 29 | + * |
| 30 | + * - Bug #101 (Opera/IE): |
| 31 | + * When mouse leaves sub-popup, the popup fades out but the mouse goes right back in and then |
| 32 | + * doesn't moove till some time after the sub-popup is completely gone, the parent popupS will |
| 33 | + * close as well because the mouse event doesn't get triggered unline the mouse moves again! |
| 34 | + * This can't just be solved by adding another event to the fading popup since then the mouse |
| 35 | + * could go to space outside of parent popup without the parent being closed. |
| 36 | + * |
| 37 | + * - Bug #102 (Opera/IE): |
| 38 | + * When content changes by using setContent() and the mouse is positioned within the popup and |
| 39 | + * doesn't move untill the fade timer ran out, the popup will fade even though the mouse is |
| 40 | + * positioned within. Event only gets triggered when mouse moves/clicks. window.scrollTo() |
| 41 | + * workaround doesn't really work, it doesn't trigger any mouse event. |
| 42 | + * |
| 43 | + * @param subject Object the html dom element the context popup should be related to |
| 44 | + */ |
| 45 | +window.semanticExpresiveness.ui.ContextPopup = function( subject ) { |
| 46 | + // alternative to any $parent or _super nonsens. At lest this save a few bytes of code |
| 47 | + this.$package = window.semanticExpresiveness.ui; |
| 48 | + |
| 49 | + // increase instances count to give IDs to popups |
| 50 | + this._id = this.$package.ContextPopup.instances++; |
| 51 | + this.POPUP_ID = this.POPUP_CLASS + '-' + this._id; |
| 52 | + |
| 53 | + if( typeof subject != 'undefined' ) { |
| 54 | + this._init( subject ); |
| 55 | + } |
| 56 | +}; |
| 57 | +window.semanticExpresiveness.ui.ContextPopup.instances = 0; |
| 58 | +window.semanticExpresiveness.ui.ContextPopup.prototype = { |
| 59 | + /** |
| 60 | + * @const |
| 61 | + * @enum number |
| 62 | + */ |
| 63 | + PARTS: { |
| 64 | + SUBJECT: 1, |
| 65 | + POPUP: 2 |
| 66 | + }, |
| 67 | + |
| 68 | + /** |
| 69 | + * @const |
| 70 | + * @enum number |
| 71 | + */ |
| 72 | + ORIENTATION: { |
| 73 | + TOP: 1, |
| 74 | + BOTTOM: 2, |
| 75 | + LEFT: 3, |
| 76 | + RIGHT: 4 |
| 77 | + }, |
| 78 | + |
| 79 | + TIME_TO_FIRST_NOTICE: 175, // time the mouse has to stay on the subject untill the popup fades in |
| 80 | + TIME_TO_FADE_IN: 125, |
| 81 | + TIME_TO_FADE_OUT: 150, // has to be lower than this.TIME_TO_REENTER time! |
| 82 | + TIME_TO_REENTER: 333, // time after mouse has left popup untill the popup finally fades |
| 83 | + // time after content-update to enter mouse to avoid bug #102 or in case popups position has changed: |
| 84 | + TIME_TO_REENTER_ON_UPDATE: 1750, |
| 85 | + |
| 86 | + /** |
| 87 | + * @const |
| 88 | + * Class which marks a popup within the site html. |
| 89 | + */ |
| 90 | + POPUP_CLASS: 'ui-contextpopup', |
| 91 | + |
| 92 | + /** |
| 93 | + * @const |
| 94 | + * ID of the popup which can be used within DOM or for events. |
| 95 | + */ |
| 96 | + POPUP_ID: null, // POPUP_CLASS + _id (set by constructor) |
| 97 | + |
| 98 | + /** |
| 99 | + * @const |
| 100 | + * ID to identify the popup store where the popups dom will temporarily be stored at. |
| 101 | + */ |
| 102 | + POPUP_STORE_ID: 'ui-contextpopup-store', |
| 103 | + |
| 104 | + /** |
| 105 | + * Element the popup is related to. |
| 106 | + * @var jQuery |
| 107 | + */ |
| 108 | + _subject: null, |
| 109 | + |
| 110 | + /** |
| 111 | + * Content which should be displayed by the context popup. |
| 112 | + * Set this from outside by using setContent() |
| 113 | + * @var jQuery |
| 114 | + */ |
| 115 | + _content: $( '<div style="font-style:italic;">No information available</div>' ), |
| 116 | + |
| 117 | + /** |
| 118 | + * Element which temporarily stores popup dom. |
| 119 | + * @var jQuery|null |
| 120 | + */ |
| 121 | + _popupStore: null, |
| 122 | + |
| 123 | + /** |
| 124 | + * An unique ID for the popup instance to keep track of its events. |
| 125 | + * @var integer |
| 126 | + */ |
| 127 | + _id: null, |
| 128 | + |
| 129 | + /** |
| 130 | + * Contains the popup in case it is visible currently. |
| 131 | + * @var jQuery|null |
| 132 | + */ |
| 133 | + _popup: null, |
| 134 | + |
| 135 | + /** |
| 136 | + * Whether the box is visible currently. |
| 137 | + * @var boolean |
| 138 | + */ |
| 139 | + _visible: false, |
| 140 | + |
| 141 | + /** |
| 142 | + * Contains the current orientation of the box. If it isn't visible at the moment this |
| 143 | + * will be set to null. |
| 144 | + * @var Object|null |
| 145 | + */ |
| 146 | + _orientation: null, |
| 147 | + |
| 148 | + /** |
| 149 | + * Equals one of this.PARTS properties to give information about which part of the ui element |
| 150 | + * was last and still is touched. In case the mouse is outside, this is set to null |
| 151 | + * In case this.isTouchable is set to false, this won't be set to this.PARTS.POPUP |
| 152 | + * @var integer|null |
| 153 | + */ |
| 154 | + _touchedPart: null, |
| 155 | + |
| 156 | + /** |
| 157 | + * Initialize the context popup and assign it to some html element. |
| 158 | + * This should normally be called directly by the constructor. |
| 159 | + */ |
| 160 | + _init: function( subject ) { |
| 161 | + if( this._subject !== null ) { |
| 162 | + // initializing twice should never happen, have to destroy first! |
| 163 | + this.destroy(); |
| 164 | + } |
| 165 | + this._subject = $( subject ); |
| 166 | + this._subject.addClass( this.POPUP_CLASS + '-subject' ); |
| 167 | + // kind of bind this object to the element so parents can find their child context popups |
| 168 | + this._subject.data( this.POPUP_CLASS, this ); |
| 169 | + |
| 170 | + // remove title so it won't get in the way of the popup |
| 171 | + this._subject.data( this.POPUP_ID + '-origTitle', this._subject.attr( 'title' ) ); |
| 172 | + this._subject.removeAttr( 'title' ); |
| 173 | + |
| 174 | + // register events for associated popup trigger: |
| 175 | + var self = this; |
| 176 | + this._subject.bind( |
| 177 | + 'mouseenter.' + this.POPUP_ID, |
| 178 | + function() { self._hoverInFunc( self.PARTS.SUBJECT ) } |
| 179 | + ).bind( |
| 180 | + 'mouseleave.' + this.POPUP_ID, |
| 181 | + function() { self._hoverOutFunc() } |
| 182 | + ); |
| 183 | + }, |
| 184 | + |
| 185 | + /** |
| 186 | + * Savely removes the popup and associated events from the DOM |
| 187 | + */ |
| 188 | + destroy: function() { |
| 189 | + if( this._id === null ) { |
| 190 | + return; |
| 191 | + } |
| 192 | + this._subject |
| 193 | + .unbind( '.' + this.POPUP_ID ) |
| 194 | + // restore original title which was removed before: |
| 195 | + .attr( 'title', this._subject.data( this.POPUP_ID + '-origTitle' ) ); |
| 196 | + |
| 197 | + this._subject |
| 198 | + .removeData( this.POPUP_ID + '-origTitle' ) |
| 199 | + .removeData( this.POPUP_CLASS ) |
| 200 | + .removeClass( this.POPUP_CLASS + '-subject' ) |
| 201 | + .removeClass( this.POPUP_CLASS + '-subject-active' ); |
| 202 | + |
| 203 | + if( this._popup !== null ) { |
| 204 | + this._popup.empty().remove(); |
| 205 | + } |
| 206 | + }, |
| 207 | + |
| 208 | + _hoverInFunc: function( part ) { |
| 209 | + this._touchedPart = part; |
| 210 | + // abord countdown to close() |
| 211 | + this._clearTimeTillFade(); |
| 212 | + |
| 213 | + if( ! this.isVisible() ) { |
| 214 | + // wait short time before opening popup, so fast mouse movments over document won't |
| 215 | + // unintendedly trigger too many popups. |
| 216 | + this._setTimeTillDisplay( this.TIME_TO_FIRST_NOTICE ); |
| 217 | + } |
| 218 | + }, |
| 219 | + _hoverOutFunc: function() { |
| 220 | + var lastTouched = this._touchedPart; |
| 221 | + this._touchedPart = null; |
| 222 | + if( ! this.isVisible() ) { |
| 223 | + // abord countdown to show() |
| 224 | + this._clearTimeTillDisplay(); |
| 225 | + } |
| 226 | + else { |
| 227 | + activeChild = this.getActiveChild(); |
| 228 | + |
| 229 | + if( lastTouched === this.PARTS.SUBJECT |
| 230 | + && activeChild !== null |
| 231 | + && activeChild._touchedPart !== null |
| 232 | + ) { |
| 233 | + // we entered, not left some sub-popup, so don't close anything! |
| 234 | + return; |
| 235 | + } |
| 236 | + |
| 237 | + if( lastTouched !== this.PARTS.SUBJECT ) { |
| 238 | + // consider closing all parents if mouse doesn't touch any in time |
| 239 | + this._setTimeTillFadeParents( this.TIME_TO_REENTER ); |
| 240 | + } else { |
| 241 | + // mouse entered parent popup since last touched part is the subject which has to be |
| 242 | + // a part of the parent (if any parent popup exists) |
| 243 | + this._setTimeTillFade( this.TIME_TO_REENTER ); |
| 244 | + } |
| 245 | + } |
| 246 | + }, |
| 247 | + |
| 248 | + /** |
| 249 | + * Sets the time the mouse has to be somewhere where the popup gets triggered to actually display |
| 250 | + * the popup. |
| 251 | + * @param time integer |
| 252 | + * @param callback Function executed after this.show() (optional) |
| 253 | + */ |
| 254 | + _setTimeTillDisplay: function( time, callback ) { |
| 255 | + var self = this; |
| 256 | + var timeoutId = setTimeout( function(){ |
| 257 | + self.show(); |
| 258 | + if( typeof callback != 'undefined' ) { |
| 259 | + callback(); |
| 260 | + } |
| 261 | + }, time ); |
| 262 | + $( this ).data( this.POPUP_ID + '-enterTimeoutId', timeoutId ); |
| 263 | + }, |
| 264 | + _clearTimeTillDisplay: function() { |
| 265 | + clearTimeout( $( this ).data( this.POPUP_ID + '-enterTimeoutId' ) ); |
| 266 | + }, |
| 267 | + |
| 268 | + /** |
| 269 | + * Sets the time left untill the popup will be closed if the mouse doesn't re-activate it somehow. |
| 270 | + * @param time integer |
| 271 | + * @param callback Function executed after this.close() (optional) |
| 272 | + */ |
| 273 | + _setTimeTillFade: function( time, callback ) { |
| 274 | + var self = this; |
| 275 | + var timeoutId = setTimeout( function(){ |
| 276 | + self.close(); |
| 277 | + if( typeof callback != 'undefined' ) { |
| 278 | + callback(); |
| 279 | + } |
| 280 | + }, time ); |
| 281 | + $( this ).data( this.POPUP_ID + '-fadeTimeoutId', timeoutId ); |
| 282 | + }, |
| 283 | + /** |
| 284 | + * Same as _setTimeTillFade() but also does the same for all parent-popups. |
| 285 | + * @param time integer |
| 286 | + * @param callback Function exectued for each affected popup after this.close() (optional) |
| 287 | + */ |
| 288 | + _setTimeTillFadeParents: function( time, callback ) { |
| 289 | + // fade this popup first, then first parent all up the chain |
| 290 | + this._setTimeTillFade( time, callback ); |
| 291 | + // do the same for all parents: |
| 292 | + var parent = this.getParent(); |
| 293 | + if( parent !== null ){ |
| 294 | + parent._setTimeTillFadeParents( time, callback ); |
| 295 | + } |
| 296 | + }, |
| 297 | + /** |
| 298 | + * Cancels the timer till popup will fade. This also stops the timer for all parents since a |
| 299 | + * popup can't exist without its parent. |
| 300 | + */ |
| 301 | + _clearTimeTillFade: function() { |
| 302 | + // do the same for all parents: |
| 303 | + var parent = this.getParent(); |
| 304 | + if( parent !== null ){ |
| 305 | + parent._clearTimeTillFade(); |
| 306 | + } |
| 307 | + // stop parent from fading first^^ |
| 308 | + clearTimeout( $( this ).data( this.POPUP_ID + '-fadeTimeoutId' ) ); |
| 309 | + }, |
| 310 | + |
| 311 | + /** |
| 312 | + * Returns the element where the popup elements will temporarily be stored. If no store |
| 313 | + * exists yet, this will create one. |
| 314 | + * @return jQuery |
| 315 | + */ |
| 316 | + getPopupStore: function() { |
| 317 | + if( ! this._popupStore ) { |
| 318 | + var store = $( '#' + this.POPUP_STORE_ID ); |
| 319 | + if( store.length == 0 ) { |
| 320 | + // no store yet, create it |
| 321 | + var store = $( '<div/>', { |
| 322 | + 'id': this.POPUP_STORE_ID |
| 323 | + } |
| 324 | + ); |
| 325 | + store.appendTo( '#bodyContent' ); // place for MWs content, to have proper css for popups |
| 326 | + } |
| 327 | + this._popupStore = store; |
| 328 | + } |
| 329 | + return this._popupStore; |
| 330 | + }, |
| 331 | + |
| 332 | + /** |
| 333 | + * Returns the popups current orientation or null if its not displayed right now. |
| 334 | + * @return integer|null |
| 335 | + */ |
| 336 | + getOrientation: function() { |
| 337 | + return this._orientation; |
| 338 | + }, |
| 339 | + |
| 340 | + /** |
| 341 | + * Function for (re)rendering the box at the ideal place, taking the boxes size and current |
| 342 | + * position of the subject element relative to the current viewport in acount. If the box is not |
| 343 | + * visible right now, this will not activate the box, use the show() function instead. |
| 344 | + * @param orientation Object containing values from this.ORIENTATION for the properties 'horizontal' |
| 345 | + * and 'vertical' if any specific orientation should be forced. (optional) |
| 346 | + * @returns boolean whether any (re)drawing did happen. |
| 347 | + */ |
| 348 | + draw: function( orientation ) { |
| 349 | + if( ! this.isVisible ) { |
| 350 | + // nothing to draw! |
| 351 | + return false; |
| 352 | + } |
| 353 | + |
| 354 | + var isUpdate = this._popup !== null; // is this a update of the content while popup is visible? |
| 355 | + |
| 356 | + // append popup here so css is taken into account for POSITIONING calculations |
| 357 | + divPopup = this._draw_buildPopup(); |
| 358 | + if( isUpdate ) { |
| 359 | + // detach popup so we can be 100% sure that the mouseenter event gets fired in case |
| 360 | + // re-positioning doesn't change position and mouse is still within popup |
| 361 | + divPopup.detach(); |
| 362 | + } |
| 363 | + divPopup.appendTo( this.getPopupStore() ); |
| 364 | + |
| 365 | + if( typeof orientation == 'undefined' ) { |
| 366 | + // calculate popup box positioning: |
| 367 | + orientation = this.getIdealAlignment( divPopup ); |
| 368 | + } |
| 369 | + |
| 370 | + this._popup = divPopup; |
| 371 | + this._orientation = orientation; |
| 372 | + |
| 373 | + // POSITIONING of the popup |
| 374 | + this._draw_doPositioning(); |
| 375 | + |
| 376 | + if( isUpdate // if we update the popups content while it is still visible |
| 377 | + && this._touchedPart != this.PARTS.SUBJECT // and mouse possibly within popup |
| 378 | + ) { |
| 379 | + // will be triggered even if mouse still within popup since we detached the popup before. |
| 380 | + // in case the mouse is outside the new popup, this leaves us with enough time to enter the popup. |
| 381 | + this._setTimeTillFadeParents( this.TIME_TO_REENTER_ON_UPDATE ); |
| 382 | + self._touchedPart = null; // parents should be set to null already |
| 383 | + //this._draw_contentUpdateCleanup( divPopup, orientation ); |
| 384 | + |
| 385 | + // FIXME: no solution for Bug #102 yet. (window.scrollTo() no solution, doesn't trigger mouse event) |
| 386 | + } |
| 387 | + |
| 388 | + this._popup.hide().fadeIn( this.TIME_TO_FADE_IN ); |
| 389 | + |
| 390 | + return true; |
| 391 | + }, |
| 392 | + |
| 393 | + /** |
| 394 | + * Sub-routine of this.draw() to do the positioning so the popup will appear relative |
| 395 | + * to the triggering subject element. |
| 396 | + */ |
| 397 | + _draw_doPositioning: function() { |
| 398 | + // Consider that the popup store might not be at position 0;0 ! |
| 399 | + var popupStoreOffset = this.getPopupStore().offset(); |
| 400 | + var divPopup = this._popup; |
| 401 | + // get pointer to add ontop/onbottom class for it as well... IE6 support once again... |
| 402 | + var divPointer = divPopup.children( '.' + this.POPUP_CLASS + '-pointer' ) |
| 403 | + |
| 404 | + // calc Y: |
| 405 | + var posY = this._subject.offset().top - popupStoreOffset.top; |
| 406 | + if( this._orientation.vertical === this.ORIENTATION.TOP ) { // get Y |
| 407 | + // above subject |
| 408 | + var yClassSuffix = '-ontop'; |
| 409 | + divPopup.addClass( this.POPUP_CLASS + '-ontop' ) |
| 410 | + divPointer.addClass( this.POPUP_CLASS + '-pointer-ontop' ); |
| 411 | + posY -= divPopup.outerHeight(); // height is different after classes are applied! |
| 412 | + } else { |
| 413 | + // underneath subject |
| 414 | + var yClassSuffix = '-onbottom'; |
| 415 | + divPopup.addClass( this.POPUP_CLASS + '-onbottom' ) |
| 416 | + divPointer.addClass( this.POPUP_CLASS + '-pointer-onbottom' ); |
| 417 | + posY += this._subject.outerHeight(); |
| 418 | + } |
| 419 | + |
| 420 | + // calc X: |
| 421 | + var posX = -popupStoreOffset.left; |
| 422 | + if( this._orientation.horizontal === this.ORIENTATION.LEFT ) { |
| 423 | + // expand to left |
| 424 | + divPopup.addClass( this.POPUP_CLASS + '-fromleft' ); |
| 425 | + posX += this._subject.offset().left + this._subject.outerWidth() - divPopup.outerWidth() // <<left |
| 426 | + } else { |
| 427 | + // expand to right |
| 428 | + divPopup.addClass( this.POPUP_CLASS + '-fromright' ); |
| 429 | + posX += this._subject.offset().left; // right>> |
| 430 | + } |
| 431 | + // if popup would leave viewport (-10px tollerance), move it to the left until it fits... |
| 432 | + var popupEndX = popupStoreOffset.left + posX + divPopup.outerWidth() + 10; |
| 433 | + var viewPortEndeX = $( window ).scrollLeft() + $( window ).width(); |
| 434 | + var xOverflow = popupEndX - viewPortEndeX; |
| 435 | + var origPosX = posX; |
| 436 | + var xPointerMarging = 0; |
| 437 | + if( xOverflow > 0 ) { |
| 438 | + posX -= xOverflow; |
| 439 | + xPointerMarging = xOverflow; |
| 440 | + } |
| 441 | + if( posX + popupStoreOffset.left <= 10 ) { |
| 442 | + // ... except this would put the popup too far left |
| 443 | + posX = -popupStoreOffset.left + 10; // 10px tollerance |
| 444 | + xOverflow = origPosX - posX; |
| 445 | + } |
| 446 | + |
| 447 | + // apply calculated coordinates |
| 448 | + divPopup.css( 'top', posY + 'px' ); |
| 449 | + divPopup.css( 'left', posX + 'px' ); |
| 450 | + |
| 451 | + // get popups pointer for adjustments |
| 452 | + divPointer = divPopup.children( '.' + this.POPUP_CLASS + '-pointer' ); |
| 453 | + |
| 454 | + // if pointer goes over the right edge, move it to the edge and cut it nicely. |
| 455 | + // this basically happens when popup is cut off on the right side by the viewport. |
| 456 | + var margingSide = 'left'; |
| 457 | + var pointerEndX = xPointerMarging + divPointer.position().left + divPointer.width(); |
| 458 | + if( pointerEndX > divPopup.outerWidth() ) { |
| 459 | + var divBox = divPopup.children( '.' + this.POPUP_CLASS + '-box' ); |
| 460 | + divPointer.css( 'border-right', divBox.css( 'border-right' ) ); |
| 461 | + divPointer.css( 'width', divPointer.width() / 2 ); |
| 462 | + if( this._orientation.horizontal == this.ORIENTATION.RIGHT ) { |
| 463 | + xPointerMarging = divPopup.outerWidth() - ( divPointer.position().left + divPointer.outerWidth() ); |
| 464 | + xPointerMarging += 'px'; |
| 465 | + } else { |
| 466 | + xPointerMarging = '-' + divPointer.css( 'right' ); |
| 467 | + margingSide = 'right'; |
| 468 | + } |
| 469 | + } |
| 470 | + |
| 471 | + divPointer.css( 'margin-' + margingSide, xPointerMarging ); |
| 472 | + }, |
| 473 | + |
| 474 | + /** |
| 475 | + * Called by this.draw() when the popups html for the dom has to be built. |
| 476 | + */ |
| 477 | + _draw_buildPopup: function() { |
| 478 | + /* |
| 479 | + * Inner div necessary because we need outer divs marging for the relative positioning. |
| 480 | + * The inner divs marging is just good for some space between subject and box. |
| 481 | + */ |
| 482 | + var divPopup; // outer div (for position marging/positioning) |
| 483 | + |
| 484 | + if( this._popup === null ) { |
| 485 | + divPopup = $( '<div/>' ); |
| 486 | + |
| 487 | + // if mouse can touch te popup: |
| 488 | + if( this.isTouchable ) { |
| 489 | + // when moving mouse from popup trigger element into popup, don't destroy popup! |
| 490 | + var self = this; |
| 491 | + divPopup.hover( |
| 492 | + function() {self._hoverInFunc( self.PARTS.POPUP )}, |
| 493 | + function() {self._hoverOutFunc()} |
| 494 | + ); |
| 495 | + } |
| 496 | + } |
| 497 | + else { |
| 498 | + // just clean-up the existing popup for re-using it |
| 499 | + divPopup = this._draw_existingPopupCleanup( this._popup ); |
| 500 | + } |
| 501 | + |
| 502 | + divPopup |
| 503 | + .addClass( this.POPUP_CLASS + ' ' + this.POPUP_ID ) |
| 504 | + .data( this.POPUP_CLASS, this ); // bind this object to element so child popups can get its parent |
| 505 | + |
| 506 | + var divContent = $( '<div/>', { // inner div (for shadow and box shape + style marging) |
| 507 | + 'class': this.POPUP_CLASS + '-box' |
| 508 | + } ); |
| 509 | + var divPointer = $( '<div/>', { // div for arrow |
| 510 | + 'class': this.POPUP_CLASS + '-pointer' |
| 511 | + } ); |
| 512 | + |
| 513 | + divContent |
| 514 | + .append( this._content ) // actual content |
| 515 | + .appendTo( divPopup ); |
| 516 | + |
| 517 | + divPointer.appendTo( divPopup ); |
| 518 | + |
| 519 | + return divPopup; |
| 520 | + }, |
| 521 | + |
| 522 | + /** |
| 523 | + * Sub-Function of this._draw_buildPopup(), gets called when this.setContent() changes the content |
| 524 | + * which leads to a re-draw. In that case we don't destroy the original popup but rather clean up |
| 525 | + * what's necessary on the old one and re-use it. |
| 526 | + * Basically this removes all children, css-styles and classes. |
| 527 | + * @param divPopup jQuery the old popup |
| 528 | + * @return jQuery the cleaned-up popup |
| 529 | + */ |
| 530 | + _draw_existingPopupCleanup: function( divPopup ) { |
| 531 | + divPopup.children().empty().remove(); |
| 532 | + return divPopup |
| 533 | + .removeAttr( 'class' ) |
| 534 | + .removeAttr( 'style' ); |
| 535 | + }, |
| 536 | + |
| 537 | + /** |
| 538 | + * Called whenever the popups content gets updated while the popup is still being displayed. |
| 539 | + * In this case the popup size might change and perhaps it will be re-aligned which could |
| 540 | + * lead to the mouse suddenly being outside of the popup. In this case some cleanup has to be |
| 541 | + * done so the popup will fade out if the mouse doesn't re-enter soon. |
| 542 | + * |
| 543 | + * FIXME: IE 6+7 & Opera Bug: In case mouse is positioned within old popup content and after new |
| 544 | + * content is applied the mouse doesn't move untill the fade timeout is out, the mosue |
| 545 | + * event will not be triggered and therefore the popup will be closed. |
| 546 | + * > This could be fixed with some permanent 'mousemove' event caching mouse position. |
| 547 | + * > Might be worse performance but less complicated than current handling. |
| 548 | + */ |
| 549 | + /* |
| 550 | + _draw_contentUpdateCleanup: function( newPopup, newOrientation ) { |
| 551 | + this._popup.unbind(); |
| 552 | + this._popup.empty().remove(); |
| 553 | + |
| 554 | + if( this._touchedPart != this.PARTS.SUBJECT ) { |
| 555 | + if( newOrientation.vertical != this._orientation.vertical ) { |
| 556 | + // popup now displayed on the other side, mouse must be outside now! |
| 557 | + this._touchedPart = null; |
| 558 | + this._setTimeTillFade( 1250 ); |
| 559 | + } |
| 560 | + else { |
| 561 | + // mouse could still be inside, no certainty! |
| 562 | + var self = this; |
| 563 | + var mouseMoveUnbind = function() { |
| 564 | + self._subject.unbind( '.ContextPopupUpdateCleanup' ); |
| 565 | + newPopup.unbind( '.ContextPopupUpdateCleanup' ); |
| 566 | + }; |
| 567 | + var mouseMoveHandler = function( part ) { |
| 568 | + return function() { |
| 569 | + self._touchedPart = part; |
| 570 | + self._clearTimeTillFade(); |
| 571 | + mouseMoveUnbind(); |
| 572 | + } |
| 573 | + }; |
| 574 | + // destroy the popup in case the mouse is outside the popup now (due to positioning/size changes)... |
| 575 | + this._setTimeTillFade( 1500, function() { |
| 576 | + self._touchedPart = null; |
| 577 | + mouseMoveUnbind(); |
| 578 | + } ); |
| 579 | + |
| 580 | + // ...unless we're still within popup-triggering territory (indicated by mouse-movement) |
| 581 | + this._subject.bind( 'mousemove.ContextPopupUpdateCleanup', mouseMoveHandler( this.PARTS.SUBJECT ) ); |
| 582 | + newPopup.bind( 'mousemove.ContextPopupUpdateCleanup', mouseMoveHandler( this.PARTS.POPUP ) ); |
| 583 | + } |
| 584 | + } |
| 585 | + }, |
| 586 | + */ |
| 587 | + |
| 588 | + /** |
| 589 | + * Calculates whether the information would best be displayed at top or bottom with left or |
| 590 | + * right orientation relative to the element, considering the current viewport. |
| 591 | + * @param popup jQuery dom element required for additional positioning calculation |
| 592 | + * @return Object containing the properties 'horizontal' and 'vertical' |
| 593 | + */ |
| 594 | + getIdealAlignment: function( popup ) { |
| 595 | + var measurement = this.$package.InlineMeasurer.measure( this._subject ); |
| 596 | + |
| 597 | + // calculate viewport offset at top and bottom |
| 598 | + var spaceT = this._subject.offset().top - $( window ).scrollTop(); |
| 599 | + var spaceB = $( window ).height() - spaceT - this._subject.outerHeight(); |
| 600 | + |
| 601 | + // calculate viewport offset left and right |
| 602 | + var spaceL = this._subject.offset().left - $( window ).scrollLeft(); |
| 603 | + var spaceR = $( window ).width() - spaceL - this._subject.outerWidth(); |
| 604 | + |
| 605 | + var result = new Object(); |
| 606 | + |
| 607 | + result.vertical = ( // if enough space, always expand downwards |
| 608 | + spaceT <= spaceB |
| 609 | + || spaceB > ( popup.outerHeight() + 10 ) |
| 610 | + || this._subject.offset().top < ( popup.outerHeight() + 5 ) // never TOP if it would be cut off! |
| 611 | + ) |
| 612 | + ? this.ORIENTATION.BOTTOM |
| 613 | + : this.ORIENTATION.TOP; |
| 614 | + |
| 615 | + result.horizontal = ( // if enough space, always expand to right if subject isn't a multi-line inline-element |
| 616 | + !( !measurement.isOneLiner && result.vertical == this.ORIENTATION.TOP ) |
| 617 | + && ( |
| 618 | + spaceL <= spaceR |
| 619 | + || ( spaceR + this._subject.outerWidth() ) > ( popup.outerWidth() + 10 ) |
| 620 | + || this._subject.offset().left < ( popup.outerWidth() + 5 ) // not LEFT if it would be cut off! |
| 621 | + || ( !measurement.isOneLiner && result.vertical == this.ORIENTATION.BOTTOM ) |
| 622 | + ) |
| 623 | + ) |
| 624 | + ? this.ORIENTATION.RIGHT |
| 625 | + : this.ORIENTATION.LEFT; |
| 626 | + |
| 627 | + return result; |
| 628 | + }, |
| 629 | + |
| 630 | + /** |
| 631 | + * This will show the box if it is in a hidden state at the time. |
| 632 | + * This will trigger the 'beforeShow' callback event. |
| 633 | + * @return boolean whether visibility state has changed. |
| 634 | + */ |
| 635 | + show: function() { |
| 636 | + if( this._visible ) { |
| 637 | + return false; |
| 638 | + } |
| 639 | + if( this.beforeShow != null && !this.beforeShow() ) { // callback |
| 640 | + return false; |
| 641 | + } |
| 642 | + this._subject.addClass( this.POPUP_CLASS + '-subject-active' ); |
| 643 | + this._visible = true; |
| 644 | + this.draw(); |
| 645 | + |
| 646 | + return true; |
| 647 | + }, |
| 648 | + |
| 649 | + /** |
| 650 | + * This will close the box if it is in an visible state at the moment. |
| 651 | + * This will trigger the 'beforeClose' callback event. |
| 652 | + * @return boolean whether visibility state has changed. |
| 653 | + */ |
| 654 | + close: function() { |
| 655 | + if( ! this._visible ) { |
| 656 | + return false; |
| 657 | + } |
| 658 | + if( this.beforeClose != null && !this.beforeClose ) { // callback |
| 659 | + return false; |
| 660 | + } |
| 661 | + // close child popups which might still be open for some reasons: |
| 662 | + var openChild = this.getActiveChild(); |
| 663 | + if( openChild !== null ) { |
| 664 | + openChild.close(); |
| 665 | + } |
| 666 | + // effect for fade out but possibility to get a new popup at the same time alreaddy: |
| 667 | + var popup = this._popup; |
| 668 | + popup.unbind(); // unbind events so we can't get the popup back while its fading out |
| 669 | + this._popup.fadeOut( this.TIME_TO_FADE_OUT, function() { |
| 670 | + // Bug #101 |
| 671 | + popup.empty().remove(); |
| 672 | + } ); |
| 673 | + // remove popup from store: |
| 674 | + this._popup = null; |
| 675 | + this._visible = false; |
| 676 | + this._orientation = null; |
| 677 | + this._touchedPart = null; |
| 678 | + this._subject.removeClass( this.POPUP_CLASS + '-subject-active' ); |
| 679 | + return true; |
| 680 | + }, |
| 681 | + |
| 682 | + /** |
| 683 | + * Whether the popup is visible at the moment |
| 684 | + * @returns boolean |
| 685 | + */ |
| 686 | + isVisible: function() { |
| 687 | + return this._visible; |
| 688 | + }, |
| 689 | + |
| 690 | + /** |
| 691 | + * Returns the element which triggers the popup. |
| 692 | + * @return jQuery |
| 693 | + */ |
| 694 | + getSubject: function() { |
| 695 | + return this._subject; |
| 696 | + }, |
| 697 | + |
| 698 | + /** |
| 699 | + * Returns the content which should be displayed within the popup container. |
| 700 | + * @return jQuery |
| 701 | + */ |
| 702 | + getContent: function() { |
| 703 | + return this._content; |
| 704 | + }, |
| 705 | + |
| 706 | + /** |
| 707 | + * Allows to set the content of the box. The contents dimensions will define the boxes size |
| 708 | + * in case the default css rules are not altered. |
| 709 | + * @param content jQuery|String |
| 710 | + */ |
| 711 | + setContent: function( content ) { |
| 712 | + if( typeof content == 'undefined' ) { |
| 713 | + content = ''; |
| 714 | + } |
| 715 | + if( content instanceof String ) { |
| 716 | + content = $( document.createTextNode( content ) ); |
| 717 | + } |
| 718 | + this._content = content; |
| 719 | + if( this._visible ) { |
| 720 | + // refresh if content has changed |
| 721 | + this.draw(); |
| 722 | + } |
| 723 | + }, |
| 724 | + |
| 725 | + /** |
| 726 | + * Returns the direct parent popup if any exists. If this is a top-level popup already, null will |
| 727 | + * be returned. Consider that as long as the popup has its content hidden, there are no children |
| 728 | + * because the parents subject would not be existant if hidden. Therefore the parent can only be |
| 729 | + * returned as long as the parents content still exists within the DOM. |
| 730 | + * @return ContextPopup|null |
| 731 | + */ |
| 732 | + getParent: function() { |
| 733 | + // check whether the subject has a popup container as one of its parents |
| 734 | + var parent = this._subject.parents( '.' + this.POPUP_CLASS ); |
| 735 | + if( parent.length === 0 ) { |
| 736 | + return null; |
| 737 | + } |
| 738 | + // the popup container should hold a data-'link' to its popup content instance |
| 739 | + var parentObj = parent.eq(0).data( this.POPUP_CLASS ); |
| 740 | + if( typeof parentObj == 'undefined' ) { |
| 741 | + return null; |
| 742 | + } |
| 743 | + return parentObj; |
| 744 | + }, |
| 745 | + |
| 746 | + /** |
| 747 | + * Returns all sub-popups within the popups content. |
| 748 | + * @return Array contains the ContextPopup child instances |
| 749 | + */ |
| 750 | + getChildren: function() { |
| 751 | + var ChildPopups = new Array(); |
| 752 | + if( !( this._content instanceof jQuery ) ) { |
| 753 | + return ChildPopups; |
| 754 | + } |
| 755 | + var childSubjects = this._content.find( '.' + this.POPUP_CLASS + '-subject' ); |
| 756 | + var i = 0; |
| 757 | + var self = this; |
| 758 | + childSubjects.each( function() { |
| 759 | + // check for potential subjects data which should be a ContextPopup instance |
| 760 | + childObj = $( this ).data( self.POPUP_CLASS ); |
| 761 | + if( typeof childObj != 'undefined' ) { |
| 762 | + ChildPopups[i++] = childObj; |
| 763 | + } |
| 764 | + } ); |
| 765 | + return ChildPopups; |
| 766 | + }, |
| 767 | + |
| 768 | + /** |
| 769 | + * Returns the direct active sub-popup. There can only be one direct active sub-popup |
| 770 | + * at a time. In case no sub-popup exists or none is active, null will be returned. |
| 771 | + * @return ContextPopup|null |
| 772 | + */ |
| 773 | + getActiveChild: function() { |
| 774 | + var childPopups = this.getChildren(); |
| 775 | + for( var i = 0; i < childPopups.length; i++ ) { |
| 776 | + var child = childPopups[i]; |
| 777 | + if( child.isVisible() ) { |
| 778 | + // mouse entered sub-popup, don't make this (parent) popup disappear! |
| 779 | + return child; |
| 780 | + } |
| 781 | + } |
| 782 | + return null; |
| 783 | + }, |
| 784 | + |
| 785 | + /////////// |
| 786 | + // EVENTS: |
| 787 | + /////////// |
| 788 | + |
| 789 | + /** |
| 790 | + * Callback which is being called before the popup is changing its state from closed to displayed. |
| 791 | + * If this returns false, showing the popup will be prevented. |
| 792 | + */ |
| 793 | + beforeShow: null, |
| 794 | + |
| 795 | + /** |
| 796 | + * Callback which is being called before the popup is changing its state from displayed to closed. |
| 797 | + * If this returns false, closing the popup will be prevented. |
| 798 | + */ |
| 799 | + beforeClose: null, |
| 800 | + |
| 801 | + ///////////////// |
| 802 | + // CONFIGURABLE: |
| 803 | + ///////////////// |
| 804 | + |
| 805 | + /** |
| 806 | + * Allows to configurate whether or not the popup will still stay when the mouse moves |
| 807 | + * from subject object into the popup. |
| 808 | + * @var boolean |
| 809 | + */ |
| 810 | + isTouchable: true |
| 811 | +}; |
Property changes on: trunk/extensions/SemanticExpressiveness/resources/ext.semex.ui.ContextPopup.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 812 | + native |
Index: trunk/extensions/SemanticExpressiveness/README |
— | — | @@ -0,0 +1,46 @@ |
| 2 | +== About ==
|
| 3 | +
|
| 4 | +~~ THIS IS NOT A FINAL RELEASE YET, ITS CONSIDERED AN ALPHA VERSION BY NOW ~~
|
| 5 | +
|
| 6 | +The 'Semantic Expressiveness' extension is an enhancement for 'Semantic MediaWiki'.
|
| 7 | +Its main feature is to introduce a new syntax for inline short queries. The purpose
|
| 8 | +of this simplest form of inline query is to fight redundancies within the wiki.
|
| 9 | +Without 'Semantic Expressivenss' it is customary to declare properties in one place
|
| 10 | +but using the same information again all over the same article or on other pages.
|
| 11 | +With 'Semantic Expressiveness' it is possible to use simple references in form of a
|
| 12 | +new syntax to place the same information in various places without writing redundant
|
| 13 | +information. This way if the property changes, the information will update itself
|
| 14 | +all over the wiki wherever the new syntax is in place.
|
| 15 | +There are also further features like parser functions for template developers and a
|
| 16 | +JavaScript context popup using AJAX to display further information on cross-article
|
| 17 | +inline queries.
|
| 18 | +
|
| 19 | +* Website: https://www.mediawiki.org/wiki/Extension:Semantic_Expressiveness
|
| 20 | +* License: GPL v3
|
| 21 | +* Author: Daniel Werner < danweetz@web.de >
|
| 22 | +
|
| 23 | +
|
| 24 | +== Installation ==
|
| 25 | +
|
| 26 | +Once you have downloaded the code, place the 'SemanticExpressiveness' directory within
|
| 27 | +your MediaWiki 'extensions' directory. Then add the following code to your
|
| 28 | +[[Manual:LocalSettings.php|LocalSettings.php]] file:
|
| 29 | +
|
| 30 | + # Semantic Expressiveness
|
| 31 | + require_once( "$IP/extensions/SemanticExpressiveness/SemanticExpressiveness.php" );
|
| 32 | +
|
| 33 | +This extension requires Jeroen De Dauws 'Validator' extension (version 0.4.14 or
|
| 34 | +above). It must be included before the 'Semantic Expressiveness' extension.
|
| 35 | +You can get it at: http://www.mediawiki.org/wiki/Extension:Validator
|
| 36 | +
|
| 37 | +Furthermore, PHP 5.3+ is required and currently it is necessary to apply a patch for
|
| 38 | +MediaWiki bug #34678 manually:
|
| 39 | +https://bugzilla.wikimedia.org/attachment.cgi?id=10095&action=diff
|
| 40 | +
|
| 41 | +
|
| 42 | +== Contributing ==
|
| 43 | +
|
| 44 | +If you have bug reports or feature requests, please add them to the 'Semantic Expressiveness'
|
| 45 | +Talk page [0]. You can also send them to Daniel Werner < danweetz@web.de >
|
| 46 | +
|
| 47 | +[0] https://www.mediawiki.org/w/index.php?title=Extension_talk:Semantic_Expressiveness
|
Index: trunk/extensions/SemanticExpressiveness/SemanticExpressiveness.i18n.magic.php |
— | — | @@ -0,0 +1,15 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Internationalisation file for 'SemanticExpressiveness' extension. |
| 5 | + * |
| 6 | + * @ingroup SemanticExpressiveness |
| 7 | + * @author Daniel Werner < danweetz@web.de > |
| 8 | + */ |
| 9 | + |
| 10 | +$magicWords = array(); |
| 11 | + |
| 12 | +$magicWords['en'] = array( |
| 13 | + '?' => array( 0, '?' ), |
| 14 | + '?!' => array( 0, '?!' ), |
| 15 | + '?to?!' => array( 0, '?to?!' ), |
| 16 | +); |
Property changes on: trunk/extensions/SemanticExpressiveness/SemanticExpressiveness.i18n.magic.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 17 | + native |
Index: trunk/extensions/SemanticExpressiveness/SemanticExpressiveness.i18n.php |
— | — | @@ -0,0 +1,43 @@ |
| 2 | +<?php |
| 3 | +/** |
| 4 | + * Internationalisation file for 'SemanticExpressiveness' extension. |
| 5 | + * |
| 6 | + * @ingroup SemanticExpressiveness |
| 7 | + * @author Daniel Werner < danweetz@web.de > |
| 8 | + */ |
| 9 | + |
| 10 | +$messages = array(); |
| 11 | + |
| 12 | +/** English |
| 13 | + * @author Daniel Werner |
| 14 | + */ |
| 15 | +$messages['en'] = array( |
| 16 | + 'semex-desc' => 'Adds a syntax for more expressive short queries.', |
| 17 | + 'semex-shortquery-title' => '$1 from $2', |
| 18 | + 'semex-shortquery-title-from-ref' => '$1 from ref $2', |
| 19 | + 'semex-shortquery-hover-loading' => 'Loading', |
| 20 | + 'semex-shortquery-hover-loading-failed' => 'Loading the short queries target pages content failed.', |
| 21 | + 'semex-shortquery-error-missing-property' => 'No value defined for the queried property.', |
| 22 | + 'semex-shortquery-error-byref-has-many-values' => 'The given reference property has more than one value, only the first one was taken as the queries target.', |
| 23 | + 'semex-shortquery-error-byref-has-wrong-type' => 'The given reference property should be one of type "Page".', |
| 24 | + 'semex-shortquery-error-failed-nested-queries' => 'Short query can not be executed because nested short query failed.', |
| 25 | + 'semex-expressivestring-unresolvable' => 'Unresolvable markup', |
| 26 | +); |
| 27 | + |
| 28 | +/** Message documentation (Message documentation) |
| 29 | + * @author Daniel Werner |
| 30 | + */ |
| 31 | +$messages['qqq'] = array( |
| 32 | + 'semex-shortquery-title' => '<$1: semantic property name> from <$2: page the query got the property value from>', |
| 33 | + 'semex-shortquery-title-from-ref' => '<$1: semantic property name> from reference <$2: another semantic property name of the same page>', |
| 34 | +); |
| 35 | + |
| 36 | +/** German (Deutsch) |
| 37 | + * @author Daniel Werner |
| 38 | + */ |
| 39 | +$messages['de'] = array( |
| 40 | + 'semex-shortquery-title' => '$1 von $2', |
| 41 | + 'semex-shortquery-title-from-ref' => '$1 von Ref $2', |
| 42 | + 'semex-shortquery-hover-loading' => 'Läd<i>t</i>', |
| 43 | + 'semex-shortquery-hover-loading-failed' => 'Laden des Inhalts der Quell-Seite der Kurz-Abfrage schlug fehl.', |
| 44 | +); |
Property changes on: trunk/extensions/SemanticExpressiveness/SemanticExpressiveness.i18n.php |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 45 | + native |