Kipcool has submitted this change and it was merged.

Change subject: Special Page Add From External API
......................................................................


Special Page Add From External API

This is a special page to add data to OmegaWiki via external APIs.

Currently supports the Wordnik API.

Since the Wordnik API is not part of the MediaWiki software, each
developer who wish to use Wordnik needs to install it themselves.

Kindly read the file README.md from extensions/WikiLexicalData/external
folder how to activate the Wordnik API.

Patch 2. i18n lowercased some words.

Change-Id: I36b6e537d8ee518a7bb2146bf09327bc2161ccf0
---
M OmegaWiki/Expression.php
M OmegaWiki/OmegaWikiDatabaseAPI.php
M OmegaWiki/WikiDataAPI.php
M OmegaWiki/forms.php
M Wikidata.hooks.php
A external/README.md
M i18n/lexicaldata/en.json
M i18n/lexicaldata/qqq.json
M includes/setup/OWSpecials.php
A includes/specials/ExternalWordnik.php
A includes/specials/SpecialOWAddFromExternalAPI.php
A resources/omegawiki-addExtAPI.js
12 files changed, 1,464 insertions(+), 127 deletions(-)

Approvals:
  Kipcool: Verified; Looks good to me, approved
  Siebrand: Looks good to me, but someone else must approve



diff --git a/OmegaWiki/Expression.php b/OmegaWiki/Expression.php
index 7037823..1b11c03 100644
--- a/OmegaWiki/Expression.php
+++ b/OmegaWiki/Expression.php
@@ -73,10 +73,15 @@
 
                $expressionId = newObjectId( "{$dc}_expression" );
                if ( isset( $options['updateId'] ) ) {
-                       $updateId = $options['updateId'];
+                       if ( $options['updateId'] === -1 ) {
+                               $updateId = getUpdateTransactionId();
+                       } else {
+                               $updateId = $options['updateId'];
+                       }
                } else  {
                        $updateId = getUpdateTransactionId();
                }
+
                $dbw->insert(
                        "{$dc}_expression",
                        array( 'expression_id' => $expressionId,
@@ -88,6 +93,129 @@
                return $expressionId;
        }
 
+       /** @ core getId function
+        *
+        * @param spelling   req'd str
+        * @param languageId opt'l int
+        * @param option     opt'l arr
+        *
+        * @return str expression id for the languageId indicated.
+        * @return arr The first expressionId/languageId [array( expessionId, 
languageId )] when languageId is skipped.
+        *      options:
+        *              dc           str The data set
+        *
+        * @note Though you can access this function, it is highly recommended 
that you
+        * use the static function OwDatabaseAPI::getTheExpressionId instead.
+        */
+       public static function getId( $spelling, $languageId = null, $options = 
array() ) {
+               if ( isset( $options['dc'] ) ) {
+                       $dc = $options['dc'];
+               } else {
+                       $dc = wdGetDataSetContext();
+               }
+               $dbr = wfGetDB( DB_SLAVE );
+
+               $opt = array(
+                       'spelling' => $spelling,
+                       'remove_transaction_id' => null
+               );
+
+               // assumes that languageId does not exists
+               $var = array( 'expression_id', 'language_id' );
+               // then checks if the languageId does exists
+               if ( $languageId ) {
+                       $opt['language_id'] = $languageId;
+                       $var = 'expression_id';
+                       // selectField returns only one field. false if not 
exists.
+                       $expression = $dbr->selectField(
+                               $dc . '_expression', $var, $opt, __METHOD__
+                       );
+               } else {
+                       // selectRow returns only one array. false if not 
exists.
+                       $expression = $dbr->selectRow(
+                               $dc . '_expression', $var, $opt, __METHOD__
+                       );
+               }
+
+               // if expression exists, returns either an array or a string
+               if ( $expression ) {
+                       return $expression;
+               }
+               return null;
+
+       }
+
+       /** @ core getMeaningIds function
+        *
+        * @param spelling   req'd str
+        * @param languageId opt'l arr
+        * @param option     opt'l arr
+        *
+        * @return arr list of defined meaning ids.
+        * @return arr if empty, an empty array.
+        *      options:
+        *              dc           str The data set
+        *
+        * @note Though you can access this function, it is highly recommended 
that you
+        * use the static function OwDatabaseAPI::getTheExpressionMeaningIds 
instead.
+        */
+       public static function getMeaningIds( $spelling, $languageIds = 
array(), $options = array() ) {
+               if ( isset( $options['dc'] ) ) {
+                       $dc = $options['dc'];
+               } else {
+                       $dc = wdGetDataSetContext();
+               }
+               $dbr = wfGetDB( DB_SLAVE );
+
+               $opt = array(
+                       'spelling' => $spelling,
+                       'exp.remove_transaction_id' => null,
+                       'exp.remove_transaction_id' => null,
+                       'exp.expression_id = synt.expression_id'
+               );
+
+               // adjust variables based on languageId existence.
+               if ( $languageIds ) {
+                       // Sanity check: in case languageId is string, convert 
to array.
+                       if ( is_string( $languageIds ) ) {
+                               $temp = array( $languageIds );  // if there is 
a better way to convert
+                               $languageIds= $temp;                    // 
this, kindly refactor. thanks!
+                       }
+                       $var = array( 'defined_meaning_id', 'language_id' );
+               } else {
+                       $var = 'defined_meaning_id';
+               }
+
+               $queryResult = $dbr->select(
+                       array(
+                               'exp' => "{$dc}_expression",
+                               'synt' => "{$dc}_syntrans"
+                       ),
+                       $var,
+                       array(
+                               'spelling' => $spelling,
+                               'exp.remove_transaction_id' => null,
+                               'synt.remove_transaction_id' => null,
+                               'exp.expression_id = synt.expression_id'
+                       ), __METHOD__,
+                       'DISTINCT'
+               );
+
+               $dmlist = array();
+
+               foreach ( $queryResult as $synonymRecord ) {
+                       if ( $languageIds ) {
+                               if ( in_array( $synonymRecord->language_id, 
$languageIds ) ) {
+                                       $dmlist[] = 
$synonymRecord->defined_meaning_id;
+                               }
+                       } else {
+                               $dmlist[] = $synonymRecord->defined_meaning_id;
+                       }
+               }
+
+               return $dmlist;
+       }
+
        /**
         * returns the total number of "Expressions"
         *
diff --git a/OmegaWiki/OmegaWikiDatabaseAPI.php 
b/OmegaWiki/OmegaWikiDatabaseAPI.php
index bc80c5f..88a620d 100644
--- a/OmegaWiki/OmegaWikiDatabaseAPI.php
+++ b/OmegaWiki/OmegaWikiDatabaseAPI.php
@@ -47,6 +47,94 @@
                return $api->Expression->createId( $spelling, $languageId, 
$options );
        }
 
+       /** @brief Returns the expressionId corresponding to $spelling and 
$languageId
+        *
+        * @return str  The expressionId
+        * @return null if not exist
+        * @see OwDatabaseAPI::getTheExpressionId
+        */
+       public static function getExpressionId( $spelling, $languageId, 
$options = array() ) {
+               return OwDatabaseAPI::getTheExpressionId( $spelling, 
$languageId, $options );
+       }
+
+       /** @brief Returns the expression->expression_id corresponding to a 
$spelling and
+        *  also returns the corresponding expression->languageId (the first 
found in the DB)
+        *
+        * @return array array( expessionId, languageId )
+        * @return null  if not exist
+        * @see OwDatabaseAPI::getTheExpressionId
+        */
+       public static function getExpressionIdAnyLanguage( $spelling, $options 
= array() ) {
+               return OwDatabaseAPI::getTheExpressionId( $spelling, null, 
$options );
+       }
+
+       /** @brief returns a list of DefinedMeaning ids
+        *
+        * @return arr list of defined meaning ids.
+        * @return arr if empty, an empty array.
+        * @see OwDatabaseAPI::getExpressionMeaningIds
+        */
+       public static function getExpressionMeaningIds( $spelling, $options = 
array() ) {
+               return OwDatabaseAPI::getTheExpressionMeaningIds( $spelling, 
null, $options );
+       }
+
+       /** @brief returns a list of DefinedMeaning ids for languages contained 
in the array languageIds
+        *
+        * @return arr list of defined meaning ids.
+        * @return arr if empty, an empty array.
+        * @see OwDatabaseAPI::getExpressionMeaningIds
+        */
+       public static function getExpressionMeaningIdsForLanguages( $spelling, 
$languageIds, $options = array() ) {
+               return OwDatabaseAPI::getTheExpressionMeaningIds( $spelling, 
$languageIds, $options );
+       }
+
+
+       /** @brief the core getExpression function
+        *
+        * @param spelling   req'd str
+        * @param languageId opt'l int
+        * @param option     opt'l arr
+        *
+        * @return str expression id for the languageId indicated.
+        * @return arr The first expressionId/languageId [array( expessionId, 
languageId )] when languageId is skipped.
+        *      options:
+        *              dc           str The data set
+        *
+        * @see Expressions::getId.
+        */
+       public static function getTheExpressionId( $spelling, $languageId = 
null, $options = array() ) {
+               $api = new OwDatabaseAPI;
+               $dc = null;
+               if ( isset( $options['dc'] ) ) {
+                       $dc = $options['dc'];
+               }
+               $api->settings( 'expression', $dc );
+               return $api->Expression->getId( $spelling, $languageId, 
$options );
+       }
+
+       /** @brief the core getMeaningIds function
+        *
+        * @param spelling   req'd str
+        * @param languageId opt'l arr
+        * @param option     opt'l arr
+        *
+        * @return arr list of defined meaning ids.
+        * @return arr if not exists, an empty array.
+        *      options:
+        *              dc           str The data set
+        *
+        * @see Expressions::getMeaningIds.
+        */
+       public static function getTheExpressionMeaningIds( $spelling, 
$languageIds, $options ) {
+               $api = new OwDatabaseAPI;
+               $dc = null;
+               if ( isset( $options['dc'] ) ) {
+                       $dc = $options['dc'];
+               }
+               $api->settings( 'expression', $dc );
+               return $api->Expression->getMeaningIds( $spelling, 
$languageIds, $options );
+       }
+
        /*! @} group OwDbAPIeFn ends here.*/
 
        /** @addtogroup OwDbAPIdmFn OwDatabaseAPI's Defined Meaning functions
@@ -375,6 +463,27 @@
                return $api->Syntrans->getSpellingWithDM( $syntransId, 
$options, $api->dc );
        }
 
+       /**
+        * @param definedMeaningId req'd int The defined meaning id
+        * @param languageId       req'd int language id
+        * @param spelling         req'd str The Expression
+        *
+        * @return array( str spelling, int language_id, int identical_meaning )
+        * @return if not exists, null
+        *
+        * @see Syntrans::getAllSynonymAndTranslation
+        */
+       public static function getSynonyms( $definedMeaningId, $languageId, 
$spelling ) {
+               $api = new OwDatabaseAPI;
+               $api->settings( 'syntrans' );
+               $options = array(
+                       'language_id' => $languageId,
+                       'scope' => 'syn',
+                       'spelling' => $spelling
+               );
+               return $api->Syntrans->getAllSynonymAndTranslation( 
$definedMeaningId, $options );
+       }
+
        /*! @} group OwDbAPIsyntFn ends here.*/
 
        /** @addtogroup OwDbAPItransactFn OwDatabaseAPI's Transactions functions
@@ -481,6 +590,124 @@
                $expression->assureIsBoundToDefinedMeaning( $definedMeaningId, 
$identicalMeaning );
        }
 
+       /** @brief added checks before adding Syntrans. Useful for APIs.
+        *
+        * @return an array of result or warning.
+        * @todo Future implemetation. Use this function in connection with
+        *      MediaWiki/WikiLexicalData API's owAddSyntrans.php
+        */
+       public static function addWithNotes( $spelling, $languageId, 
$definedMeaningId, $identicalMeaning, $options = array() ) {
+               global $wgUser;
+               $dc = wdGetDataSetContext();
+
+               // set test status
+               if ( !isset( $options['test'] ) ) {
+                       $options['test'] = false;
+               }
+               // check that the language_id exists
+               if ( !verifyLanguageId( $languageId ) ) {
+                       return array(
+                               'WARNING' => 'Non existent language id (' . 
$languageId . ').'
+                       );
+               }
+
+               // check that defined_meaning_id exists
+               if ( !verifyDefinedMeaningId( $definedMeaningId ) ) {
+                       return array(
+                               'WARNING' => 'Non existent dm id (' . 
$definedMeaningId . ').'
+                       );
+               }
+
+               if ( $identicalMeaning === true ) { $identicalMeaning = 1; }
+               if ( $identicalMeaning === false ) { $identicalMeaning = 0; }
+               if ( $identicalMeaning === 1 ) {
+                       $identicalMeaningStr = "true";
+                       if ( $options['ver'] == '1' ) { $identicalMeaning = 
"true"; }
+               }
+               else {
+                       $identicalMeaningStr = "false";
+                       $identicalMeaning = 0;
+                       if ( $options['ver'] == '1' ) { $identicalMeaning = 
"false"; }
+               }
+
+               if ( !isset( $options['addedBy'] ) ) { // assumed used by API
+                       $addedBy = 'API function add_syntrans';
+               } else {
+                       $addedBy = $options['addedBy'];
+               }
+
+               // first check if it exists, then create the transaction and 
put it in db
+               $expression = findExpression( $spelling, $languageId, $options 
);
+               $concept = getDefinedMeaningSpellingForLanguage( 
$definedMeaningId, WLD_ENGLISH_LANG_ID );
+               if ( $expression ) {
+                       // the expression exists, check if it has this syntrans
+                       $bound = expressionIsBoundToDefinedMeaning ( 
$definedMeaningId, $expression->id );
+                       if (  $bound == true ) {
+                               $synonymId = getSynonymId( $definedMeaningId, 
$expression->id );
+                               $note = array (
+                                       'status' => 'exists',
+                                       'in' => $concept . ' DM(' . 
$definedMeaningId . ')',
+                                       'sid' => $synonymId,
+                                       'e' => $spelling,
+                                       'langid' => $languageId,
+                                       'dm' => $definedMeaningId,
+                                       'im' => $identicalMeaning
+                               );
+                               if ( $options['test'] ) {
+                                       $note['note'] = 'test run only';
+                               }
+
+                               return $note;
+                       }
+               }
+
+               // adding the expression
+               $expressionId = getExpressionId( $spelling, $languageId );
+               $synonymId = getSynonymId( $definedMeaningId, $expressionId );
+               $note = array (
+                       'status' => 'added',
+                       'to' => $concept . ' DM(' . $definedMeaningId . ')',
+                       'sid' => $synonymId,
+                       'e' => $spelling,
+                       'langid' => $languageId,
+                       'dm' => $definedMeaningId,
+                       'im' => $identicalMeaning
+               );
+
+               // safety net.
+               if ( !isset( $options['transacted'] ) ) { 
$options['transacted'] = false; };
+               if ( !isset( $options['updateId'] ) ) { $options['updateId'] = 
-1; };
+               if ( !isset( $options['tid'] ) ) { $options['tid'] = -1; };
+               if ( !isset( $options['test'] ) ) { $options['test'] = false; };
+
+               // add note['tid'] from $options['tid'] (transaction id), if 
null, get value
+               // from $this->options['updateId'].
+               if ( $options['ver'] == '1.1' ) {
+                       if ( $options['tid'] ) {
+                               $note['tid'] = $options['tid'];
+                       } else {
+                               $note['tid'] = $options['updateId'];
+                       }
+               }
+
+               if ( !$options['test'] ) {
+                       if ( !$options['transacted'] ) {
+                               $note['transacted'] = true; // @todo when used 
in owAddSyntrans.php, kindly use this to switch $this->transacted to true.
+                               $tid = startNewTransaction( $wgUser->getID(), 
"0.0.0.0", 'Added using ' . $addedBy, $dc );
+                               if ( $options['ver'] == '1.1' ) {
+                                       $note['tid'] = $tid;
+                               }
+                       }
+                       OwDatabaseAPI::addSynonymOrTranslation( $spelling, 
$languageId, $definedMeaningId, $identicalMeaningStr, $options );
+                       $synonymId = getSynonymId( $definedMeaningId, 
$expressionId );
+                       $note['sidd'] = $synonymId;
+               } else {
+                       $note['note'] = 'test run only';
+               }
+
+               return $note;
+       }
+
        /**
         * @param syntransId req'd int The syntrans id
         * @param options    opt'l arr  An optional parameters
@@ -530,4 +757,80 @@
                return array();
        }
 
+       /** @brief core get syntrans function
+        *
+        * @param definedMeaningId      int     req'd
+        * @param options                       int opt'l
+        *
+        * @return array( str spelling, int language_id, int identical_meaning )
+        * @return if not exists, null
+        */
+       public static function getAllSynonymAndTranslation( $definedMeaningId, 
$options ) {
+               if ( isset( $options['dc'] ) ) {
+                       $dc = $options['dc'];
+               } else {
+                       $dc = wdGetDataSetContext();
+               }
+               $dbr = wfGetDB( DB_SLAVE );
+
+               $opt = array(
+                       'defined_meaning_id' => $definedMeaningId,
+                       'st.expression_id = e.expression_id',
+                       'st.remove_transaction_id' => null
+               );
+
+               if( isset( $options['language_id'] ) ) {
+                       $languageId = $options['language_id'];
+               }
+
+               if( isset( $options['spelling'] ) ) {
+                       $spelling = $options['spelling'];
+               }
+
+               if( isset( $options['scope'] ) ) {
+                       switch( $options['scope'] ) {
+                               case 'syn':
+                               $opt['language_id'] = $languageId;
+                               $opt[] = 'spelling not in (' . "'" . $spelling 
. "'" . ')';
+                               break;
+                       }
+               }
+
+               $result = $dbr->select(
+                       array(
+                               'e' => "{$dc}_expression",
+                               'st' => "{$dc}_syntrans"
+                       ),
+                       array(
+                               'spelling',
+                               'language_id',
+                               'identical_meaning',
+                               'syntrans_sid'
+                       ),
+                       $opt, __METHOD__,
+                       array(
+                               'ORDER BY' => array (
+                                       'identical_meaning DESC',
+                                       'language_id',
+                                       'spelling'
+                               )
+                       )
+               );
+
+               $syntrans = array();
+               foreach ( $result as $row ) {
+                       $syntrans[] = array(
+                               0 => $row->spelling,
+                               1 => $row->language_id,
+                               2 => $row->identical_meaning,
+                               3 => $row->syntrans_sid
+                       );
+               }
+
+               if ( $syntrans ) {
+                       return $syntrans;
+               }
+               return null;
+       }
+
 }
diff --git a/OmegaWiki/WikiDataAPI.php b/OmegaWiki/WikiDataAPI.php
index 638ea99..8054744 100644
--- a/OmegaWiki/WikiDataAPI.php
+++ b/OmegaWiki/WikiDataAPI.php
@@ -73,53 +73,16 @@
        return "";
 }
 
-/**
- * Returns the expressionId corresponding to $spelling and $languageId
- * @return null if not exist
+/** @todo for deprecation. Use OwDatabaseAPI::getExpressionId
  */
 function getExpressionId( $spelling, $languageId ) {
-       $dc = wdGetDataSetContext();
-       $dbr = wfGetDB( DB_SLAVE );
-
-       $expressionId = $dbr->selectField(
-               "{$dc}_expression",
-               'expression_id',
-               array(
-                       'spelling' => $spelling,
-                       'language_id' => $languageId,
-                       'remove_transaction_id' => null
-               ), __METHOD__
-       );
-
-       if ( $expressionId ) {
-               return $expressionId;
-       }
-       return null;
+       return OwDatabaseAPI::getExpressionId( $spelling, $languageId );
 }
 
-/**
- * Returns the expression->expression_id corresponding to a $spelling and
- * also returns the corresponding expression->languageId (the first found in 
the DB)
- * returns null if not exist
+/** @todo for deprecation. Use OwDatabaseAPI::getExpressionIdAnyLanguage
  */
 function getExpressionIdAnyLanguage( $spelling ) {
-       $dc = wdGetDataSetContext();
-       $dbr = wfGetDB( DB_SLAVE );
-
-       // selectRow returns only one. false if not exists.
-       $expression = $dbr->selectRow(
-               "{$dc}_expression",
-               array( 'expression_id', 'language_id' ),
-               array(
-                       'spelling' => $spelling,
-                       'remove_transaction_id' => null
-               ), __METHOD__
-       );
-
-       if ( $expression ) {
-               return $expression;
-       }
-       return null;
+       return OwDatabaseAPI::getExpressionIdAnyLanguage( $spelling );
 }
 
 function getRemovedExpressionId( $spelling, $languageId ) {
@@ -236,17 +199,23 @@
 }
 
 /**
- * returns true if a spelling exists in the
- * expression table of the database
+ * @return boolean if a spelling exists in the expression table of the database
  */
-function existSpelling( $spelling ) {
+function existSpelling( $spelling, $languageId = 0 ) {
        $dc = wdGetDataSetContext();
 
        $dbr = wfGetDB( DB_SLAVE );
+
+       $cond = array( 'spelling' => $spelling, 'remove_transaction_id' => null 
);
+
+       if ( $languageId > 0 ) {
+               $cond['language_id'] = $languageId;
+       }
+
        $expressionId = $dbr->selectField(
                "{$dc}_expression",
                'expression_id',
-               array( 'spelling' => $spelling, 'remove_transaction_id' => null 
),
+               $cond,
                __METHOD__
        );
 
@@ -2130,64 +2099,16 @@
        return 0;
 }
 
+/** @todo for deprecation. use OwDatabaseAPI::getExpressionMeaningIds instead.
+ */
 function getExpressionMeaningIds( $spelling, $dc = null ) {
-       if ( is_null( $dc ) ) {
-               $dc = wdGetDataSetContext();
-       }
-       $dbr = wfGetDB( DB_SLAVE );
-
-       $queryResult = $dbr->select(
-               array(
-                       'exp' => "{$dc}_expression",
-                       'synt' => "{$dc}_syntrans"
-               ),
-               'defined_meaning_id',
-               array(
-                       'spelling' => $spelling,
-                       'exp.remove_transaction_id' => null,
-                       'synt.remove_transaction_id' => null,
-                       'exp.expression_id = synt.expression_id'
-               ), __METHOD__
-       );
-
-       $dmlist = array();
-
-       foreach ( $queryResult as $synonymRecord ) {
-               $dmlist[] = $synonymRecord->defined_meaning_id;
-       }
-
-       return $dmlist;
+       return OwDatabaseAPI::getExpressionMeaningIds( $spelling, array( 'dc' 
=> $dc ) );
 }
 
+/** @todo for deprecation. use 
OwDatabaseAPI::getExpressionMeaningIdsForLanguages instead.
+ */
 function getExpressionMeaningIdsForLanguages( $spelling, $languageIds, $dc = 
null ) {
-       if ( is_null( $dc ) ) {
-               $dc = wdGetDataSetContext();
-       }
-       $dbr = wfGetDB( DB_SLAVE );
-
-       $queryResult = $dbr->select(
-               array(
-                       'exp' => "{$dc}_expression",
-                       'synt' => "{$dc}_syntrans"
-               ),
-               array( 'defined_meaning_id', 'language_id' ),
-               array(
-                       'spelling' => $spelling,
-                       'exp.expression_id = synt.expression_id',
-                       'synt.remove_transaction_id' => null,
-                       'exp.remove_transaction_id' => null
-               ), __METHOD__,
-               'DISTINCT'
-       );
-
-       $dmlist = array();
-
-       foreach( $queryResult as $synonymRecord ) {
-               if ( in_array( $synonymRecord->language_id, $languageIds ) ) {
-                       $dmlist[] = $synonymRecord->defined_meaning_id;
-               }
-       }
-       return $dmlist;
+       return OwDatabaseAPI::getExpressionMeaningIdsForLanguages( $spelling, 
$languageIds, array( 'dc' => $dc ) );
 }
 
 /** Get Defined Meaning Ids from Expression Id
diff --git a/OmegaWiki/forms.php b/OmegaWiki/forms.php
index ae6374d..029a99d 100644
--- a/OmegaWiki/forms.php
+++ b/OmegaWiki/forms.php
@@ -13,9 +13,9 @@
                '" value="' . htmlspecialchars( $value ) . '"' . 
$onChangeAttribute .
                ' style="width: 100%; padding: 0px; margin: 0px;"/>' ;
 
-       return $inputHTML ;
+       return $inputHTML;
 }
- 
+
 function getTextArea( $name, $text = "", $rows = 5, $columns = 80, $disabled = 
false ) {
        if ( $disabled ) {
                // READONLY alone is not enough: apparently, some browsers 
ignore it
@@ -31,7 +31,7 @@
        }
        return '';
 }
- 
+
 function getCheckBox( $name, $isChecked, $disabled = false ) {
        // a disabled checkbox returns no value, as if unchecked
        // therefore the value of a disabled, but checked, checkbox must be 
sent with a hidden input
@@ -69,28 +69,11 @@
        }
 }
 
-# $options is an array of [value => text] pairs
+/** @todo for deprecration use Class OmegaWikiForms's getSelect function 
instead.
+ */
 function getSelect( $name, $options, $selectedValue = "", $onChangeHandler = 
"" ) {
-       if ( $onChangeHandler != "" ) {
-               $onChangeAttribute = ' onchange="' . $onChangeHandler . '"';
-       } else {
-               $onChangeAttribute = '';
-       }
-
-       $result = '<select id="' . $name . '" name="' . $name . '"' . 
$onChangeAttribute . '>';
- 
-       asort( $options );
-
-       foreach ( $options as $value => $text ) {
-               if ( $value == $selectedValue )
-                       $selected = ' selected="selected"';
-               else
-                       $selected = '';
-
-               $result .= '<option value="' . $value . '"' . $selected . '>' . 
htmlspecialchars( $text ) . '</option>';
-       }
-
-       return $result . '</select>';
+       $form = new OmegaWikiForms;
+       return $form->getSelect( $name, $options, $selectedValue, 
$onChangeHandler );
 }
 
 function getFileField( $name, $onChangeHandler = "" ) {
@@ -101,7 +84,6 @@
 
        return '<input type="file" id="' . $name . '" name="' . $name . '"' . 
$onChangeAttribute . ' style="width: 100%; padding: 0px; margin: 0px;"/>';
 }
- 
 
 /**
  *
@@ -296,3 +278,137 @@
        return $result;
 }
 
+/** @brief Generic Forms
+ */
+class GenericForms {
+
+       public function __construct() {
+               $this->labelTemplate = 
'&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;';
+       }
+
+
+       /**
+        * @return HTML string for HTML tag select
+        *
+        * @param name            str req'd unique identifier for this form 
field
+        * @param options         arr req'd list of options, [value => text] 
pairs
+        * @param selectedValue   str opt'l in case a value is present
+        * @param onChangeHandler str js
+        */
+       function getSelect( $name, $options, $selectedValue = "", 
$onChangeHandler = "" ) {
+               if ( $onChangeHandler != "" ) {
+                       $onChangeAttribute = ' onchange="' . $onChangeHandler . 
'"';
+               } else {
+                       $onChangeAttribute = '';
+               }
+
+               $result = '<select id="' . $name . '" name="' . $name . '"' . 
$onChangeAttribute . '>';
+
+               asort( $options );
+
+               foreach ( $options as $value => $text ) {
+                       if ( $value == $selectedValue ) {
+                               $selected = ' selected="selected"';
+                       } else {
+                               $selected = '';
+                       }
+
+                       $result .= '<option value="' . $value . '"' . $selected 
. '>' . htmlspecialchars( $text ) . '</option>';
+               }
+
+               return $result . '</select>';
+       }
+
+       /**
+        * @return HTML string for HTML input type text
+        * @param name            str     req'd unique identifier for this form 
field
+        * @param value           str     opt'l input value
+        * @param onChangeHandler str     opt'l js
+        * @param disabled        boolean opt'l to disable editing of the field
+        */
+       public function getTextBox( $name, $value = "", $onChangeHandler = "", 
$disabled = false ) {
+               if ( $onChangeHandler != "" ) {
+                       $onChangeAttribute = ' onchange="' . $onChangeHandler . 
'"';
+               } else {
+                       $onChangeAttribute = '';
+               }
+
+               $disableText = $disabled ? 'disabled="disabled" ' : '';
+               $inputHTML = '<input ' . $disableText . 'type="text" id="' . 
$name . '" name="' . $name .
+                       '" value="' . htmlspecialchars( $value ) . '"' . 
$onChangeAttribute .
+                       ' style="width: 100%; padding: 0px; margin: 0px;"/>';
+
+               return $inputHTML;
+       }
+
+}
+
+/** @brief OmegaWiki extension to the generic forms
+ */
+class OmegaWikiForms extends GenericForms {
+
+       public function __construct() {
+               parent::__construct();
+       }
+
+       /**
+        *
+        * @return HTML for an autocompleted form field.
+        *
+        * @param name                str unique identifier for this form field
+        * @param query               str type of query to run
+        * @param parameters          arr span options (parameters and values )
+        * @param value               int Default value
+        * @param label               str How default value will be shown
+        * @param displayLabelColumns arr Override column titles
+        * @param DataSet             str Override standard dataset
+        *
+       */
+       function getSuggest( $name, $query, $parameters = array(), $value = 0, 
$label = '', $displayLabelColumns = array( 0 ), DataSet $dc = null ) {
+               global $wgScriptPath;
+
+               if ( is_null( $dc ) ) {
+                       $dc = wdGetDataSetContext();
+               }
+               if ( $label == "" ) {
+                       $label = $this->labelTemplate;
+               }
+
+               $result = Html::openElement('span', array( 'class' => 'suggest' 
) );
+
+               // the input that will contain the value selected with 
suggest.js
+               $inputOptions = array(
+                       'id' => $name,
+                       'name' => $name,
+                       'value' => $value,
+                       'type' => 'hidden'
+               );
+               $result .= Html::element('input', $inputOptions);
+
+               $spanOptions = array(
+                       'id' => $name . '-suggest-link',
+                       'name' => $name . '-suggest-link',
+                       'class' => 'suggest-link',
+                       'title' => wfMessage( "ow_SuggestHint" )->text(),
+                       'query' => $query,
+                       'offset' => 0,
+                       'label-columns' => implode( ', ', $displayLabelColumns 
),
+                       'dataset' => $dc
+               );
+
+               foreach( $parameters as $parameter => $parameterValue ) {
+                       // parameters like level, definedMeaningId, 
annotationAttributeId, syntransId
+                       $spanOptions[$parameter] = $parameterValue;
+               }
+
+               $result .= Html::rawElement( 'span', $spanOptions, $label );
+
+               $result .= Html::closeElement( 'span' );
+
+               // The table that then allows to select from a dropdown list
+               // is generated with javascript (cf. suggest.js)
+
+               return $result;
+       }
+
+}
diff --git a/Wikidata.hooks.php b/Wikidata.hooks.php
index 4579937..998cca4 100644
--- a/Wikidata.hooks.php
+++ b/Wikidata.hooks.php
@@ -26,6 +26,14 @@
                                $out->setPageTitle( mb_substr( 
$out->getPageTitle(), mb_strlen( $namespaceText ) + 1 ) );
                        }
                }
+
+               // SpecialPage Add from External API
+               if (
+                       $skin->getTitle()->mNamespace === -1 and
+                       $skin->getTitle()->mTextform === 'Ow addFromExtAPI'
+               ) {
+                       $out->addModules( 'ext.OwAddFromExtAPI.js' );
+               }
                return true;
        }
 
diff --git a/external/README.md b/external/README.md
new file mode 100644
index 0000000..c515431
--- /dev/null
+++ b/external/README.md
@@ -0,0 +1,26 @@
+# Installing External APIs
+
+This directory will be used to add external APIs.
+
+## APIs that are supported by WikiLexicalData
+
+### Wordnik
+
+Currently tested with Wordnik.com v4 API.
+
+#### Basic Setup
+
+Place the `wordnik` folder that you downloaded in this directory
+where it can be accessed by WikiLexicaldata.
+
+Obtain an API key from Wordnik.
+
+Then create a PHP file under this directory named wordnikConfig.php and 
+with the following code:
+
+       <?php
+       global $myWordnikAPIKey;
+       $myWordnikAPIKey = '<PLACE_YOUR_WORDNIK_API_KEY_HERE>';
+
+Replace <PLACE_YOUR_WORDNIK_API_KEY_HERE> with the API key you have received
+from Wordnik.
diff --git a/i18n/lexicaldata/en.json b/i18n/lexicaldata/en.json
index a775ee9..3ae0901 100644
--- a/i18n/lexicaldata/en.json
+++ b/i18n/lexicaldata/en.json
@@ -216,5 +216,8 @@
     "prefs-omegawiki": "OmegaWiki",
     "prefs-ow-lang": "Languages",
     "ow_pref_lang_switch": "Show only the selected languages",
-    "ow_pref_lang_select": "Languages to display:"
+    "ow_pref_lang_select": "Languages to display:",
+       "ow_addFromExtAPI": "Add data from external APIs",
+       "ow_addFromExtAPI_title" : "Add data from API",
+       "ow_api_source" : "External API source:"
 }
diff --git a/i18n/lexicaldata/qqq.json b/i18n/lexicaldata/qqq.json
index fe1cc1b..7eec342 100644
--- a/i18n/lexicaldata/qqq.json
+++ b/i18n/lexicaldata/qqq.json
@@ -147,5 +147,8 @@
        "prefs-omegawiki": "{{optional}}",
        "prefs-ow-lang": "A header in the user preferences where the user can 
configure languages.\n{{Identical|Language}}",
        "ow_pref_lang_switch": "A checkbox in the user preferences. If checked, 
it allows the user to select which languages should be displayed. If unchecked, 
all languages are displayed.",
-       "ow_pref_lang_select": "Next to this text is shown a list of languages, 
each with a checkbox, to select the languages to display or hide in OmegaWiki"
+       "ow_pref_lang_select": "Next to this text is shown a list of languages, 
each with a checkbox, to select the languages to display or hide in OmegaWiki",
+       "ow_addFromExtAPI": "Special page name for adding OmegaWiki data from 
External APIs",
+       "ow_addFromExtAPI_title" : "The page title for Special page name for 
adding OmegaWiki data from External APIs",
+       "ow_api_source" : "External API source label"
 }
diff --git a/includes/setup/OWSpecials.php b/includes/setup/OWSpecials.php
index 915c63d..6b12fdc 100644
--- a/includes/setup/OWSpecials.php
+++ b/includes/setup/OWSpecials.php
@@ -82,6 +82,11 @@
        'author' => 'Hiong3-eng5',
 );
 
+$wgExtensionCredits['specialpage'][] = array(
+       'name' => 'SpecialAddFromExternalAPI',
+       'author' => 'Hiong3-eng5',
+);
+
 # Location of the SpecialMyExtension class (Tell MediaWiki to load this file)
 $wgAutoloadClasses['SpecialCopy'] = $dir . 'OmegaWiki/SpecialCopy.php';
 $wgAutoloadClasses['SpecialSelect'] = $dir . 'OmegaWiki/SpecialSelect.php';
@@ -99,6 +104,8 @@
 
 $wgAutoloadClasses['SpecialExportTSV'] = $wgWldSpecialsScriptPath . 
'SpecialExportTSV.php';
 $wgAutoloadClasses['SpecialImportTSV'] = $wgWldSpecialsScriptPath . 
'SpecialImportTSV.php';
+
+$wgAutoloadClasses['SpecialOWAddFromExternalAPI'] = $wgWldSpecialsScriptPath . 
'SpecialOWAddFromExternalAPI.php';
 
 // $wgAutoloadClasses['SpecialTransaction'] = $dir . 
'OmegaWiki/SpecialTransaction.php';
 
@@ -119,6 +126,8 @@
 
 $wgSpecialPages['exportTSV'] = 'SpecialExportTSV';
 $wgSpecialPages['importTSV'] = 'SpecialImportTSV';
+
+$wgSpecialPages['ow_addFromExtAPI'] = 'SpecialOWAddFromExternalAPI';
 
 // $wgSpecialPages['Transaction'] = 'SpecialTransaction';
 
@@ -143,6 +152,33 @@
 $wgSpecialPageGroups[ 'ow_statistics' ] = 'wiki';
 $wgSpecialPageGroups[ 'ow_downloads' ] = 'wiki';
 
+// special page with conditional groups
+
+// ow_addFromExtAPI
+
+global $wgWldProcessExternalAPIClasses, $wgWldExtenalResourceLanguages, 
$wgWldScriptPath;
+$wgWldProcessExternalAPIClasses = array();
+$wgWldExtenalResourceLanguages = array();
+
+if ( file_exists( $wgWldScriptPath . '/external/wordnik/wordnik/Swagger.php' ) 
) {
+       $wgAutoloadClasses['WordnikExtension' ] = $wgWldSpecialsScriptPath . 
'ExternalWordnik.php';
+       $wgAutoloadClasses['WordnikWiktionaryExtension' ] = 
$wgWldSpecialsScriptPath . 'ExternalWordnik.php';
+       $wgAutoloadClasses['WordnikWordnetExtension' ] = 
$wgWldSpecialsScriptPath . 'ExternalWordnik.php';
+       $wgWldProcessExternalAPIClasses['WordnikExtension'] = 'Wordnik';
+       $wgWldProcessExternalAPIClasses['WordnikWiktionaryExtension'] = 
'Wordnik Wiktionary';
+       $wgWldProcessExternalAPIClasses['WordnikWordnetExtension'] = 'Wordnik 
Wordnet';
+       $wgWldExtenalResourceLanguages[WLD_ENGLISH_LANG_ID] = 'English';
+       require_once( $wgWldScriptPath . '/external/wordnikConfig.php' );
+}
+
+if ( $wgWldProcessExternalAPIClasses ) {
+       $wgSpecialPageGroups[ 'ow_addFromExtAPI' ] = 'maintenance';
+
+       $wgResourceModules['ext.OwAddFromExtAPI.js'] = $resourcePathArray + 
array(
+               'scripts' => 'omegawiki-addExtAPI.js'
+       );
+}
+
 # Location of an aliases file (Tell MediaWiki to load this file)
 //$wgExtensionMessagesFiles[ 'OWSpecialsAlias' ] = #dir . 
'../i18n/OWSpecials.alias.php';
 
diff --git a/includes/specials/ExternalWordnik.php 
b/includes/specials/ExternalWordnik.php
new file mode 100644
index 0000000..951fa06
--- /dev/null
+++ b/includes/specials/ExternalWordnik.php
@@ -0,0 +1,131 @@
+<?php
+
+if ( !defined( 'MEDIAWIKI' ) ) die();
+
+/** @brief class to access Wordnik's API
+ */
+class WordnikExtension extends ExternalResources {
+
+       private $wordApi; //< object to handle Wordnik's API
+
+       /** @note see ExternalResources::__contruct
+        */
+       function __construct( $spTitle, $source, $sourceLanguageId, $search, 
$collectionId ) {
+               parent::__construct( $spTitle, $source, $sourceLanguageId, 
$search, $collectionId );
+               preg_match( '/^Wordnik(.+)/', $this->source, $match );
+               $this->sourceLabel = 'Wordnik ' . $match[1];
+
+               global $myWordnikAPIKey;
+               require_once( __DIR__ . 
'/../../external/wordnik/wordnik/Swagger.php' );
+               $wgWldExtenalResourceLanguages = array(
+                       85 => 'English'
+               );
+               $WordnikClient = new APIClient($myWordnikAPIKey, 
'http://api.wordnik.com/v4');
+               $this->wordApi = new WordApi( $WordnikClient );
+               $this->sourceDictionary = 'all';
+
+       }
+
+       function execute() {
+               // reconstruct spTitle
+               $this->spTitle = 'Wordnik: ' . $this->spTitle;
+               parent::execute();
+       }
+
+       function checkExternalDefinition() {
+       //      $example = $this->wordApi->getTopExample('big');
+       //      $exampleSentence = $example->text;
+               $this->externalDefinition = $this->wordApi->getDefinitions( 
$this->search, null, $this->sourceDictionary, null, 'true' );
+               $this->externalExists = true;
+               if ( $this->externalDefinition ) {
+                       $this->externalExists = true;
+               }
+       }
+
+       function setExternalDefinition() {
+               $this->externalLexicalData = array();
+
+               if ( $this->externalDefinition ) {
+                       foreach( $this->externalDefinition as $definition ) {
+                               if ( $definition->sourceDictionary !== 
'ahd-legacy' ) {
+
+                                       $this->setExternalLexicalData( 
$definition );
+
+                               }
+                       }
+               }
+               $this->externalLexicalDataJSON = json_encode( 
$this->externalLexicalData );
+               // line below for testing purpose when without internet for 
expression 'pig'
+       //      $this->getTestExternalDefinition();
+               $this->wgOut->addHTML(
+                       '<div id="ext-data">' . $this->externalLexicalDataJSON 
. '</div>'
+               );
+       }
+
+       /** Includes only definitions that are relevant. Filters out definitions
+        *      that would be useless to the current program.
+        * @note currently, only related words have data that is relevant to 
this special page.
+        */
+       function setExternalLexicalData( $definition ) {
+               $includeDefinition = $this->includeDefinition( $definition );
+
+               if ( $includeDefinition === true ) {
+                       $this->externalLexicalData[] = array(
+                               'process' => null,
+                               'src' => $definition->sourceDictionary,
+                               'text' => $definition->text,
+                               'partOfSpeech' => $definition->partOfSpeech,
+                               'relatedWords' => $definition->relatedWords
+                       );
+               }
+       }
+
+       private function includeDefinition( $definition ) {
+               $includeDefinition = false;
+               if ( $definition->relatedWords ) {
+                       foreach( $definition->relatedWords as $rw ) {
+                               switch ( $rw->relationshipType ) {
+                                       case 'synonym': $includeDefinition = 
true; break;
+                               }
+                       }
+               }
+
+               return $includeDefinition;
+       }
+
+       private function getTestExternalDefinition() {
+               $this->externalLexicalDataJSON = 
'[{"process":null,"src":"wiktionary","text":"earthenware, or an earthenware 
shard","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"An
 earthenware hot-water jar to warm a bed; a stone bed 
warmer","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"a
 
pigeon.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"Any
 of several mammals of the genus Sus, having cloven hooves, bristles and a nose 
adapted for digging; especially the domesticated farm animal Sus 
scrofa.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A
 young swine, a 
piglet.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"The
 edible meat of such an animal; 
pork.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"Someone
 who overeats or eats rapidly and 
noisily.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A
 nasty or disgusting 
person.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A
 dirty or slovenly 
person.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A
 difficult 
problem.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A
 block of cast 
metal.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"The
 mold in which a block of metal is 
cast.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"A
 device for cleaning or inspecting the inside of an oil or gas pipeline, or for 
separating different substances within the pipeline. Named for the pig-like 
squealing noise made by their 
progress.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"a
 person who is obese to the extent of resembling a pig (the 
animal)","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wiktionary","text":"to
 give 
birth.","partOfSpeech":"verb","relatedWords":[]},{"process":null,"src":"wiktionary","text":"To
 greedily consume (especially 
food).","partOfSpeech":"verb","relatedWords":[]},{"process":null,"src":"wiktionary","text":"To
 huddle or lie together like pigs, in one 
bed.","partOfSpeech":"verb","relatedWords":[]},{"process":null,"src":"gcide","text":"A
 
piggin.","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"synonym","label2":null,"label3":null,"words":["piggin"],"gram":null,"label4":null},{"label1":null,"relationshipType":"variant","label2":null,"label3":null,"words":["pigg"],"gram":null,"label4":null}]},{"process":null,"src":"gcide","text":"The
 young of swine, male or female; also, any swine; a 
hog.","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"synonym","label2":null,"label3":null,"words":["hog"],"gram":null,"label4":null}]},{"process":null,"src":"gcide","text":"Any
 wild species of the genus Sus and related 
genera.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"gcide","text":"An
 oblong mass of cast iron, lead, or other metal. See Mine pig, under 
Mine.","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"variant","label2":null,"label3":null,"words":["mine"],"gram":null,"label4":null}]},{"process":null,"src":"gcide","text":"One
 who is hoggish; a greedy 
person.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"gcide","text":"To
 bring forth (pigs); to bring forth in the manner of pigs; to 
farrow.","partOfSpeech":"verb","relatedWords":[{"label1":null,"relationshipType":"form","label2":null,"label3":null,"words":["pigged"],"gram":"imp.
 & p. 
p.","label4":null},{"label1":null,"relationshipType":"form","label2":null,"label3":null,"words":["pigging"],"gram":"p.
 pr. & vb. 
n.","label4":null},{"label1":null,"relationshipType":"synonym","label2":null,"label3":null,"words":["farrow"],"gram":null,"label4":null},{"label1":null,"relationshipType":"form","label2":null,"label3":null,"words":["pigged"],"gram":"imp.
 & p. 
p.","label4":null},{"label1":null,"relationshipType":"form","label2":null,"label3":null,"words":["pigging"],"gram":"p.
 pr. & vb. n.","label4":null}]},{"process":null,"src":"gcide","text":"To huddle 
or lie together like pigs, in one 
bed.","partOfSpeech":"verb","relatedWords":[]},{"process":null,"src":"century","text":"A
 hog; a swine; especially, a porker, or young swine of either sex, the old male 
being called boar, the old female 
sow.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"The
 flesh of swine; 
pork.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"An
 oblong mass of metal that has been run while still molten into a mold 
excavated in sand; specifically, iron from the blast-furnace run into molds 
excavated in 
sand.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"A
 customary unit of weight for lead, 301 
pounds.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"A
 very short space of 
time.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"To
 bring forth pigs; bring forth in the manner of pigs; 
litter.","partOfSpeech":null,"relatedWords":[]},{"process":null,"src":"century","text":"To
 act as pigs; live like a pig; live or huddle as pigs: sometimes with an 
indefinite 
it.","partOfSpeech":null,"relatedWords":[]},{"process":null,"src":"century","text":"An
 earthen vessel; any article of 
earthenware.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"A
 can for a 
chimney-top.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"A
 
potsherd.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"Pig-iron
 collectively or any specified amount of iron 
pigs.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"century","text":"In
 forestry, see 
rigging-sled.","partOfSpeech":"noun","relatedWords":[]},{"process":null,"src":"wordnet","text":"domestic
 
swine","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hyponym","label2":null,"label3":null,"words":["porker"],"gram":null,"label4":null},{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["swine"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"live
 like a pig, in 
squalor","partOfSpeech":"verb","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["live"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"give
 
birth","partOfSpeech":"verb","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["bear","give
 
birth","birth","have","deliver"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"a
 person regarded as greedy and 
pig-like","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["selfish
 
person"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"eat
 
greedily","partOfSpeech":"verb","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["eat"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"uncomplimentary
 terms for a 
policeman","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["police
 
officer","policeman","officer"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"a
 crude block of metal (lead or iron) poured from a smelting 
furnace","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["ingot","metal
 bar","block of 
metal"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"a 
coarse obnoxious 
person","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hyponym","label2":null,"label3":null,"words":["litterbug","litter
 lout","slattern","trollop","slut","litterer","slovenly 
woman"],"gram":null,"label4":null},{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["vulgarian"],"gram":null,"label4":null}]},{"process":null,"src":"wordnet","text":"mold
 consisting of a bed of sand in which pig iron is 
cast","partOfSpeech":"noun","relatedWords":[{"label1":null,"relationshipType":"hypernym","label2":null,"label3":null,"words":["mold","cast","mould"],"gram":null,"label4":null}]}]';
+               $this->tempExternalLexicalData = json_decode( 
$this->externalLexicalDataJSON );
+
+               $this->externalLexicalData = array();
+
+               foreach( $this->tempExternalLexicalData as $definition ) {
+                       if ( $definition->src !== 'ahd-legacy' ) {
+
+                               $includeDefinition = $this->includeDefinition( 
$definition );
+
+                               if ( $includeDefinition ) {
+                                       $this->externalLexicalData[] = 
$definition;
+                               }
+
+                       }
+               }
+
+               $this->externalLexicalDataJSON = json_encode( 
$this->externalLexicalData );
+
+       }
+}
+
+class WordnikWiktionaryExtension extends WordnikExtension {
+       function __construct( $spTitle, $source, $sourceLanguageId, $search, 
$collectionId ) {
+               parent::__construct( $spTitle, $source, $sourceLanguageId, 
$search, $collectionId );
+               $this->sourceDictionary = 'wiktionary';
+       }
+}
+
+class WordnikWordnetExtension extends WordnikExtension {
+       function __construct( $spTitle, $source, $sourceLanguageId, $search, 
$collectionId ) {
+               parent::__construct( $spTitle, $source, $sourceLanguageId, 
$search, $collectionId );
+               $this->sourceDictionary = 'wordnet';
+       }
+}
diff --git a/includes/specials/SpecialOWAddFromExternalAPI.php 
b/includes/specials/SpecialOWAddFromExternalAPI.php
new file mode 100644
index 0000000..f739063
--- /dev/null
+++ b/includes/specials/SpecialOWAddFromExternalAPI.php
@@ -0,0 +1,314 @@
+<?php
+
+if ( !defined( 'MEDIAWIKI' ) ) die();
+
+require_once( __DIR__ . "/../../OmegaWiki/OmegaWikiDatabaseAPI.php" );
+/** @file
+ * @brief Special Page to add data from external sources via APIs
+ *
+ * This special page consist of the special page to process data and a
+ *     web api that is used by its accompanying js script ( 
omegawiki-addExtAPI.js ).
+ *     Currently only adds synonyms via an external Wordnik API.
+ *
+ *     First release: September 2014.
+ *
+ * @note he: This is not as simple as I thought. So phase one will only be 
adding synonyms.
+ *
+ * @todo phase 2: text annotations
+ *
+ * @note he: limit SP to editwikidata-uw and exclude blocked users. Is this 
enough
+ *     or too much?
+ */
+class SpecialOWAddFromExternalAPI extends SpecialPage {
+
+       private $saveResult;    // string Used to output JSON via this class' 
web API (POST).
+       private $saveType;              // string The type to save. see save 
function.
+
+       function __construct() {
+               global $wgWldProcessExternalAPIClasses;
+               if ( $wgWldProcessExternalAPIClasses ) {
+                       parent::__construct( 'ow_addFromExtAPI' );
+               } else {
+                       parent::__construct( 'ow_addFromExtAPI', 
'UnlistedSpecialPage' );
+               }
+       }
+
+       /** @brief This function is used as a web API by omegawiki-addExtAPI.js
+        *      This function directs the program to the needed save function 
via $this->saveType.
+        *      Afterwards, outputs a JSON string.
+        */
+       private function save() {
+
+               switch ( $this->saveType ) {
+                       case 'synonym': $this->saveSynonym(); break;
+                       break;
+               }
+
+               // disable wgOut in order to output only the JSON string.
+               global $wgOut;
+               $wgOut->disable();
+               echo json_encode( $this->saveResult );
+
+       }
+
+       /** @brief This is the save function that handles adding Synonyms.
+        *
+        */
+       private function saveSynonym() {
+               $definedMeaningId = array_key_exists( 'dm-id', $_POST ) ? 
$_POST['dm-id']  : '';
+               $languageId = array_key_exists( 'lang-id', $_POST )     ? 
$_POST['lang-id']  : '';
+               $spelling = array_key_exists( 'e', $_POST )     ? $_POST['e']  
: '';
+               $identicalMeaning = array_key_exists( 'im', $_POST )    ? 
$_POST['im']  : 1;
+               $transactionId = array_key_exists( 'tid', $_POST )      ? 
$_POST['tid']  : '';
+               $transacted = array_key_exists( 'transacted', $_POST )  ? 
$_POST['transacted']  : false;
+               $source = array_key_exists( 'src', $_POST )     ? $_POST['src'] 
 : '';
+
+               // @todo create checks for correctness
+               if ( $identicalMeaning === true ) { $identicalMeaning = 1; }
+               if ( $identicalMeaning === false ) { $identicalMeaning = 0; }
+               if ( $identicalMeaning === '' ) { $identicalMeaning = 1; }
+
+               $options = array(
+                       'ver' => '1.1',
+               //      'test' => true,
+                       'dc' => 'uw',
+                       'transacted' => $transacted,
+                       'addedBy' => 'SpecialPage 
SpecialOWAddFromExternalAPI'//,
+               //      'tid',
+               //      'updateId'
+               );
+
+               if ( $transactionId ) {
+                       $options['tid'] = $transactionId;
+                       $options['updateId'] = $transactionId;
+               }
+               $this->saveResult = Syntrans::addWithNotes( $spelling, 
$languageId, $definedMeaningId, $identicalMeaning, $options );
+
+       }
+
+       private function process() {
+               global $myWordnikAPIKey, $wgWldProcessExternalAPIClasses, 
$wgOut;
+
+               // limit access to wikidata editors
+               if ( !$this->getUser()->isAllowed( 'editwikidata-uw' ) ) {
+                       $this->dieUsage( 'you must have a WikiLexicalData edit 
flag to use this page', 'wld_edit_only' );
+               }
+
+               // keep blocked users out
+               if ( $this->getUser()->isBlocked() ) {
+                       $this->dieUsage( 'your account is blocked.', 'blocked' 
);
+               }
+
+               $sourceLanguageId       = array_key_exists( 'from-lang', $_GET 
)        ? $_GET['from-lang']  : '';
+               $source                         = array_key_exists( 'api', 
$_GET )                      ? $_GET['api']        : '';
+               $search                         = array_key_exists( 
'search-ext', $_GET )       ? $_GET['search-ext']     : '';
+               $collectionId           = array_key_exists( 'collection', $_GET 
)       ? $_GET['collection'] : '';
+
+               switch ( $source ) {
+                       case 'Wordnik'                          : 
$this->requireWordnik(); break;
+                       case 'Wordnik-Wiktionary'       : 
$this->requireWordnik(); break;
+                       case 'Wordnik-Wordnet'          : 
$this->requireWordnik(); break;
+               }
+
+               $externalResourceClass = 'ExternalResources';
+               if ( $source ) {
+                       foreach( $wgWldProcessExternalAPIClasses as 
$sourceClass => $sourceValue ) {
+                               if ( $source === $sourceClass ) {
+                                       $externalResourceClass = $sourceClass;
+                               }
+                       }
+               }
+
+               $handlerInstance = new $externalResourceClass(
+                       wfMessage( 'ow_addFromExtAPI_title' )->text(),
+                       $source,
+                       $sourceLanguageId,
+                       $search,
+                       $collectionId
+               );
+               $handlerInstance->execute();
+       }
+
+       /** execute the special page.
+        *
+        * separates the save from the process functions
+        */
+       function execute( $par ) {
+               $this->saveType = array_key_exists( 'save-data', $_POST ) ? 
$_POST['save-data'] : '';
+               if ( $this->saveType ) { $this->save();}
+               else { $this->process();}
+       }
+
+       protected function requireWordik() {
+               require_once( 'ExternalWordnik.php' );
+       }
+
+}
+
+/** @brief This class handles External Resources.
+ *
+ * This class is the base of individual external resources
+ *
+ * @note: To extend this class, the extended class needs its own __construct, 
execute,
+ *     checkExternalDefinition, setExternalDefinition functions.
+ *
+ */
+class ExternalResources {
+
+       protected $wgOut;
+       protected $externalLexicalData = array();
+       protected $owlLexicalData = array();
+       protected $spTitle;
+       protected $source;
+       protected $sourceLanguageId;
+       protected $collectionId;
+       protected $externalDefinition;
+       protected $externalExists = false;              // bool
+       protected $owlDefinition;
+       protected $owlExists = false;                   // bool
+
+
+       /**
+        * @param spTitle          str Special Page Title
+        * @param source           str the source dictionary
+        * @param sourceLabel      str the source dictionary name that will 
appear.
+        * @param sourceLanguageId int The languageId of the source dictionary
+        * @param search           str The expression/spelling( word ) to be 
searched
+        * @param collectionId     int The Collection Id
+        */
+       function __construct( $spTitle, $source, $sourceLanguageId, $search, 
$collectionId ) {
+               global $wgOut;
+               $this->wgOut = $wgOut;
+               $this->spTitle = $spTitle;
+               $this->source = $source;
+               $this->sourceLabel = $source;
+               $this->sourceLanguageId = $sourceLanguageId;
+               $this->search = $search;
+               $this->collectionId = $collectionId;
+       }
+
+       public function execute() {
+               $this->outputTitle();
+               $this->getOptionPanel();
+               $this->checkConnectionStatus();
+
+               // inline css ( for future refactoring )
+               // removes from data when finished testing
+               $this->wgOut->addHTML( $this->temporaryCodeSpace() );
+
+               if ( $this->source ) {
+                       switch ( $this->connection ) {
+                               case true:
+                                       $this->checkExternalDefinition();
+                                       $this->checkOmegaWikiDefinition();
+                                       if ( $this->externalExists and 
$this->owlExists ) {
+                                               $this->setExternalDefinition();
+                                               $this->setOmegaWikiDefinition();
+                                               $this->createChoice();
+                                       }
+                                       break;
+                               case false:
+                                       $this->wgOut->addHtml( 'Sorry, there is 
a problem with the connection. Can not find ' . $this->search );
+                                       break;
+                       }
+               }
+       }
+
+       private function temporaryCodeSpace() {
+               return '<style>' .
+               '#ext-data {visibility: hidden; display: none }' .
+               '#owl-data {visibility: hidden; display: none }' .
+               '</style>';
+       }
+
+       private function createChoice() {
+               $owlLineProcessed = false;
+               $ctr = 0;
+               $this->wgOut->addHTML(
+                       '<form id="flexible_form">'.
+                       '<input type="hidden" name="title" value="Special:Ow 
addFromExtAPI"/>'
+               );
+               $this->wgOut->addHTML(
+                       '<div><div id="owl_def"></div><div 
id="ext_def"></div><span  id="selectChecks"><input type="button" 
id="inputSelectButton" value="process"/></span><span  id="skipChecks"><input 
type="button" id="inputSkipSelectButton" value="next"/></span></div>'
+               );
+               $this->wgOut->addHTML(
+                       '</form>'
+               );
+       }
+
+       private function outputTitle() {
+               $this->wgOut->setPageTitle( $this->spTitle );
+       }
+
+       private function getOptionPanel() {
+               global $wgWldProcessExternalAPIClasses, 
$wgWldExtenalResourceLanguages;
+               $forms = new OmegaWikiForms;
+               $this->wgOut->addHTML( getOptionPanel(
+                       array(
+                               wfMessage( 'ow_api_source' )->text()            
    => $forms->getSelect( 'api',        $wgWldProcessExternalAPIClasses, 
$this->source ),
+                               wfMessage( 'ow_needs_xlation_source_lang' 
)->text() => $forms->getSelect( 'from-lang',  $wgWldExtenalResourceLanguages,  
$this->sourceLanguageId ),
+                               wfMessage( 'datasearch_search_text' )->text()   
    =>        getTextBox( 'search-ext', $this->search ),
+                       )
+               ) );
+       }
+
+       /**
+        */
+       function checkConnectionStatus() {
+               $this->connection = false;
+               if ( connection_status() === CONNECTION_NORMAL ) {
+                       $this->connection = true;
+               }
+       }
+
+       protected function outputResult() {
+               if ( $this->externalLexicalData ) {
+                       $this->wgOut->addHTML( json_encode( 
$this->externalLexicalData ) . '<br/><br/>.' );
+               } else {
+               }
+               if ( $this->owlLexicalData ) {
+                       $this->wgOut->addHTML( json_encode( 
$this->owlLexicalData ) . '<br/><br/>' );
+               } else {
+               }
+       }
+
+       protected function checkOmegaWikiDefinition() {
+               if ( existSpelling( $this->search, $this->sourceLanguageId ) ) {
+                       $this->owlExists = true;
+               }
+       }
+
+       protected function setOmegaWikiDefinition() {
+               // If expression exist in the source language, then proceed.
+               if ( existSpelling( $this->search, $this->sourceLanguageId ) ) {
+                       $this->expressionId = 
OwDatabaseAPI::getTheExpressionId( $this->search, $this->sourceLanguageId );
+                       $dmList = 
OwDatabaseAPI::getExpressionMeaningIdsForLanguages( $this->search, 
$this->sourceLanguageId );
+                       foreach( $dmList as $dmLine ) {
+                               $text = getDefinedMeaningDefinitionForLanguage( 
$dmLine, $this->sourceLanguageId );
+                               if ( !$text ) {
+                                       $text = 
getDefinedMeaningDefinitionForLanguage( $dmLine, WLD_ENGLISH_LANG_ID );
+                               }
+
+                               $synonyms = OwDatabaseAPI::getSynonyms( 
$dmLine, $this->sourceLanguageId, $this->search );
+
+                               $this->owlLexicalData[] = array(
+                                       'processed' => null,
+                                       'e' => $this->search,
+                                       'dm_id' => $dmLine,
+                                       'lang_id' => $this->sourceLanguageId,
+                                       'text' => $text,
+                                       'syn' => $synonyms
+                               );
+                       }
+               }
+
+               $this->owlLexicalDataJSON = json_encode( $this->owlLexicalData 
);
+               // Line below for testing. When there's no internet connection
+       //      $this->owlLexicalDataJSON = 
'[{"processed":null,"dm_id":"5836","lang_id":"85","text":"A common, four-legged 
animal (Sus scrofa) that has cloven hooves, bristles and a nose adapted for 
digging and is farmed by humans for its 
meat.","syn":null},{"processed":null,"dm_id":"1499810","lang_id":"85","text":"(Pejorative)
 A fat or overweight 
person.","syn":[["butterball","85","1","1499814"],["chubster","85","1","1499816"],["chunker","85","1","1499818"],["fat-ass","85","1","1499825"],["fatass","85","1","1499827"],["fatfuck","85","1","1499820"],["fatshit","85","1","1499829"],["fatso","85","1","1499811"],["fattie","85","1","1499822"],["fatty","85","1","1499823"],["lardass","85","1","1499831"],["lardo","85","1","1499833"],["obeast","85","1","1499837"],["oinker","85","1","1499835"],["podge","85","1","1499840"],["porker","85","1","1499842"],["pudge","85","1","1499844"],["salad
 dodger","85","1","1499846"],["tub of 
lard","85","1","1499848"]]},{"processed":null,"dm_id":"583600","lang_id":"85","text":"A
 common, four-legged animal (Sus scrofa) that has cloven hooves, bristles and a 
nose adapted for digging and is farmed by humans for its meat.","syn":null}]';
+
+               $this->wgOut->addHTML(
+                       '<div id="owl-data">' . $this->owlLexicalDataJSON . 
'</div>'
+               );
+       }
+
+}
diff --git a/resources/omegawiki-addExtAPI.js b/resources/omegawiki-addExtAPI.js
new file mode 100644
index 0000000..fdeedbe
--- /dev/null
+++ b/resources/omegawiki-addExtAPI.js
@@ -0,0 +1,348 @@
+// hide these buttons even before the document is ready.
+$('#ext-data').hide();
+$('#owl-data').hide();
+$('#owl_def').hide('');
+$('#ext_def').hide('');
+$('#flexible_form').hide();
+$('#inputSelectButton').hide();
+$('#inputSkipSelectButton').hide();
+
+jQuery(document).ready( function( $ ) {
+
+       $('#flexible_form').slideDown( 'slow' );
+       createExternalAPIDataChoice();
+
+       // process the selected items at flexible forms
+       $('#selectChecks').on('click', function(event) {
+               var selectValue = $('#inputSelectButton').val();
+               if ( selectValue === 'process' ) {
+                       processSelectChecksPhaseOne();
+               }
+
+               if ( selectValue === 'submit' ) {
+                       processSelectChecksPhaseTwo();
+               }
+       });
+
+       // skip the selected items at flexible forms
+       $('#skipChecks').on('click', function(event) {
+               createExternalAPIDataChoice();
+
+               $('input.choices').on('click', function(event) {
+                       checkInputChoices( this );
+               });
+
+               $('input.choosing').on('click', function(event) {
+                       checkInputChoices( this );
+               });
+
+       });
+
+       // toggle input.choices' value ( null or the value of 
$(this).attr('name') )
+       $('input.choices').on('click', function(event) {
+               checkInputChoices( this );
+       });
+
+       // toggle input.choosing' value ( null or the value of 
$(this).attr('name') )
+       $('input.choosing').on('click', function(event) {
+               checkInputChoices( this );
+       });
+
+       function checkInputChoices( selectorName ) {
+               if ( $(selectorName).val() === '' ) {
+                       if( !$(selectorName).attr('name') ) {
+                               $(selectorName).val( 'selected' );
+                       } else {
+                               $(selectorName).val( 
$(selectorName).attr('name') );
+                       }
+               } else {
+                       $(selectorName).val( '' );
+               }
+               console.log( 'value changed to ' + $(selectorName).val() );
+       }
+
+       // adds the necessary output to the screen
+       function createExternalAPIDataChoice() {
+               $('#owl_def').slideUp('');
+               $('#ext_def').slideUp('');
+               var owlExists = nextOwlExists(); // check if there are still DM 
to process
+
+               if( owlExists === true ) {
+                       var     owlLineProcessed = false;
+                       var addOwlHtml = '';
+                       var addExtHtml = '<table><tr>';
+
+                       $('#inputSelectButton').attr( 'value', 'process' 
).show();
+                       $('#inputSkipSelectButton').attr( 'value', 'next' 
).show();
+
+                       // get owlLexicalData
+                       var owlLexicalData = getOwlData();
+
+                       var ctr = 0;
+                       owlLexicalData.forEach( function( oLine ) {
+                       //      if( owlLineProcessed === false && 
owlLexicalData[ctr]['processed'] === null ) {
+                               if( owlLineProcessed === false && 
owlLexicalData[ctr].processed === null ) {
+                                       owlLineProcessed = true;
+                               //      owlLexicalData[ctr]['processed'] = true;
+                                       owlLexicalData[ctr].processed = true;
+                                       if ( oLine.syn === null ) {
+                                               oLineSyn = '';
+                                       } else {
+                                               oLineSyn = JSON.stringify( 
oLine.syn );
+                                       }
+                                       addOwlHtml =
+                                               '<h2>DefinedMeaning:' + oLine.e 
+ ' (' + oLine.dm_id + ')</h2>' + oLine.text +
+                                               '<span id="owl_def_syn" 
style="visibility:hidden;display:none;">' +
+                                               oLineSyn + '</span><hr/>\n'
+                                       ;
+                                       $('#owl_def').attr( 'dm_id', 
oLine.dm_id );
+                                       $('#owl_def').attr( 'lang_id', 
oLine.lang_id );
+                                       $('#owl_def').html( addOwlHtml );
+                                       $('#owl_def').slideDown('slow');
+
+                               }
+                               ctr++;
+                       });
+
+                       // get extLexicalData
+                       var extLexicalData = getExtData();
+
+                       ctr = 0;
+                       extLexicalData.forEach( function( eLine ) {
+                               addExtHtml = addExtHtml + '<td><input 
class="choices" name="' + ctr + '" value="" type="checkbox"/>' +
+                                       eLine.src + '</td><td>' + 
eLine.partOfSpeech + '</td><td>' + eLine.text + '</td></tr><tr>\n';
+                               ctr++;
+                       });
+                       addExtHtml = addExtHtml + '</tr></table>';
+
+                       // refresh flexible_form id
+                       $('#ext_def').html( addExtHtml );
+                       $('#ext_def').slideDown('slow');
+
+                       // refresh owl-data id
+                       owlData = JSON.stringify( owlLexicalData );
+                       $('#owl-data').text( owlData );
+               } else {
+                       resetFlexibleForm();
+                       $('#owl_def').text( 'Finished. No more DefinedMeaning 
to process.' ).slideDown('slow');
+               }
+               return true;
+       }
+
+       // @return array either the external data or an empty array
+       function getExtData() {
+               var thisData = [];
+               var extData = $('#ext-data').text();
+               if ( extData ) {
+                       thisData = JSON.parse( extData );
+               }
+               return thisData;
+       }
+
+       // @return  HTML string of synonyms from external source to choose from.
+       function getExtSynonym( rwWords, dmId, langId, src ) {
+               var includedWord = '';
+               rwWords.forEach(function( theWord ){
+                       var owlDefSyn = $('#owl_def_syn').text();
+                       var includeTheWord = true;
+                       if ( owlDefSyn !== '' ) {
+                               owlDefSyn = JSON.parse( owlDefSyn );
+                               owlDefSyn.forEach( function( owlSynonym ) {
+                                       if ( theWord === owlSynonym[0] ) {
+                                               includeTheWord = false;
+                                       }
+                               });
+                       }
+                       if ( includeTheWord === true ) {
+                               includedWord +=
+                                       '<td><input class="choosing" value="" 
type="checkbox" ' +
+                                       'action="owAddSyntrans" ' +
+                                       'e="' + theWord + '" ' +
+                                       'dm="' + dmId + '" ' +
+                                       'lang="' + langId + '" ' +
+                                       'src="' + src + '" ' +
+                                       'im="' + '' + '" ' + // he: future 
implementation?
+                               '/>' +
+                               'add synonym' + '</td><td>' + theWord + 
'</td><td>~ ' + src + '</td></tr>\n<tr>';
+                       }
+               });
+               return includedWord;
+       }
+
+       // @return array either the OmegaWikiLexical data or an empty array
+       function getOwlData() {
+               var thisData = [];
+               var owlData = $('#owl-data').text();
+               if ( owlData ) {
+                       thisData = JSON.parse( owlData );
+               }
+               return thisData;
+       }
+
+       // checks if there are still DMs to process
+       function nextOwlExists() {
+               owlData = getOwlData();
+               owlExists = false;
+               owlData.forEach( function( data ) { if ( data.processed === 
null) {
+                       owlExists = true;
+               }});
+               return owlExists;
+       }
+
+       function processSelectChecksPhaseOne() {
+               var extDef = $('#ext_def').html();
+               var owlDef = $('#owl_def').html();
+               var dmId = $('#owl_def').attr('dm_id');
+               var langId = $('#owl_def').attr('lang_id');
+               var extData = getExtData();
+               var myChoices = extDef.match( /value="\d+"/gm );
+
+               if ( !myChoices ) {
+                       alert( 'No definition selected.' );
+               } else {
+                       var addExtHtml = '';
+
+                       var ctr = 0;
+                       extData.forEach(function( definition ) {
+                               if( definition.relatedWords ) {
+                                       definition.relatedWords.forEach( 
function( rw ) {
+                                               myChoices.forEach( function( 
myChoiceLine ) {
+                                                       ctrChoice = 
myChoiceLine.match( /\d+/ ) + '.';
+                                                       if ( ctr + '.' === 
ctrChoice ) {
+                                                               if( 
rw.relationshipType === 'synonym' ) {
+                                                               //      
console.log( rw['words'] );
+                                                                       
addExtHtml += getExtSynonym( rw['words'], dmId, langId, definition.src );
+                                                               }
+                                                       }
+                                               });
+                                       });
+                               }
+                               ctr++;
+                       });
+
+                       if( addExtHtml !== '' ) {
+                               $('#ext_def').slideUp();
+                               $('#inputSelectButton').attr( 'value', 'submit' 
);
+                               $('#inputSkipSelectButton').attr( 'value', 
'skip' );
+                               var addExtHtml = '<table><tr>' + addExtHtml + 
'</tr></table>';
+                               $('#ext_def').html( addExtHtml );
+                               $('#ext_def').slideDown();
+                       } else {
+                               if ( nextOwlExists() === true ) {
+                                       alert( 'Nothing to add.\nSkipping to 
next definition.');
+                               } else {
+                                       alert( 'Nothing to add.\nNo more 
DefinedMeaning left.');
+                               }
+                               createExternalAPIDataChoice();
+                       }
+
+               }
+
+               $('input.choices').on('click', function(event) {
+                       checkInputChoices( this );
+               });
+
+               $('input.choosing').on('click', function(event) {
+                       checkInputChoices( this );
+               });
+
+       }
+
+       function processSelectChecksPhaseTwo() {
+               var URL = mw.config.get( 'wgServer' ) + mw.config.get( 
'wgScript' );
+               URL = URL + '/Special:Ow_addFromExtAPI';
+               console.log( 'Website:' + URL );
+               var myChoices = [];
+               console.log( 'choosing search result: ' + 
$('#ext_def').html().search( /<input 
class="choosing".+value="selected".+type="checkbox">/gm ) );
+               if ( $('#ext_def').html().search( /<input 
class="choosing".+value="selected".+type="checkbox">/gm ) !== -1 ) {
+                       console.log( 'found choosing' );
+                       myChoices = $('#ext_def').html().match( /<input 
class="choosing".+value="selected".+type="checkbox">/gm );
+               } else {
+                       alert( 'nothing selected' );
+               }
+
+               var tid = null;
+               var processHowMany = myChoices.length;
+               var processedAll = 0;
+               var processStatement = '';
+
+               myChoices.forEach( function( line ){
+                       console.log( line + ' :' + typeof line  );
+                       var exp = line.match( / e=".+" dm/ ).shift().match( 
/".+"/ ).shift().slice( 1, -1 );
+                       var dmId = line.match( / dm="\d+"/ ).shift().match( 
/\d+/ ).shift();
+                       var langId = line.match( / lang="\d+"/ ).shift().match( 
/\d+/ ).shift();
+                       var src = line.match( / src=".+" im/ ).shift().match( 
/".+"/ ).shift().slice( 1, -1 );
+
+                       saveData = {
+                               'e': exp,
+                               'dm-id': dmId,
+                               'lang-id': langId,
+                               'src': src,
+                               'save-data':'synonym',
+                               'printable':'yes'
+                       };
+
+                       if ( tid !== null ) {
+                               saveData.tid = '' + tid;
+                               saveData.transacted = true;
+                       }
+
+                       $.post( URL, saveData, function( data, status ) {
+                               console.log( 'Data: ' + data + '\nStatus: ' + 
status );
+                       //      data = JSON.parse( '{' + data + '}' );
+                               data = JSON.parse( data );
+                               if ( data.note !== 'test run only' ) {
+                                       tid = data.tid;
+                               }
+                               if ( !data.note ) {
+                                       data.note = '';
+                               } else {
+                                       data.note += '.';
+                               }
+
+                               processStatement += data.status + ' ';
+                               if ( data.status === 'exists' ) {
+                                       processStatement = '<br>\n' + data.e + 
' ' + processStatement + 'in ' + data.in;
+                               //      processStatement += ' in ' + data.in;
+                               } else {
+                                       processStatement =  '<br>\n' + 
processStatement + data.e +' to ' + data.to;
+                               }
+                               processStatement += '. ' + data.note + '<br/>\n'
+                                       ;
+                               processedAll++;
+
+                               if ( processedAll === processHowMany ) {
+                                       processStatement += '<br\n>';
+                                       console.log( processStatement );
+                                       // remove ext_def and replace with 
statement
+                                       $('#ext_def').html( processStatement );
+                                       $('#inputSelectButton').hide();
+                                       $('#inputSkipSelectButton').attr( 
'value', 'next' );
+                               }
+
+                       });
+
+               });
+
+
+               $('input.choices').on('click', function(event) {
+                       checkInputChoices( this );
+               });
+
+               $('input.choosing').on('click', function(event) {
+                       checkInputChoices( this );
+               });
+
+       }
+
+       // basically, blanks the output divs
+       function resetFlexibleForm() {
+               $('#owl_def').text('');
+               $('#ext_def').text('');
+               $('#owl-data').text('');
+               $('#ext-data').text('');
+               $('#inputSelectButton').hide();
+               $('#inputSkipSelectButton').hide();
+       }
+
+});

-- 
To view, visit https://gerrit.wikimedia.org/r/158842
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I36b6e537d8ee518a7bb2146bf09327bc2161ccf0
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/WikiLexicalData
Gerrit-Branch: master
Gerrit-Owner: Hiong3-eng5 <hiong3.e...@gmail.com>
Gerrit-Reviewer: Kipcool <kipmas...@gmail.com>
Gerrit-Reviewer: Siebrand <siebr...@kitano.nl>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to