* stubs for api iFrame Proxy system. Early summary in /js2/mwEmbed/apiProxy/
authorMichael Dale <dale@users.mediawiki.org>
Sat, 17 Oct 2009 10:35:46 +0000 (10:35 +0000)
committerMichael Dale <dale@users.mediawiki.org>
Sat, 17 Oct 2009 10:35:46 +0000 (10:35 +0000)
** testing page for proxy setup (hard coded to localhost)
** added basic support to skin.php for enabling of apiproxy (off by default)

* added flickrSearch as another remote repository
* other refactoring, cleanup of remoteSearchDriver (add-media-wizard)

* removed query.json.1-3.js
* removed jquery.secureEvalJSON.js
* replaced with official http://www.JSON.org/json2.js script which is only included if JSON is undefined

24 files changed:
includes/AutoLoader.php
includes/DefaultSettings.php
includes/Skin.php
js2/apiProxyPage.js [new file with mode: 0644]
js2/editPage.js
js2/mwEmbed/jquery/plugins/jquery.json-1.3.js [deleted file]
js2/mwEmbed/jquery/plugins/jquery.secureEvalJSON.js [deleted file]
js2/mwEmbed/libAddMedia/mvBaseUploadInterface.js
js2/mwEmbed/libAddMedia/remoteSearchDriver.js
js2/mwEmbed/libAddMedia/searchLibs/archiveOrgSearch.js
js2/mwEmbed/libAddMedia/searchLibs/baseRemoteSearch.js
js2/mwEmbed/libAddMedia/searchLibs/flickrSearch.js
js2/mwEmbed/libAddMedia/searchLibs/mediaWikiSearch.js
js2/mwEmbed/libAddMedia/searchLibs/metavidSearch.js
js2/mwEmbed/libAddMedia/seqRemoteSearchDriver.js [deleted file]
js2/mwEmbed/libEmbedVideo/nativeEmbed.js
js2/mwEmbed/libMwApi/NestedCallbackIframe.html [new file with mode: 0644]
js2/mwEmbed/libMwApi/json2.js [new file with mode: 0644]
js2/mwEmbed/libMwApi/mw.proxy.js [new file with mode: 0644]
js2/mwEmbed/libMwApi/mwProxy.js [new file with mode: 0644]
js2/mwEmbed/mv_embed.js
js2/mwEmbed/php/languages/mwEmbed.i18n.php
js2/mwEmbed/tests/testApiProxy.html [new file with mode: 0644]
js2/remoteMwEmbed.js

index 94e4dce..8ca1a4d 100644 (file)
@@ -619,6 +619,7 @@ $wgJSAutoloadLocalClasses = array(
        'uploadPage' => 'js2/uploadPage.js',
        'editPage' => 'js2/editPage.js',
        'ajaxCategories' => 'js2/ajaxcategories.js',
+       'apiProxyPage'  => 'js2/apiProxyPage.js'
 );
 
 class AutoLoader {
index c135b37..8087816 100644 (file)
@@ -213,9 +213,9 @@ $wgImgAuthPublicTest = true; ///< defaults to true - if public read is turned on
  *    thumbScriptUrl    The URL for thumb.php (optional, not recommended)
  *    transformVia404   Whether to skip media file transformation on parse and rely on a 404
  *                      handler instead.
- *    initialCapital    Equivalent to $wgCapitalLinks (or $wgCapitalLinkOverrides[NS_FILE], 
- *                      determines whether filenames implicitly start with a capital letter. 
- *                      The current implementation may give incorrect description page links 
+ *    initialCapital    Equivalent to $wgCapitalLinks (or $wgCapitalLinkOverrides[NS_FILE],
+ *                      determines whether filenames implicitly start with a capital letter.
+ *                      The current implementation may give incorrect description page links
  *                      when the local $wgCapitalLinks and initialCapital are mismatched.
  *    pathDisclosureProtection
  *                      May be 'paranoid' to remove all parameters from error messages, 'none' to
@@ -462,7 +462,7 @@ $wgMaxUploadSize = 1024*1024*100; # 100MB
 
 
 /**
- * Enable Firefogg support. Adds support for in-browser transcoding to Ogg 
+ * Enable Firefogg support. Adds support for in-browser transcoding to Ogg
  * Theora, chunked uploads for large image files and client side hash checks.
  *
  * Ignored unless $wgEnableJS2system is true.
@@ -2438,11 +2438,11 @@ $wgCapitalLinks = true;
 
 /**
  * @since 1.16 - This can now be set per-namespace. Some special namespaces (such
- * as Special, see Namespace::$alwaysCapitalizedNamespaces for the full list) must be 
- * true by default (and setting them has no effect), due to various things that 
- * require them to be so. Also, since Talk namespaces need to directly mirror their 
- * associated content namespaces, the values for those are ignored in favor of the 
- * subject namespace's setting. Setting for NS_MEDIA is taken automatically from 
+ * as Special, see Namespace::$alwaysCapitalizedNamespaces for the full list) must be
+ * true by default (and setting them has no effect), due to various things that
+ * require them to be so. Also, since Talk namespaces need to directly mirror their
+ * associated content namespaces, the values for those are ignored in favor of the
+ * subject namespace's setting. Setting for NS_MEDIA is taken automatically from
  * NS_FILE.
  * EX: $wgCapitalLinkOverrides[ NS_FILE ] = false;
  */
@@ -2787,7 +2787,7 @@ $wgEnableScriptLoader = false;
  *
  * note this will only check core scripts that are directly included on the page.
  * (not scripts loaded after the initial page display since after initial page
- * display scripts inherit the unique request id) 
+ * display scripts inherit the unique request id)
  *
  * and or you can update $wgStyleVersion
  */
@@ -2799,6 +2799,11 @@ $wgScriptModifiedCheck = true;
  */
 $wgEnableJS2system = false;
 
+/*
+ * enable api iframe proxy
+ */
+$wgEnableIframeApiProxy = false;
+
 /*
  * boolean; if we should minify the output. (note if you send ?debug=true in
  * the page request it will automatically not group and not minify)
@@ -2806,7 +2811,7 @@ $wgEnableJS2system = false;
 $wgEnableScriptMinify = true;
 
 /*
- * boolean; if we should enable javascript localization (it loads loadGM json 
+ * boolean; if we should enable javascript localization (it loads loadGM json
  * call with mediaWiki msgs)
  */
 $wgEnableScriptLocalization = true;
@@ -2817,7 +2822,7 @@ $wgEnableScriptLocalization = true;
 $wgMwEmbedDirectory = "js2/mwEmbed/";
 
 /*
- * Turn on debugging for the javascript script-loader & forces fresh copies 
+ * Turn on debugging for the javascript script-loader & forces fresh copies
  * of javascript
  */
 $wgDebugJavaScript = false;
@@ -3729,7 +3734,7 @@ $wgAjaxWatch = true;
 $wgAjaxUploadDestCheck = true;
 
 /**
- * Enable the AJAX upload interface (needed for large http uploads & to display 
+ * Enable the AJAX upload interface (needed for large http uploads & to display
  * progress on uploads for browsers that support it)
  */
 $wgAjaxUploadInterface = true;
@@ -4010,7 +4015,7 @@ $wgExceptionHooks = array();
  * Page property link table invalidation lists. When a page property
  * changes, this may require other link tables to be updated (eg
  * adding __HIDDENCAT__ means the hiddencat tracking category will
- * have been added, so the categorylinks table needs to be rebuilt). 
+ * have been added, so the categorylinks table needs to be rebuilt).
  * This array can be added to by extensions.
  */
 $wgPagePropLinkInvalidations = array(
index a0c3311..81dd0bf 100644 (file)
@@ -363,6 +363,7 @@ class Skin extends Linker {
                global $wgVersion, $wgEnableAPI, $wgEnableWriteAPI;
                global $wgRestrictionTypes, $wgLivePreview;
                global $wgMWSuggestTemplate, $wgDBname, $wgEnableMWSuggest;
+               global $wgSitename, $wgEnableIframeApiProxy, $wgEnableJS2system;
 
                $ns = $wgTitle->getNamespace();
                $nsname = MWNamespace::exists( $ns ) ? MWNamespace::getCanonicalName( $ns ) : $wgTitle->getNsText();
@@ -413,6 +414,7 @@ class Skin extends Linker {
                        'wgMainPageTitle' => $mainPage ? $mainPage->getPrefixedText() : null,
                        'wgFormattedNamespaces' => $wgContLang->getFormattedNamespaces(),
                        'wgNamespaceIds' => $wgContLang->getNamespaceIds(),
+                       'wgSiteName' => $wgSitename,
                );
                if ( $wgContLang->hasVariants() ) {
                        $vars['wgUserVariant'] = $wgContLang->getPreferredVariant();
@@ -442,6 +444,17 @@ class Skin extends Linker {
                        $vars['wgLivepreviewMessageError']   = wfMsg( 'livepreview-error' );
                }
 
+               //add api proxy var and script link if on the special proxy page:
+               if( $wgEnableJS2system &&
+                       $wgTitle->getNamespace() == NS_MEDIAWIKI &&
+                       $wgTitle->getDBKey() == 'ApiProxy' )
+               {
+                       $vars['wgEnableIframeApiProxy'] = $wgEnableIframeApiProxy;                      
+                       //also add the apiProxy Page script if we are on that page
+                       if( $wgEnableIframeApiProxy )
+                               $wgOut->addScriptClass( 'apiProxyPage' );
+               }
+
                if ( $wgOut->isArticleRelated() && $wgUseAjax && $wgAjaxWatch && $wgUser->isLoggedIn() ) {
                        $msgs = (object)array();
                        foreach ( array( 'watch', 'unwatch', 'watching', 'unwatching' ) as $msgName ) {
@@ -864,7 +877,7 @@ END;
                $catlinks = $this->getCategoryLinks();
 
                $classes = 'catlinks';
-               
+
                // Check what we're showing
                global $wgOut, $wgUser;
                $allCats = $wgOut->getCategoryLinks();
@@ -960,7 +973,7 @@ END;
                        else
                                $ret .= str_repeat( "<ul><li>\n", $diff );
                        $ret .= $display . "\n";
-                       
+
                        $curIdent = $ident;
                }
                $ret .= str_repeat( '</li></ul>', $curIdent ) . '</li>';
diff --git a/js2/apiProxyPage.js b/js2/apiProxyPage.js
new file mode 100644 (file)
index 0000000..46ff0fe
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+* mwProxy js2 page system.
+*
+* invokes the apiProxy system 
+*/
+
+/*
+ * since this is proxy server set a pre-append debug flag to know which debug msgs are coming from where
+ */
+
+if( !mwApiProxyConfig )
+       var mwApiProxyConfig = {};
+
+//The default mwApiProxyConfig config 
+//(presently hard coded but should read from user and site config)  
+var mwApiProxyDefaultConfig = {
+               'master_whitelist'      : [  'en.wikipedia.org', 'localhost', '127.1.1.100' ],
+               'master_blacklist'      : []                                    
+};
+//user_white_list should also be checked and configured at runtime.
+
+js2AddOnloadHook( function() {                         
+       //build our configuration from the default and mwApiProxyConfig vars
+       mwApiProxyConfig = $j.extend(true, mwApiProxyDefaultConfig,  mwApiProxyConfig);
+       
+       $j.apiProxy( 'server', mwApiProxyConfig );      
+});
index 63958ff..1c0d1e0 100644 (file)
@@ -24,7 +24,7 @@ var defaultAddMediaConfig = {
 js2AddOnloadHook( function() {
        var amwConf = $j.extend( true, defaultAddMediaConfig, mwAddMediaConfig );
        // kind of tricky, it would be nice to use run on ready "loader" call here
-       if( typeof $j.wikiEditor != 'undefined' ) {             
+       if( typeof $j.wikiEditor != 'undefined' ) {
                        $j( 'textarea#wpTextbox1' ).bind( 'wikiEditor-toolbar-buildSection-main',
                    function( e, section ) {
                        if ( typeof section.groups.insert.tools.file !== 'undefined' ) {
diff --git a/js2/mwEmbed/jquery/plugins/jquery.json-1.3.js b/js2/mwEmbed/jquery/plugins/jquery.json-1.3.js
deleted file mode 100644 (file)
index 225ca82..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * jQuery JSON Plugin
- * version: 1.0 (2008-04-17)
- *
- * This document is licensed as free software under the terms of the
- * MIT License: http://www.opensource.org/licenses/mit-license.php
- *
- * Brantley Harris technically wrote this plugin, but it is based somewhat
- * on the JSON.org website's http://www.json.org/json2.js, which proclaims:
- * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
- * I uphold.  I really just cleaned it up.
- *
- * It is also based heavily on MochiKit's serializeJSON, which is 
- * copywrited 2005 by Bob Ippolito.
- */
-(function($) {   
-    function toIntegersAtLease(n) 
-    // Format integers to have at least two digits.
-    {    
-        return n < 10 ? '0' + n : n;
-    }
-
-    Date.prototype.toJSON = function(date)
-    // Yes, it polutes the Date namespace, but we'll allow it here, as
-    // it's damned usefull.
-    {
-        return this.getUTCFullYear()   + '-' +
-             toIntegersAtLease(this.getUTCMonth()) + '-' +
-             toIntegersAtLease(this.getUTCDate());
-    };
-
-    var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
-    var meta = {    // table of character substitutions
-            '\b': '\\b',
-            '\t': '\\t',
-            '\n': '\\n',
-            '\f': '\\f',
-            '\r': '\\r',
-            '"' : '\\"',
-            '\\': '\\\\'
-        };
-        
-    $.quoteString = function(string)
-    // Places quotes around a string, inteligently.
-    // If the string contains no control characters, no quote characters, and no
-    // backslash characters, then we can safely slap some quotes around it.
-    // Otherwise we must also replace the offending characters with safe escape
-    // sequences.
-    {
-        if (escapeable.test(string))
-        {
-            return '"' + string.replace(escapeable, function (a) 
-            {
-                var c = meta[a];
-                if (typeof c === 'string') {
-                    return c;
-                }
-                c = a.charCodeAt();
-                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
-            }) + '"';
-        }
-        return '"' + string + '"';
-    };
-    
-    $.toJSON = function(o, compact)
-    {
-        var type = typeof(o);
-        
-        if (type == "undefined")
-            return "undefined";
-        else if (type == "number" || type == "boolean")
-            return o + "";
-        else if (o === null)
-            return "null";
-        
-        // Is it a string?
-        if (type == "string") 
-        {
-            return $.quoteString(o);
-        }
-        
-        // Does it have a .toJSON function?
-        if (type == "object" && typeof o.toJSON == "function") 
-            return o.toJSON(compact);
-        
-        // Is it an array?
-        if (type != "function" && typeof(o.length) == "number") 
-        {
-            var ret = [];
-            for (var i = 0; i < o.length; i++) {
-                ret.push( $.toJSON(o[i], compact) );
-            }
-            if (compact)
-                return "[" + ret.join(",") + "]";
-            else
-                return "[" + ret.join(", ") + "]";
-        }
-        
-        // If it's a function, we have to warn somebody!
-        if (type == "function") {
-            throw new TypeError("Unable to convert object of type 'function' to json.");
-        }
-        
-        // It's probably an object, then.
-        var ret = [];
-        for (var k in o) {
-            var name;
-            type = typeof(k);
-            
-            if (type == "number")
-                name = '"' + k + '"';
-            else if (type == "string")
-                name = $.quoteString(k);
-            else
-                continue;  //skip non-string or number keys
-            
-            var val = $.toJSON(o[k], compact);
-            if (typeof(val) != "string") {
-                // skip non-serializable values
-                continue;
-            }
-            
-            if (compact)
-                ret.push(name + ":" + val);
-            else
-                ret.push(name + ": " + val);
-        }
-        return "{" + ret.join(", ") + "}";
-    };
-    
-    $.compactJSON = function(o)
-    {
-        return $.toJSON(o, true);
-    };
-    
-    $.evalJSON = function(src)
-    // Evals JSON that we know to be safe.
-    {
-        return eval("(" + src + ")");
-    };
-    
-    $.secureEvalJSON = function(src)
-    // Evals JSON in a way that is *more* secure.
-    {
-        var filtered = src;
-        filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
-        filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
-        filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
-        
-        if (/^[\],:{}\s]*$/.test(filtered))
-            return eval("(" + src + ")");
-        else
-            throw new SyntaxError("Error parsing JSON, source is not valid.");
-    };
-})(jQuery);
diff --git a/js2/mwEmbed/jquery/plugins/jquery.secureEvalJSON.js b/js2/mwEmbed/jquery/plugins/jquery.secureEvalJSON.js
deleted file mode 100644 (file)
index 225ca82..0000000
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * jQuery JSON Plugin
- * version: 1.0 (2008-04-17)
- *
- * This document is licensed as free software under the terms of the
- * MIT License: http://www.opensource.org/licenses/mit-license.php
- *
- * Brantley Harris technically wrote this plugin, but it is based somewhat
- * on the JSON.org website's http://www.json.org/json2.js, which proclaims:
- * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
- * I uphold.  I really just cleaned it up.
- *
- * It is also based heavily on MochiKit's serializeJSON, which is 
- * copywrited 2005 by Bob Ippolito.
- */
-(function($) {   
-    function toIntegersAtLease(n) 
-    // Format integers to have at least two digits.
-    {    
-        return n < 10 ? '0' + n : n;
-    }
-
-    Date.prototype.toJSON = function(date)
-    // Yes, it polutes the Date namespace, but we'll allow it here, as
-    // it's damned usefull.
-    {
-        return this.getUTCFullYear()   + '-' +
-             toIntegersAtLease(this.getUTCMonth()) + '-' +
-             toIntegersAtLease(this.getUTCDate());
-    };
-
-    var escapeable = /["\\\x00-\x1f\x7f-\x9f]/g;
-    var meta = {    // table of character substitutions
-            '\b': '\\b',
-            '\t': '\\t',
-            '\n': '\\n',
-            '\f': '\\f',
-            '\r': '\\r',
-            '"' : '\\"',
-            '\\': '\\\\'
-        };
-        
-    $.quoteString = function(string)
-    // Places quotes around a string, inteligently.
-    // If the string contains no control characters, no quote characters, and no
-    // backslash characters, then we can safely slap some quotes around it.
-    // Otherwise we must also replace the offending characters with safe escape
-    // sequences.
-    {
-        if (escapeable.test(string))
-        {
-            return '"' + string.replace(escapeable, function (a) 
-            {
-                var c = meta[a];
-                if (typeof c === 'string') {
-                    return c;
-                }
-                c = a.charCodeAt();
-                return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
-            }) + '"';
-        }
-        return '"' + string + '"';
-    };
-    
-    $.toJSON = function(o, compact)
-    {
-        var type = typeof(o);
-        
-        if (type == "undefined")
-            return "undefined";
-        else if (type == "number" || type == "boolean")
-            return o + "";
-        else if (o === null)
-            return "null";
-        
-        // Is it a string?
-        if (type == "string") 
-        {
-            return $.quoteString(o);
-        }
-        
-        // Does it have a .toJSON function?
-        if (type == "object" && typeof o.toJSON == "function") 
-            return o.toJSON(compact);
-        
-        // Is it an array?
-        if (type != "function" && typeof(o.length) == "number") 
-        {
-            var ret = [];
-            for (var i = 0; i < o.length; i++) {
-                ret.push( $.toJSON(o[i], compact) );
-            }
-            if (compact)
-                return "[" + ret.join(",") + "]";
-            else
-                return "[" + ret.join(", ") + "]";
-        }
-        
-        // If it's a function, we have to warn somebody!
-        if (type == "function") {
-            throw new TypeError("Unable to convert object of type 'function' to json.");
-        }
-        
-        // It's probably an object, then.
-        var ret = [];
-        for (var k in o) {
-            var name;
-            type = typeof(k);
-            
-            if (type == "number")
-                name = '"' + k + '"';
-            else if (type == "string")
-                name = $.quoteString(k);
-            else
-                continue;  //skip non-string or number keys
-            
-            var val = $.toJSON(o[k], compact);
-            if (typeof(val) != "string") {
-                // skip non-serializable values
-                continue;
-            }
-            
-            if (compact)
-                ret.push(name + ":" + val);
-            else
-                ret.push(name + ": " + val);
-        }
-        return "{" + ret.join(", ") + "}";
-    };
-    
-    $.compactJSON = function(o)
-    {
-        return $.toJSON(o, true);
-    };
-    
-    $.evalJSON = function(src)
-    // Evals JSON that we know to be safe.
-    {
-        return eval("(" + src + ")");
-    };
-    
-    $.secureEvalJSON = function(src)
-    // Evals JSON in a way that is *more* secure.
-    {
-        var filtered = src;
-        filtered = filtered.replace(/\\["\\\/bfnrtu]/g, '@');
-        filtered = filtered.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']');
-        filtered = filtered.replace(/(?:^|:|,)(?:\s*\[)+/g, '');
-        
-        if (/^[\],:{}\s]*$/.test(filtered))
-            return eval("(" + src + ")");
-        else
-            throw new SyntaxError("Error parsing JSON, source is not valid.");
-    };
-})(jQuery);
index 7c2bb54..3417e3d 100644 (file)
@@ -359,16 +359,11 @@ mvBaseUploadInterface.prototype = {
                                //@@check if we are done
                                if( data.upload['apiUploadResult'] ){
                                        //update status to 100%
-                                       _this.updateProgress( 1 );
-                                       if(typeof JSON == 'undefined'){
-                                               //we need to load the jQuery json parser: (older browsers don't have JSON.parse
-                                               mvJsLoader.doLoad([
-                                                       '$j.secureEvalJSON'
-                                               ],function(){
-                                                       var  apiResult = $j.secureEvalJSON( data.upload['apiUploadResult'] );
-                                                       _this.processApiResult( apiResult );
-                                               });
-                                       }else{
+                                       _this.updateProgress( 1 );                              
+                                       //see if we need to load JSON substitue:
+                                       mvJsLoader.doLoad( [
+                                               'JSON'
+                                       ],function(){                                                   
                                                var apiResult = {};
                                                try{
                                                        apiResult = JSON.parse ( data.upload['apiUploadResult'] ) ;
@@ -377,7 +372,7 @@ mvBaseUploadInterface.prototype = {
                                                        js_log('errro: could not parse apiUploadResult ')
                                                }
                                                _this.processApiResult( apiResult );
-                                       }
+                                       });
                                        return ;
                                }
 
index c1927e1..7e1f588 100644 (file)
@@ -35,8 +35,8 @@ loadGM({
        "mwe-results_from" : "Results from <a href=\"$1\" target=\"_new\" >$2<\/a>",
        "mwe-missing_desc_see_source" : "This asset is missing a description. Please see the [$1 orginal source] and help describe it.",
        "rsd_config_error" : "Add media wizard configuration error: $1",
-       "mwe-your_recent_uploads" : "Your recent uploads",
-       "mwe-upload_a_file" : "Upload a new file",
+       "mwe-your_recent_uploads" : "Your recent uploads to $1",
+       "mwe-upload_a_file" : "Upload a new file to $1",
        "mwe-resource_page_desc" : "Resource page description:",
        "mwe-edit_resource_desc" : "Edit wiki text resource description:",
        "mwe-local_resource_title" : "Local resource title:",
@@ -47,7 +47,7 @@ loadGM({
        "mwe-importing_asset" : "Importing asset",
        "mwe-preview_insert_resource" : "Preview insert of resource: $1",
        "mwe-checking-resource": "Checking for resource",
-       "mwe-resource-needs-import": "Resource $1 needs to be imported",
+       "mwe-resource-needs-import": "Resource $1 needs to be imported to $2",
        "mwe-ftype-svg" : "SVG vector file",
        "mwe-ftype-jpg" : "JPEG image file",
        "mwe-ftype-png" : "PNG image file",
@@ -81,7 +81,9 @@ var default_remote_search_options = {
        'cFileNS':'File', //What is the canonical namespace prefix for images
                                          //@@todo (should get that from the api or in-page vars)
        
-       'upload_api_target': 'http://localhost/wiki_trunk/api.php', // can be local or the url of the upload api.
+       'upload_api_target': 'local', // can be local or the url or remote
+       'upload_api_name' : null,
+       'upload_api_proxy_frame': null, //a page that will request mw.proxy.server
        
        'enabled_cps':'all', //can be keyword 'all' or an array of enabled content provider keys
                
@@ -173,9 +175,6 @@ remoteSearchDriver.prototype = {
                        'local_domains': ['wikimedia','wikipedia','wikibooks'],
                        //specific to wiki commons config:
                        'search_title':false, //disable title search
-                       //set up default range limit
-                       'offset'                        : 0,
-                       'limit'                         : 30,
                        'tab_img':true
                },
                'archive_org':{
@@ -191,11 +190,24 @@ remoteSearchDriver.prototype = {
                        'resource_prefix': 'AO_',
                        'tab_img':true
                },
-               'metavid':{
+               'flickr':{
                        'enabled':1,
                        'checked':1,
-                       'title' :'Metavid.org',
-                       'homepage':'http://metavid.org',
+                       'title' : 'flickr.com',
+                       'desc'  : 'flickr.com, a online photo sharing site',
+                       'homepage':'http://www.flickr.com/about/',
+
+                       'api_url':'http://www.flickr.com/services/rest/',
+                       'lib'   : 'flickr',
+                       'local' : false,
+                       'resource_prefix': '',
+                       'tab_img':true
+               },
+               'metavid':{
+                       'enabled' : 1,
+                       'checked' : 1,
+                       'title' : 'Metavid.org',
+                       'homepage':'http://metavid.org/wiki/Metavid_Overview',
                        'desc'  : 'Metavid hosts thousands of hours of US house and senate floor proceedings',
                        'api_url':'http://metavid.org/w/index.php?title=Special:MvExportSearch',
                        'lib'   : 'metavid',
@@ -216,7 +228,7 @@ remoteSearchDriver.prototype = {
                'upload':{
                        'enabled':1,
                        'checked':1,
-                       'title' :'Upload'                       
+                       'title' :'Upload',
                }
        },
        //define the licenses
@@ -309,6 +321,10 @@ remoteSearchDriver.prototype = {
         * @param licence_url the url of the license
         */
        getLicenceFromUrl: function( license_url ){
+               //check for some pre-defined url types:
+               if( license_url == 'http://www.usa.gov/copyright.shtml')
+                       return this.getLicenceFromKey('pd' , license_url);
+               
                //js_log("getLicenceFromUrl::" + license_url);                          
                //first do a direct lookup check:
                for(var j =0; j < this.licenses.cc.licenses.length; j++){
@@ -370,6 +386,7 @@ remoteSearchDriver.prototype = {
 
        cUpLoader                       : null,
        cEdit                           : null,
+       proxySetupDone          : null,
        dmodalCss                       : {},
 
        init: function( options ){
@@ -394,7 +411,11 @@ remoteSearchDriver.prototype = {
                                }
                        }
                }               
-
+               //set the upload target name if unset
+               if( _this.upload_api_target == 'local' &&  ! _this.upload_api_name && wgSiteName)
+                       _this.upload_api_name =  wgSiteName;
+               
+               
                //set up the target invocation:
                if( $j( this.target_invocation ).length==0 ){
                        js_log("RemoteSearchDriver:: no target invocation provided (will have to run your own doInitDisplay() )");
@@ -478,14 +499,13 @@ remoteSearchDriver.prototype = {
        init_modal:function(){
                js_log("init_modal");
                var _this = this;
+               _this.target_container = '#rsd_modal_target';
                //add the parent target_container if not provided or missing
                if(!_this.target_container || $j(_this.target_container).length==0){
-                       $j('body').append('<div id="rsd_modal_target" style="position:absolute;top:3em;left:0px;bottom:3em;right:0px;" title="' + gM('mwe-add_media_wizard') + '" ></div>');
-                       _this.target_container = '#rsd_modal_target';
+                       $j('body').append('<div id="rsd_modal_target" style="position:absolute;top:3em;left:0px;bottom:3em;right:0px;" title="' + gM('mwe-add_media_wizard') + '" ></div>');                    
                        //js_log('appended: #rsd_modal_target' + $j(_this.target_container).attr('id'));
                        //js_log('added target id:' + $j(_this.target_container).attr('id'));
                        //get layout
-                       //layout = _this.getMaxModalLayout();
                        js_log( 'width: ' + $j(window).width() +  ' height: ' + $j(window).height());
                        var cConf = {};
                        cConf['cancel'] = function(){
@@ -508,9 +528,8 @@ remoteSearchDriver.prototype = {
                                close: function() {
                                        //if we are 'editing' a item close that 
                                        //@@todo maybe prompt the user?                                         
-                                       _this.cancelClipEditCB();                                               
-                                       //$j(this).dialog('close');             
-                                       $j(this).parents('.ui-dialog').fadeOut('slow');
+                                       _this.cancelClipEditCB();                                                                                                                       
+                                       $j(this).parents('.ui-dialog').fadeOut('slow');                         
                                }
                        });                             
                        doResize();
@@ -528,25 +547,7 @@ remoteSearchDriver.prototype = {
                                'left':'0px',
                                'right':'0px',
                                'bottom':'0px'
-                       });
-                       /*
-                       
-                       
-                       js_log('done setup of target_container: ' +
-                               $j(_this.target_container +'~ .ui-dialog-buttonpane').length);
-                       */
-                       
-               }
-       },
-       getMaxModalLayout:function(border){
-               if(!border)
-                       border = 50;
-               //js_log('setting h:' + (parseInt( $j(document).height() ) - parseInt(border*2)) + ' from:' + $j(document).height() );
-               return {
-                       'h': parseInt( $j(document).height() ) - parseInt(border*4),
-                       'w': parseInt( $j(document).width() ) - parseInt(border*2),
-                       'r': border,
-                       't': border
+                       });                     
                }
        },
        //sets up the initial html interface
@@ -623,82 +624,85 @@ remoteSearchDriver.prototype = {
                                        _this.upload_api_target = _this.local_wiki_api_url;
                                }
                        }
+                       
                        //make sure we have a url for the upload target:
                        if(  parseUri( _this.upload_api_target ).host ==  _this.upload_api_target ){
                                $j('#tab-upload').html( gM('rsd_config_error', 'bad_api_url') );
                                return false;
                        }
-                       //output the form
-                       //set the form action based on domain:
-                       if( parseUri( document.URL ).host == parseUri( _this.upload_api_target ).host ){
-                               mvJsLoader.doLoad(['$j.fn.simpleUploadForm'],function(){
-
-                                       //get extends info about the file
-                                       var cp = _this.content_providers['this_wiki'];
-                                       //check for "this_wiki" enabled
-                                       /*if(!cp.enabled){
-                                               $j('#tab-upload').html('error this_wiki not enabled (can\'t get uploaded file info)');
-                                               return false;
-                                       }*/
-
-                                       //load  this_wiki search system to grab the rObj
-                                       _this.loadSearchLib(cp, function(){
-                                               //do basic layout form on left upload "bin" on right
-                                               $j('#tab-upload').html('<table>' +
-                                               '<tr>' +
-                                                       '<td valign="top" style="width:350px; padding-right: 12px;">' +
-                                                               '<h4>' + gM('mwe-upload_a_file') + '</h4>' +
-                                                               '<div id="upload_form">' +
-                                                                       mv_get_loading_img() +
-                                                               '</div>' +
-                                                       '</td>' +
-                                                       '<td valign="top" id="upload_bin_cnt">' +
-                                                       '<h4>' + gM('mwe-your_recent_uploads') + '</h4>' +
-                                                               '<div id="upload_bin">' +
-                                                                       mv_get_loading_img() +
-                                                               '</div>'+
-                                                       '</td>' +
-                                               '</tr>' +
-                                               '</table>');
-
-
-                                               //fill in the user page:
-                                               if(typeof wgUserName != 'undefined' && wgUserName){                                             
-                                                       //load the upload bin with anything the current user has uploaded
-                                                       cp.sObj.getUserRecentUploads( wgUserName, function(){
-                                                               _this.drawOutputResults();
-                                                       });
-                                               }else{
-                                                       $j('#upload_bin_cnt').empty();
-                                               }
-
-                                               //deal with the api form upload form directly:
-                                               $j('#upload_form').simpleUploadForm({
-                                                       "api_target" :  _this.upload_api_target,
-                                                       "ondone_cb"     : function( resultData ){
-                                                               var wTitle = resultData['filename'];    
-                                                               //add a loading div
-                                                               _this.addResourceEditLoader();
-                                                               //@@note: we have most of what we need in resultData imageinfo
-                                                               cp.sObj.addByTitle( wTitle, function( rObj ){                                                           
-                                                                       //redraw (with added result if new)
-                                                                       _this.drawOutputResults();
-                                                                       //pull up resource editor:                                                                      
-                                                                       _this.resourceEdit( rObj, $j('#res_upload__' + rObj.id).get(0) );                                                                       
-                                                               });
-                                                               //return false to close progress window:
-                                                               return false;
-                                                       }
-                                               })
-                                       });
-                               });
-                       }else{
-                               //setup the proxy
-                               js_log('do proxy:: ' + parseUri( _this.upload_api_target ).host);
-                               $j('#tab-upload').html('proxy upload not yet ready');
-                       }
+                       //check if we need to setup the proxy::
+                       if( parseUri( document.URL ).host != parseUri( _this.upload_api_target ).host ){
+                               //setup proxy
+                               $j('#tab-upload').html( 'do proxy setup');
+                       }else{                          
+                               _this.getUploadForm();
+                       }                                                       
                },1);
        },
+       getUploadForm:function(){
+               var _this = this;
+               mvJsLoader.doLoad(['$j.fn.simpleUploadForm'],function(){
+                       //get extends info about the file
+                       var cp = _this.content_providers['this_wiki'];
+                       
+                       //check for "this_wiki" enabled
+                       /*if(!cp.enabled){
+                               $j('#tab-upload').html('error this_wiki not enabled (can\'t get uploaded file info)');
+                               return false;
+                       }*/
+       
+                       //load  this_wiki search system to grab the rObj
+                       _this.loadSearchLib(cp, function(){
+                               //do basic layout form on left upload "bin" on right
+                               $j('#tab-upload').html('<table>' +
+                               '<tr>' +
+                                       '<td valign="top" style="width:350px; padding-right: 12px;">' +
+                                               '<h4>' + gM('mwe-upload_a_file', _this.upload_api_name ) + '</h4>' +
+                                               '<div id="upload_form">' +
+                                                       mv_get_loading_img() +
+                                               '</div>' +
+                                       '</td>' +
+                                       '<td valign="top" id="upload_bin_cnt">' +
+                                       '<h4>' + gM('mwe-your_recent_uploads', _this.upload_api_name) + '</h4>' +
+                                               '<div id="upload_bin">' +
+                                                       mv_get_loading_img() +
+                                               '</div>'+
+                                       '</td>' +
+                               '</tr>' +
+                               '</table>');
+       
+       
+                               //fill in the user page:
+                               if(typeof wgUserName != 'undefined' && wgUserName){                                             
+                                       //load the upload bin with anything the current user has uploaded
+                                       cp.sObj.getUserRecentUploads( wgUserName, function(){
+                                               _this.drawOutputResults();
+                                       });
+                               }else{
+                                       $j('#upload_bin_cnt').empty();
+                               }
+       
+                               //deal with the api form upload form directly:
+                               $j('#upload_form').simpleUploadForm({
+                                       "api_target" :  _this.upload_api_target,
+                                       "ondone_cb"     : function( resultData ){
+                                               var wTitle = resultData['filename'];    
+                                               //add a loading div
+                                               _this.addResourceEditLoader();
+                                               //@@note: we have most of what we need in resultData imageinfo
+                                               cp.sObj.addByTitle( wTitle, function( rObj ){                                                           
+                                                       //redraw (with added result if new)
+                                                       _this.drawOutputResults();
+                                                       //pull up resource editor:                                                                      
+                                                       _this.resourceEdit( rObj, $j('#res_upload__' + rObj.id).get(0) );                                                                       
+                                               });
+                                               //return false to close progress window:
+                                               return false;
+                                       }
+                               });             
+                       }); //load searchLibs
+               }); //load simpleUploadForm
+       },
        runSearch: function(){
                js_log("f:runSearch::" + this.disp_item);
                //draw_direct_flag
@@ -709,9 +713,9 @@ remoteSearchDriver.prototype = {
                        this.doUploadInteface();
                        return true;
                }
-               //else do runSearch                     
                
-               cp = this.content_providers[this.disp_item];
+               //else do runSearch                                     
+               var cp = this.content_providers[this.disp_item];
 
                //check if we need to update:
                if( typeof cp.sObj != 'undefined' ){
@@ -737,6 +741,15 @@ remoteSearchDriver.prototype = {
        checkForCopyURLSupport:function ( callback ){
                var _this = this;
                js_log('checkForCopyURLSupport:: ');
+               //check if the import url is diffrent from 
+               //check if we need to setup the proxy::
+               /*if( parseUri( document.URL ).host != parseUri( _this.upload_api_target ).host ){                      
+                       //setup proxy
+                       js_log(" doc.url:" +  parseUri( document.URL ).host + ' != ' +parseUri( _this.upload_api_target ).host);
+                       $j('#tab-' + this.disp_item ).html( 'do proxy setup');
+                       return false;
+               }*/
+               
                //see if we already have the import mode:
                if( this.import_url_mode != 'autodetect'){
                        js_log('import mode: ' + _this.import_url_mode);
@@ -860,7 +873,7 @@ remoteSearchDriver.prototype = {
                        var cp = this.content_providers[ cp_id ];
                        if(typeof cp['sObj'] != 'undefined'){
                                if( cp.sObj.loading )
-                                       loading_done=false;
+                                       loading_done = false;
                        }
                }
                if( loading_done ){
@@ -996,10 +1009,10 @@ remoteSearchDriver.prototype = {
                        _this.setResultBarControl();
                }
                
-               var drawResultCount     =0;
+               var drawResultCount     = 0;
 
                //output all the results for the current disp_item
-               if( typeof cp['sObj'] != 'undefined' ){
+               if( typeof cp['sObj'] != 'undefined' ){                 
                        $j.each(cp.sObj.resultsObj, function(rInx, rItem){
                                if( _this.result_display_mode == 'box' ){
                                        o+='<div id="mv_result_' + rInx + '" class="mv_clip_box_result" style="width:' +
@@ -1051,7 +1064,7 @@ remoteSearchDriver.prototype = {
                        $j(tab_target).append( o + '<div style="clear:both"/>');
                }
 
-               js_log( ' drawResultCount :: ' + drawResultCount + ' append: ' + $j('#rsd_q').val() );
+               js_log( 'did drawResultCount :: ' + drawResultCount + ' append: ' + $j('#rsd_q').val() );
 
                //remove any old search res
                $j('#rsd_no_search_res').remove();
@@ -1206,7 +1219,7 @@ remoteSearchDriver.prototype = {
                        });
        },
        cancelClipEditCB:function(){
-               var _this = this;
+               var _this = this;               
                js_log('cancelClipEditCB');
                var b_target =   _this.target_container + '~ .ui-dialog-buttonpane';
                $j('#rsd_resource_edit').remove();
@@ -1218,12 +1231,12 @@ remoteSearchDriver.prototype = {
                //restore the title:
                $j( _this.target_container ).dialog( 'option', 'title', gM('mwe-add_media_wizard'));
                js_log("should update: " + b_target + ' with: cancel');
-               //restore the buttons:
+               //restore the buttons:          
                $j(b_target).html( $j.btnHtml( 'Cancel' , 'mv_cancel_rsd', 'close'))
                        .children('.mv_cancel_rsd')
                        .btnBind()
                        .click(function(){
-                               $j( _this.target_container).dialog('close');
+                               $j( _this.target_container).dialog('close');                            
                        })
 
        },
@@ -1253,16 +1266,17 @@ remoteSearchDriver.prototype = {
                js_log('remoteSearchDriver::doMediaEdit: ' + mediaType);
                
                var mvClipInit = {
-                               'rObj':rObj, //the resource object
-                               'parent_ct'                     : 'rsd_modal_target',
-                               'clip_disp_ct'          : 'clip_edit_disp',
-                               'control_ct'            : 'clip_edit_ctrl',
-                               'media_type'            : mediaType,
-                               'p_rsdObj'                      : _this,
-                               'controlActionsCb'      : _this.getClipEditControlActions( cp )
+                       'rObj' : rObj, //the resource object
+                       'parent_ct'                     : 'rsd_modal_target',
+                       'clip_disp_ct'          : 'clip_edit_disp',
+                       'control_ct'            : 'clip_edit_ctrl',
+                       'media_type'            : mediaType,
+                       'p_rsdObj'                      : _this,
+                       'controlActionsCb'      : _this.getClipEditControlActions( cp )
                };
-
+               //set the base clip edit lib class req set:
                var clibs = ['mvClipEdit'];
+               
                if( mediaType == 'image'){
                        //display the mvClipEdit obj once we are done loading:
                        mvJsLoader.doLoad( clibs, function(){
@@ -1432,7 +1446,7 @@ remoteSearchDriver.prototype = {
                $j( _this.target_container ).append('<div id="rsd_resource_import" '+
                'class="ui-state-highlight ui-widget-content ui-state-error" ' +
                'style="position:absolute;top:50px;left:50px;right:50px;bottom:50px;z-index:5">' +
-                       '<h3 style="color:red">' + gM('mwe-resource-needs-import', rObj.title) + '</h3>' +
+                       '<h3 style="color:red">' + gM('mwe-resource-needs-import', [rObj.title, _this.upload_api_name] ) + '</h3>' +
                                '<div id="rsd_preview_import_container" style="position:absolute;width:50%;bottom:0px;left:0px;overflow:auto;top:30px;">' +
                                        rObj.pSobj.getEmbedHTML( rObj, {
                                                'id': _this.target_container + '_rsd_pv_vid', 
@@ -1468,7 +1482,8 @@ remoteSearchDriver.prototype = {
                //add hover:
                
                //update video tag (if a video) 
-               rewrite_by_id( _this.target_container + '_rsd_pv_vid');
+               if( rObj.mime.indexOf('video/') !== -1 )
+                       rewrite_by_id( $j(_this.target_container).attr('id') + '_rsd_pv_vid');
                
                //load the preview text:
                _this.getParsedWikiText( wt, _this.cFileNS +':'+ rObj.target_resource_title, function( o ){
@@ -1487,7 +1502,14 @@ remoteSearchDriver.prototype = {
                        js_log("do import asset:" + _this.import_url_mode);
                        //check import mode:                                    
                        if( _this.import_url_mode == 'api' ){
-                               _this.doImportAPI( rObj , callback);
+                               if( parseUri( document.URL ).host != parseUri( _this.upload_api_target ).host ){
+                                       _this.setupProxy( function(){
+                                               debugger;
+                                               //_this.doImportAPI( rObj , callback);                                          
+                                       });                                                                                             
+                               }else{
+                                       _this.doImportAPI( rObj , callback);
+                               }
                        }else{
                                js_log("Error: import mode is not form or API (can not copy asset)");
                        }
@@ -1497,7 +1519,33 @@ remoteSearchDriver.prototype = {
                                $j(this).remove();
                        });
                });                                                                     
-       },                                              
+       },                      
+       /** 
+        * sets up the proxy for the remote inserts
+        */
+       setupProxy:function(callback){
+               var _this = this;
+               
+               if( _this.proxySetupDone ){
+                       if(callback) callback();
+                       return ;
+               }
+               //setup the the proxy via mv_embed  $j.apiProxy loader:
+               if( ! _this.upload_api_proxy_frame ){
+                       js_log("Error:: remote api but no proxy frame target");
+                       return false;
+               }else{                  
+                       $j.apiProxy(
+                               'client',
+                               {
+                                       'server_frame' : _this.upload_api_proxy_frame,                                  
+                               },function(){
+                                       //now that the api is setup call actual import
+                                       debugger;
+                               }                       
+                       );      
+               }
+       },
        checkForFile:function( fName, callback){
                js_log("checkForFile::");
                var _this = this;        
@@ -1559,7 +1607,7 @@ remoteSearchDriver.prototype = {
                                
                                //close the loader now that we are ready to present the progress dialog::
                                $j.closeLoaderDialog();
-                               
+                                                               
                                myUp.doHttpUpload({
                                        'url'       : rObj.src,
                                        'filename'  : rObj.target_resource_title,
@@ -1755,7 +1803,7 @@ remoteSearchDriver.prototype = {
                        var cp = _this.content_providers['this_wiki'];
                }else{          
                        var cp = this.content_providers[ this.disp_item ];
-               }
+               }               
                //js_log('getPaging:'+ cp_id + ' len: ' + cp.sObj.num_results);
                var to_num = ( cp.limit > cp.sObj.num_results )?
                                                (cp.offset + cp.sObj.num_results):
index 02bbaa7..2285d16 100644 (file)
@@ -23,23 +23,21 @@ archiveOrgSearch.prototype = {
        },
        getSearchResults:function(){
                //call parent: 
-               this.parent_getSearchResults();
-               
-               var _this = this;               
-               this.loading=true;
+               this.parent_getSearchResults();         
+               var _this = this;                               
                js_log('f:getSearchResults for:' + $j('#rsd_q').val() );                
                //build the query var
                var q = $j('#rsd_q').val();
                //@@todo check advanced options: include audio and images media types
-               //for now force (Ogg video) & a creativecommons license
+               //for now force (Ogg video) & url based license
                q+=' format:(Ogg video)';
                q+=' licenseurl:(http\\:\\/\\/*)';
                var reqObj = {
                        'q': q, //just search for video atm
                        'fl':"description,title,identifier,licenseurl,format,license,thumbnail",                        
                        'wt':'json',                    
-                       'rows':'30',
-                       'indent':'yes'                  
+                       'rows' : this.cp.limit,
+                       'start' : this.cp.offset                                                
                }                                                                       
                do_api_req( {
                        'data':reqObj, 
@@ -77,15 +75,7 @@ archiveOrgSearch.prototype = {
                                        'pSobj'          :_this                         
                                        
                                };                                                                                                                                                                                                               
-                               this.resultsObj[ resource_id ] = rObj;
-                               
-                               //likely a audio clip if no poster and type application/ogg 
-                               //@@todo we should return audio/ogg for the mime type or some other way to specify its "audio" 
-                                               
-                               //this.num_results++;   
-                               //for(var i in this.resultsObj[page_id]){
-                               //      js_log('added: '+ i +' '+ this.resultsObj[page_id][i]);
-                               //}
+                               this.resultsObj[ resource_id ] = rObj;                                                          
                        }
                }               
        },
index 687649f..9fb234a 100644 (file)
@@ -35,9 +35,9 @@ baseRemoteSearch.prototype = {
 
        //default search result values for paging:
        offset                   :0,
-       limit                     :20,
-       more_results    :false,
-       num_results             :0,
+       limit                   : 30,
+       more_results    : false,
+       num_results             : 0,
 
        //init the object:
        init: function( iObj ){
@@ -53,8 +53,9 @@ baseRemoteSearch.prototype = {
                //do global getSearchResults bindings
                this.last_query = $j('#rsd_q').val();
                this.last_offset = this.cp.offset;
-               //@@todo its possible that video rss is the "default" format we could put that logic here:
-       },
+               //set the loading flag:         
+               this.loading=true;
+       },      
        /*
        * Parses and adds video rss based input format
        * @param $data XML data to parse
@@ -146,6 +147,37 @@ baseRemoteSearch.prototype = {
                        _this.num_results++;
                });
        },
+       getEmbedHTML: function( rObj , options) {
+               if(!options)
+                       options = {};
+               //set up the output var with the default values: 
+               var outOpt = { 'width': rObj.width, 'height': rObj.height};
+               if( options['max_height'] ){                    
+                       outOpt.height = (options.max_height > rObj.height) ? rObj.height : options.max_height;  
+                       outOpt.width = (rObj.width / rObj.height) *outOpt.height;                       
+               }                                               
+               options.style_attr = 'style="width:' + outOpt.width + 'px;height:' + outOpt.height +'px"';
+               options.id_attr = (options['id'])?' id = "' + options['id'] +'" ': '';
+               
+               if( rObj.mime.indexOf('image') != -1 ){
+                       return this.getImageEmbedHTML( rObj, options );
+               }else{
+                       js_log("ERROR:: no embed code for mime type: " + rObj.mime);
+                       return ' Error missing embed code ';
+               }
+       },
+       getImageEmbedHTML:function( rObj, options ) {   
+               //if crop is null do base output: 
+               var imgHtml = '<img ' + options.id_attr + ' src="' + rObj.edit_url  + '"' + options.style_attr + ' >';
+               if( rObj.crop == null)
+                       return imgHtml
+               //else do crop output:  
+                       return '<div style="width:'+rObj.crop.w +'px;height: ' + rObj.crop.h +'px;overflow:hidden;position:relative">' +
+                                               '<div style="position:relative;top:-' + rObj.crop.y +'px;left:-' + rObj.crop.x +'px">'+
+                                                       imgHtml + 
+                                               '</div>'+
+                                       '</div>';
+       },
        //by default just return the existing image with callback
        getImageObj:function( rObj, size, callback){
                callback( {'url':rObj.poster} );
index 1b9c3ab..8a137de 100644 (file)
@@ -1,7 +1,36 @@
-var flickrOrgSearch = function ( iObj){
+/*
+* basic flickr search uses flickr jsonp api  
+* http://www.flickr.com/services/api/
+* 
+* uses the "example api_key" 519b66e3fd8d8080e27a64fe51101e2c
+* should update with a difrent "public" key sometime soon
+http://www.flickr.com/services/rest/?method=flickr.test.echo&format=json&api_key=519b66e3fd8d8080e27a64fe51101e2c
+*
+* we look for licenses from method=flickr.photos.licenses.getInfo
+* per http://commons.wikimedia.org/wiki/Special:Upload?uselang=fromflickr
+* we are interested in:  
+       (4) Attribution License 
+       (5) Attribution-ShareAlike License, 
+       (7) No known copyright restrictions,
+       (8) United States Government Work
+*/
+
+var flickrSearch = function ( iObj){
        return this.init( iObj );
 }
-flickrOrgSearch.prototype = {
+flickrSearch.prototype = {
+       dtUrl : 'http://www.flickr.com/photos/',
+       //@@todo probably would be good to read the api-key from configuration
+       apikey : '2867787a545cc66c0bce6f2e57aca1d1', 
+       //what licence we are interested in
+       _licence_keys: '4,5,7,8',       
+       _srctypes: ['t','sq','s','m','o'],
+       licenceMap:{
+               '4' : 'http://creativecommons.org/licenses+/by/3.0/',
+               '5'     : 'http://creativecommons.org/licenses/by-sa/3.0/',
+               '7'     : 'http://www.flickr.com/commons/usage/',
+               '8' : 'http://www.usa.gov/copyright.shtml'
+       },
        init:function( iObj ){
                //init base class and inherit: 
                var baseSearch = new baseRemoteSearch( iObj );
@@ -14,9 +43,111 @@ flickrOrgSearch.prototype = {
                }
                //inherit the cp settings for 
        },
-       getSearchResults:function(){
-               //call parent: 
+       getSearchResults:function(){            
+               var _this = this;
+               js_log("flickr::getSearchResults");
+               //call parent (sets loading sate and other setup stuff) 
                this.parent_getSearchResults();
                //setup the flickr request: 
+               var reqObj = {
+                       'method':'flickr.photos.search', 
+                       'format':'json',
+                       'license':this._licence_keys,                                           
+                       'api_key':this.apikey,  
+                       'per_page': this.cp.limit,
+                       'page' : this.cp.offset,
+                       'text': $j('#rsd_q').val(),
+                       'extras' :      'license, date_upload, date_taken, owner_name, icon_server, original_format, last_update, geo, tags, machine_tags, o_dims, views, media, path_alias, url_sq, url_t, url_s, url_m, url_o'        
+               }                                                                       
+               do_api_req( {
+                       'data': reqObj,
+                       'url':this.cp.api_url,
+                       'jsonCB':'jsoncallback',
+               },      function( data ){
+                       _this.addResults( data);
+                       _this.loading = false;
+               });
+       },
+       addResults:function( data ){
+               var _this = this;                       
+               if(data.photos && data.photos.photo){                   
+                       //set result info: 
+                       this.num_results = data.photos.total;                   
+                       for(var resource_id in data.photos.photo){                              
+                               var resource = data.photos.photo[resource_id];  
+                       
+                               var rObj = {
+                                       'titleKey'       :  resource.title + '.jpg',
+                                       'resourceKey':  resource.id,
+                                       'link'           : _this.dtUrl + resource.pathalias + '/'+ resource.id,                         
+                                       'title'          : resource.title,
+                                       'thumbwidth' : resource.width_t,
+                                       'thumbheight': resource.height_t,                       
+                                       'desc'           : resource.title,                                      
+                                       //set the license: (rsd is a pointer to the parent remoteSearchDriver )          
+                                       'license'        : this.rsd.getLicenceFromUrl( _this.licenceMap[ resource.license ] ),
+                                       'pSobj'          : _this,       
+                                       //assume image/jpeg for "photos"
+                                       'mime'           : 'image/jpeg'                                 
+                               };                                              
+                               //set all the provided srcs:
+                               rObj['srcSet'] = {}; 
+                               for( var i in _this._srctypes){
+                                       var st = _this._srctypes[i];
+                                       //if resource has a url add it to the srcSet:   
+                                       if( resource['url_' + st] ){                            
+                                               rObj['srcSet'][st] = {
+                                                       'h': resource['height_' + st],
+                                                       'w': resource['width_' + st],
+                                                       'src': resource['url_' + st]
+                                               }
+                                               //set src to the largest 
+                                               rObj['src'] = resource['url_' + st];
+                                       }
+                               }       
+                                                                                                                                                                                                                                                       
+                               _this.resultsObj[ resource_id ] = rObj;
+                       }
+               }
+       },
+       //return image transform via callback 
+       getImageObj:function( rObj, size, callback){    
+               if( size.width ){
+                       var skey = this.getSrcTypeKey(rObj, size.width )        
+                       callback ({
+                               'url' : rObj.srcSet[ skey ].src,
+                               'width' : rObj.srcSet[ skey ].w,
+                               'height' : rObj.srcSet[ skey ].h
+                       });             
+               }
+       },      
+       getImageTransform:function(rObj, opt){
+               if( opt.width ){
+                       return rObj.srcSet[ this.getSrcTypeKey(rObj, opt.width) ].src;
+               }               
+       },
+       getSrcTypeKey:function(rObj, width ){
+               if( width <= 75 ){                              
+                       if( rObj.srcSet['sq'] )
+                               return 'sq';                    
+               }else if( width <= 100 ){
+                       if( rObj.srcSet['t'] )
+                               return 't';
+               }else if( width <= 240 ){
+                       if( rObj.srcSet['s'] )
+                               return 's';
+               }else if( width <= 500 ){
+                       if( rObj.srcSet['m'] )
+                               return 'm';
+               }else{
+                       if( rObj.srcSet['o'] )
+                               return 'o';
+               }
+               //original was missing return medium or small
+               if( rObj.srcSet['m'] )
+                       return 'm';
+               if( rObj.srcSet['s'] )
+                       return 's';
+               
        }
 }
\ No newline at end of file
index 489dbea..d7be4f6 100644 (file)
@@ -88,9 +88,9 @@ mediaWikiSearch.prototype = {
        getSearchResults:function(){
                //call parent: 
                this.parent_getSearchResults();
-               
+               //set local ref:
                var _this = this;
-               this.loading = true;
+                               
                js_log('f:getSearchResults for:' + $j('#rsd_q').val() );                
                //do two queries against the Image / File / MVD namespace:
                                                                                 
@@ -207,7 +207,7 @@ mediaWikiSearch.prototype = {
                                                }
                                        }                                                                               
                                }
-                                                                                                       
+                                                                               
                                //likely a audio clip if no poster and type application/ogg 
                                //@@todo we should return audio/ogg for the mime type or some other way to specify its "audio" 
                                if( ! rObj.poster && rObj.mime == 'application/ogg' ){                                  
@@ -307,36 +307,20 @@ mediaWikiSearch.prototype = {
                if(!cEdit)
                        var cEdit = _this.cEdit;                
        },
-       getEmbedHTML: function( rObj , options) {
+       getEmbedHTML: function( rObj , options) {               
                if(!options)
-                       options = {};
-               //set up the output var with the default values: 
-               var outOpt = { 'width': rObj.width, 'height': rObj.height};
-               if( options['max_height'] ){                    
-                       outOpt.height = (options.max_height > rObj.height) ? rObj.height : options.max_height;  
-                       outOpt.width = (rObj.width / rObj.height) *outOpt.height;                       
-               }                                               
-               var style_attr = 'style="width:' + outOpt.width + 'px;height:' + outOpt.height +'px"';
-               var id_attr = (options['id'])?' id = "' + options['id'] +'" ': '';
-               var cat = rObj;         
-               //return the html type: 
-               if(rObj.mime.indexOf('image')!=-1){
-                       //if crop is null do base output: 
-                       var imgHtml = '<img ' + id_attr + ' src="' + rObj.edit_url  + '"' + style_attr + ' >';
-                       if( rObj.crop == null)
-                               return imgHtml
-                       //else do crop output:  
-                               return '<div style="width:'+rObj.crop.w +'px;height: ' + rObj.crop.h +'px;overflow:hidden;position:relative">' +
-                                                       '<div style="position:relative;top:-' + rObj.crop.y +'px;left:-' + rObj.crop.x +'px">'+
-                                                               imgHtml + 
-                                                       '</div>'+
-                                               '</div>';                       
+                       options = {};   
+               this.parent_getEmbedHTML( rObj, options);
+               //check for image output:
+               if( rObj.mime.indexOf('image') != -1 ){
+                       return this.getImageEmbedHTML( rObj, options );         
                }
+               //for video and audio output:           
                var ahtml='';
-               if(rObj.mime == 'application/ogg' || rObj.mime == 'audio/ogg'){
-                       ahtml = id_attr + 
+               if( rObj.mime == 'application/ogg' || rObj.mime == 'audio/ogg' ){
+                       ahtml = options.id_attr + 
                                                ' src="' + rObj.src + '" ' +
-                                               style_attr +
+                                               options.style_attr +
                                                ' poster="'+  rObj.poster + '" '                                                                                
                        if(rObj.mime.indexOf('application/ogg')!=-1){
                                return '<video ' + ahtml + '></video>'; 
@@ -346,13 +330,17 @@ mediaWikiSearch.prototype = {
                                return '<audio ' + ahtml + '></audio>';
                        }
                }                                               
-               js_log('ERROR:unsupored mime type: ' + rObj.mime);
+               js_log( 'ERROR:unsupored mime type: ' + rObj.mime );
        },
        getInlineDescWiki:function( rObj ){                                             
                var desc = this.parent_getInlineDescWiki( rObj );
+               
+               //strip categories for inline Desc: (should strip license tags too but not as easy)
+               desc = desc.replace(/\[\[Category\:[^\]]*\]\]/, '');
+               
                //just grab the description tag for inline desc:
                var descMatch = new RegExp(/Description=(\{\{en\|)?([^|]*|)/);                  
-               var dparts = desc.match(descMatch);
+               var dparts = desc.match(descMatch);             
                                
                if( dparts && dparts.length > 1){       
                        desc = (dparts.length == 2) ? dparts[1] : dparts[2].replace('}}','');
@@ -363,9 +351,6 @@ mediaWikiSearch.prototype = {
                js_log('Error: No Description Tag, Using::' + desc );
                return desc;
        },
-       parseWikiTemplate: function( text ){
-               //@@todo parse wiki Template return object with properties and values
-       },
        //returns the inline wikitext for insertion (template based crops for now) 
        getEmbedWikiCode: function( rObj ){             
                        //set default layout to right justified
index 43862e9..221ace9 100644 (file)
@@ -26,10 +26,8 @@ metavidSearch.prototype = {
        getSearchResults:function(){
                //call parent:
                this.parent_getSearchResults();
-
-               var _this = this;
-               //start loading:
-               _this.loading= 1;
+               //set local ref:
+               var _this = this;               
                js_log('metavidSearch::getSearchResults()');
                //proccess all options
                var url = this.cp.api_url;
diff --git a/js2/mwEmbed/libAddMedia/seqRemoteSearchDriver.js b/js2/mwEmbed/libAddMedia/seqRemoteSearchDriver.js
deleted file mode 100644 (file)
index 43496f3..0000000
+++ /dev/null
@@ -1,181 +0,0 @@
-/*the sequence remote search driver
-        extends the base remote search driver with sequence specific stuff
-*/
-
-var seqRemoteSearchDriver = function(iObj){
-       return this.init( iObj )
-}
-seqRemoteSearchDriver.prototype = {
-       sequence_add_target:false,
-       init:function( this_seq ){
-               var _this = this;
-               js_log("init:seqRemoteSearchDriver");
-               //setup remote search driver with a seq parent:
-               this.pSeq = this_seq;
-               var iObj = {
-                       'target_container'      : '#cliplib_ic',
-                       'local_wiki_api_url': this_seq.getLocalApiUrl(),
-                       'instance_name'         : this_seq.instance_name + '.mySearch',
-                       'default_query'         : this.pSeq.plObj.title
-               }               
-               if(typeof this_seq.amw_conf != 'undefined')
-                       $j.extend(iObj,  this_seq.amw_conf);
-               //inherit the remoteSearchDriver properties:n
-               var tmpRSD = new remoteSearchDriver( iObj );
-               for(var i in tmpRSD){
-                       if(this[i]){
-                               this['parent_'+i] = tmpRSD[i];
-                       }else{
-                               this[i] = tmpRSD[i];
-                       }
-               }
-               //extend parent_do_refresh_timeline actions:
-               if(!this.pSeq.parent_do_refresh_timeline){
-                       this.pSeq.parent_do_refresh_timeline = this.pSeq.do_refresh_timeline;
-                       this.pSeq.do_refresh_timeline = function(){
-                               js_log("seqRemoteSearchDriver::" + _this.pSeq.disp_menu_item);
-                               //call the parent
-                               _this.pSeq.parent_do_refresh_timeline();
-                               //add our local bindings
-                               _this.addResultBindings();
-                               return true;
-                       }
-               }
-       },
-       resourceEdit:function(){
-               var _this = this;
-
-       },
-       addResultBindings:function(){
-               //set up seq:
-               var _this = this;
-               //setup parent bindings:
-               this.parent_addResultBindings();
-
-               //add an aditional click binding
-               $j('.rsd_res_item').click(function(){
-                       js_log('SeqRemoteSearch: rsd_res_item: click (remove sequence_add_target)');
-                       _this.sequence_add_target =false;
-               });
-
-               //add an additional drag binding
-               $j( '.rsd_res_item' ).draggable('destroy').draggable({
-                       helper:function(){
-                               return $j( this ).clone().appendTo('body').css({'z-index':9999}).get(0);
-                       },
-                       revert:'invalid',
-                       start:function(){
-                               js_log('start drag');
-                       }
-               });
-               $j(".mv_clip_drag").droppable( 'destroy' ).droppable({
-                       accept: '.rsd_res_item',
-                       over:function(event, ui){
-                               //js_log("over : mv_clip_drag: " + $j(this).attr('id') );
-                               $j(this).css('border-right', 'solid thick red');
-                       },
-                       out:function(event, ui){
-                               $j(this).css('border-right', 'solid thin white');
-                       },
-                       drop: function(event, ui) {
-                               $j(this).css('border-right', 'solid thin white');
-                               js_log("Droped: "+ $j(ui.draggable).attr('id') +' on ' +  $j(this).attr('id') );
-                               _this.sequence_add_target =  $j(this).attr('id');
-                               //load the orginal draged item
-                               var rObj = _this.getResourceFromId( $j(ui.draggable).attr('id') );
-                               _this.resourceEdit(rObj, ui.draggable);
-                       }
-               });
-
-       },
-       insertResource:function(rObj){
-               var _this = this;
-               js_log("SEQ insert resource after:" + _this.sequence_add_target  + ' of type: ' + rObj.mime);
-               if(_this.sequence_add_target ){
-                       var tClip = _this.pSeq.getClipFromSeqID( _this.sequence_add_target );
-                       var target_order = false;
-                       if(tClip)
-                               var target_order = tClip.order;
-               }
-               //@@todo show wating of sorts.
-
-               //get target order:
-               var cat = rObj;
-               //check for target insert path
-               this.checkImportResource( rObj, function(){
-
-                       var clipConfig = {
-                               'type'   : rObj.mime,
-                               'uri'    : _this.cFileNS + ':' + rObj.target_resource_title,
-                               'title'  : rObj.title
-                       };
-                       //set via local properites if avaliable
-                       clipConfig['src'] = (rObj.local_src) ? rObj.local_src : rObj.src;
-                       clipConfig['poster'] = ( rObj.local_poster ) ? rObj.local_poster : rObj.poster;
-
-                       if(rObj.start_time && rObj.end_time){
-                               clipConfig['dur'] = npt2seconds( rObj.end_time ) - npt2seconds( rObj.start_time );
-                       }else{
-                               //provide a default duration if none set
-                               clipConfig['dur'] = 4;
-                       }
-
-                       //create the media element (target order+1 (since we insert (after)
-                       _this.pSeq.plObj.tryAddMediaObj( clipConfig, (parseInt(target_order) + 1) );
-                       //refresh the timeline:
-                       _this.pSeq.do_refresh_timeline();
-                       js_log("run close all: ");
-                       _this.closeAll();
-               });
-       },
-       getClipEditControlActions:function(){
-               var _this = this;
-               return {
-                       'insert_seq':function(rObj){
-                               _this.insertResource( rObj )
-                       },
-                       'cancel':function(rObj){
-                               _this.cancelClipEditCB( rObj )
-                       }
-               };
-       },
-       resourceEdit:function(rObj, rsdElement){
-               var _this = this;
-               //don't resize to default (full screen behavior)
-               _this.dmodalCss = {};
-               //open up a new target_contaienr:
-               if($j('#seq_resource_import').length == 0)
-                       $j('body').append('<div id="seq_resource_import" style="position:relative"></div>');
-
-               $j('#seq_resource_import').dialog('destroy').dialog({
-                       bgiframe: true,
-                       width:750,
-                       height:480,
-                       modal: true,
-                       buttons: {
-                               "Cancel": function() {
-                                               $j(this).dialog("close");
-                                       }
-                               }
-               });
-               _this.target_container = '#seq_resource_import';
-               //do parent resource edit (with updated target)
-               this.parent_resourceEdit(rObj, rsdElement);
-       },
-       closeAll:function(){
-               js_log( 'should close: seq_resource_import');
-               $j('#seq_resource_import').dialog('close').dialog('destroy').remove();
-               this.parent_closeAll();
-       },
-       getEditToken:function(callback){
-               if(this.pSeq.sequenceEditToken){
-                       callback( this.pSeq.sequenceEditToken )
-               }else{
-                       this.parent_getEditToken(callback);
-               }
-       },
-       cancelClipEditCB:function(){
-               js_log('seqRSD:cancelClipEditCB');
-               $j('#seq_resource_import').dialog('close').dialog('destroy').remove();
-       }
-};
index 7df81e6..4784ff9 100644 (file)
@@ -37,13 +37,12 @@ var nativeEmbed = {
                        
                //continue with the other attr:                                         
                eb+= 'oncanplaythrough="$j(\'#'+this.id+'\').get(0).oncanplaythrough();return false;" ' +
-                          'onloadedmetadata="$j(\'#'+this.id+'\').get(0).onloadedmetadata();return false;" ' + 
-                          'loadedmetadata="$j(\'#'+this.id+'\').get(0).onloadedmetadata();return false;" ' +
-                          'onprogress="$j(\'#'+this.id+'\').get(0).onprogress( event );return false;" '+
-                          'onended="$j(\'#'+this.id+'\').get(0).onended();return false;" '+
-                          'onseeking="$j(\'#'+this.id+'\').get(0).onseeking();" ' +
-                          'onseeked="$j(\'#'+this.id+'\').get(0).onseeked();" ' +
-                          '>' +                           
+                         'onloadedmetadata="$j(\'#'+this.id+'\').get(0).onloadedmetadata();return false;" ' + 
+                         'loadedmetadata="$j(\'#'+this.id+'\').get(0).onloadedmetadata();return false;" ' +
+                         'onprogress="$j(\'#'+this.id+'\').get(0).onprogress( event );return false;" '+
+                         'onended="$j(\'#'+this.id+'\').get(0).onended();return false;" '+
+                         'onseeking="$j(\'#'+this.id+'\').get(0).onseeking();" ' +
+                         'onseeked="$j(\'#'+this.id+'\').get(0).onseeked();" >' +                         
                        '</video>';
                return eb;
        },
diff --git a/js2/mwEmbed/libMwApi/NestedCallbackIframe.html b/js2/mwEmbed/libMwApi/NestedCallbackIframe.html
new file mode 100644 (file)
index 0000000..c896446
--- /dev/null
@@ -0,0 +1,16 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Simple nested iframe callback page</title>
+<script type="text/javascript">
+window.onload = function (){
+       //call the nested callback in top most frame:
+       top.$mw.proxy.nested( window.location.href.split("#")[1] || false );            
+}
+</script>
+</head>
+<body>
+Nested Iframe callback
+</body>
+</html>
\ No newline at end of file
diff --git a/js2/mwEmbed/libMwApi/json2.js b/js2/mwEmbed/libMwApi/json2.js
new file mode 100644 (file)
index 0000000..c422a6e
--- /dev/null
@@ -0,0 +1,479 @@
+/*
+    http://www.JSON.org/json2.js
+    2009-09-29
+
+    Public Domain.
+
+    NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+    See http://www.JSON.org/js.html
+
+    This file creates a global JSON object containing two methods: stringify
+    and parse.
+
+        JSON.stringify(value, replacer, space)
+            value       any JavaScript value, usually an object or array.
+
+            replacer    an optional parameter that determines how object
+                        values are stringified for objects. It can be a
+                        function or an array of strings.
+
+            space       an optional parameter that specifies the indentation
+                        of nested structures. If it is omitted, the text will
+                        be packed without extra whitespace. If it is a number,
+                        it will specify the number of spaces to indent at each
+                        level. If it is a string (such as '\t' or '&nbsp;'),
+                        it contains the characters used to indent at each level.
+
+            This method produces a JSON text from a JavaScript value.
+
+            When an object value is found, if the object contains a toJSON
+            method, its toJSON method will be called and the result will be
+            stringified. A toJSON method does not serialize: it returns the
+            value represented by the name/value pair that should be serialized,
+            or undefined if nothing should be serialized. The toJSON method
+            will be passed the key associated with the value, and this will be
+            bound to the value
+
+            For example, this would serialize Dates as ISO strings.
+
+                Date.prototype.toJSON = function (key) {
+                    function f(n) {
+                        // Format integers to have at least two digits.
+                        return n < 10 ? '0' + n : n;
+                    }
+
+                    return this.getUTCFullYear()   + '-' +
+                         f(this.getUTCMonth() + 1) + '-' +
+                         f(this.getUTCDate())      + 'T' +
+                         f(this.getUTCHours())     + ':' +
+                         f(this.getUTCMinutes())   + ':' +
+                         f(this.getUTCSeconds())   + 'Z';
+                };
+
+            You can provide an optional replacer method. It will be passed the
+            key and value of each member, with this bound to the containing
+            object. The value that is returned from your method will be
+            serialized. If your method returns undefined, then the member will
+            be excluded from the serialization.
+
+            If the replacer parameter is an array of strings, then it will be
+            used to select the members to be serialized. It filters the results
+            such that only members with keys listed in the replacer array are
+            stringified.
+
+            Values that do not have JSON representations, such as undefined or
+            functions, will not be serialized. Such values in objects will be
+            dropped; in arrays they will be replaced with null. You can use
+            a replacer function to replace those with JSON values.
+            JSON.stringify(undefined) returns undefined.
+
+            The optional space parameter produces a stringification of the
+            value that is filled with line breaks and indentation to make it
+            easier to read.
+
+            If the space parameter is a non-empty string, then that string will
+            be used for indentation. If the space parameter is a number, then
+            the indentation will be that many spaces.
+
+            Example:
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}]);
+            // text is '["e",{"pluribus":"unum"}]'
+
+
+            text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+            // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+            text = JSON.stringify([new Date()], function (key, value) {
+                return this[key] instanceof Date ?
+                    'Date(' + this[key] + ')' : value;
+            });
+            // text is '["Date(---current time---)"]'
+
+
+        JSON.parse(text, reviver)
+            This method parses a JSON text to produce an object or array.
+            It can throw a SyntaxError exception.
+
+            The optional reviver parameter is a function that can filter and
+            transform the results. It receives each of the keys and values,
+            and its return value is used instead of the original value.
+            If it returns what it received, then the structure is not modified.
+            If it returns undefined then the member is deleted.
+
+            Example:
+
+            // Parse the text. Values that look like ISO date strings will
+            // be converted to Date objects.
+
+            myData = JSON.parse(text, function (key, value) {
+                var a;
+                if (typeof value === 'string') {
+                    a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+                    if (a) {
+                        return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+                            +a[5], +a[6]));
+                    }
+                }
+                return value;
+            });
+
+            myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+                var d;
+                if (typeof value === 'string' &&
+                        value.slice(0, 5) === 'Date(' &&
+                        value.slice(-1) === ')') {
+                    d = new Date(value.slice(5, -1));
+                    if (d) {
+                        return d;
+                    }
+                }
+                return value;
+            });
+
+
+    This is a reference implementation. You are free to copy, modify, or
+    redistribute.
+
+    This code should be minified before deployment.
+    See http://javascript.crockford.com/jsmin.html
+
+    USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+    NOT CONTROL.
+*/
+
+/*jslint evil: true, strict: false */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+    call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+    getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+    lastIndex, length, parse, prototype, push, replace, slice, stringify,
+    test, toJSON, toString, valueOf
+*/
+
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+if (!this.JSON) {
+    this.JSON = {};
+}
+
+(function () {
+
+    function f(n) {
+        // Format integers to have at least two digits.
+        return n < 10 ? '0' + n : n;
+    }
+
+    if (typeof Date.prototype.toJSON !== 'function') {
+
+        Date.prototype.toJSON = function (key) {
+
+            return isFinite(this.valueOf()) ?
+                   this.getUTCFullYear()   + '-' +
+                 f(this.getUTCMonth() + 1) + '-' +
+                 f(this.getUTCDate())      + 'T' +
+                 f(this.getUTCHours())     + ':' +
+                 f(this.getUTCMinutes())   + ':' +
+                 f(this.getUTCSeconds())   + 'Z' : null;
+        };
+
+        String.prototype.toJSON =
+        Number.prototype.toJSON =
+        Boolean.prototype.toJSON = function (key) {
+            return this.valueOf();
+        };
+    }
+
+    var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+        gap,
+        indent,
+        meta = {    // table of character substitutions
+            '\b': '\\b',
+            '\t': '\\t',
+            '\n': '\\n',
+            '\f': '\\f',
+            '\r': '\\r',
+            '"' : '\\"',
+            '\\': '\\\\'
+        },
+        rep;
+
+
+    function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+        escapable.lastIndex = 0;
+        return escapable.test(string) ?
+            '"' + string.replace(escapable, function (a) {
+                var c = meta[a];
+                return typeof c === 'string' ? c :
+                    '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+            }) + '"' :
+            '"' + string + '"';
+    }
+
+
+    function str(key, holder) {
+
+// Produce a string from holder[key].
+
+        var i,          // The loop counter.
+            k,          // The member key.
+            v,          // The member value.
+            length,
+            mind = gap,
+            partial,
+            value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+        if (value && typeof value === 'object' &&
+                typeof value.toJSON === 'function') {
+            value = value.toJSON(key);
+        }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+        if (typeof rep === 'function') {
+            value = rep.call(holder, key, value);
+        }
+
+// What happens next depends on the value's type.
+
+        switch (typeof value) {
+        case 'string':
+            return quote(value);
+
+        case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+            return isFinite(value) ? String(value) : 'null';
+
+        case 'boolean':
+        case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+            return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+        case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+            if (!value) {
+                return 'null';
+            }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+            gap += indent;
+            partial = [];
+
+// Is the value an array?
+
+            if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+                length = value.length;
+                for (i = 0; i < length; i += 1) {
+                    partial[i] = str(i, value) || 'null';
+                }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+                v = partial.length === 0 ? '[]' :
+                    gap ? '[\n' + gap +
+                            partial.join(',\n' + gap) + '\n' +
+                                mind + ']' :
+                          '[' + partial.join(',') + ']';
+                gap = mind;
+                return v;
+            }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+            if (rep && typeof rep === 'object') {
+                length = rep.length;
+                for (i = 0; i < length; i += 1) {
+                    k = rep[i];
+                    if (typeof k === 'string') {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+                for (k in value) {
+                    if (Object.hasOwnProperty.call(value, k)) {
+                        v = str(k, value);
+                        if (v) {
+                            partial.push(quote(k) + (gap ? ': ' : ':') + v);
+                        }
+                    }
+                }
+            }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+            v = partial.length === 0 ? '{}' :
+                gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+                        mind + '}' : '{' + partial.join(',') + '}';
+            gap = mind;
+            return v;
+        }
+    }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+    if (typeof JSON.stringify !== 'function') {
+        JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+            var i;
+            gap = '';
+            indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+            if (typeof space === 'number') {
+                for (i = 0; i < space; i += 1) {
+                    indent += ' ';
+                }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+            } else if (typeof space === 'string') {
+                indent = space;
+            }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+            rep = replacer;
+            if (replacer && typeof replacer !== 'function' &&
+                    (typeof replacer !== 'object' ||
+                     typeof replacer.length !== 'number')) {
+                throw new Error('JSON.stringify');
+            }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+            return str('', {'': value});
+        };
+    }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+    if (typeof JSON.parse !== 'function') {
+        JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+            var j;
+
+            function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+                var k, v, value = holder[key];
+                if (value && typeof value === 'object') {
+                    for (k in value) {
+                        if (Object.hasOwnProperty.call(value, k)) {
+                            v = walk(value, k);
+                            if (v !== undefined) {
+                                value[k] = v;
+                            } else {
+                                delete value[k];
+                            }
+                        }
+                    }
+                }
+                return reviver.call(holder, key, value);
+            }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+            cx.lastIndex = 0;
+            if (cx.test(text)) {
+                text = text.replace(cx, function (a) {
+                    return '\\u' +
+                        ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                });
+            }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+            if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+                j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+                return typeof reviver === 'function' ?
+                    walk({'': j}, '') : j;
+            }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+            throw new SyntaxError('JSON.parse');
+        };
+    }
+}());
diff --git a/js2/mwEmbed/libMwApi/mw.proxy.js b/js2/mwEmbed/libMwApi/mw.proxy.js
new file mode 100644 (file)
index 0000000..86f673e
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+* 
+* Api proxy system
+*
+* Built to support cross domain uploading, and api actions for a approved set of domains.
+* mwProxy enables a system for fluid contributions across wikis domains for which your logged in.
+*
+* The framework support a request approval system for per-user domain approval
+* and a central blacklisting of domains controlled by site or system administrators. 
+*
+*  Flow outline below:  
+* 
+* Domain A (lets say en.wiki)  
+*      invokes add-media-wizard and wants to upload to domain B ( commons.wiki )
+* 
+*      Domain A loads iframe to domain B ? with request param to to insert from Domain A
+*              Domain B checks list of approved domains for (Domain A) & checks the user is logged in ( and if the same account name ) 
+*                      if user is not logged in 
+*                              a _link_ to Domain B to new window login page is given
+*                      if user has not approved domain and (Domain A) is not pre-approved 
+*                              a new page link is generated with a approve domain request
+*                                      if user approves domain it goes into their User:{username}/apiProxyDomains.js config
+*              If Domain A is approved we then: 
+*                      loads a "push" and "pull" iframe back to Domain A 
+                               (Domain B can change the #hash values of these children thereby proxy the data)  
+*      Domain A now gets the iframe "loaded" callback a does a initial echo to confirm cross domain proxy
+*              echo sends "echo" to push and (Domain A) js passes the echo onto the "pull"
+*      Domain A now sends api requests to the iframe "push" child and gets results from the iframe "pull"
+*              api actions happen with status updates and everything and we can reuse existing api interface code  
+* 
+* if the browser supports it we can pass msgs with the postMessage  API
+* http://ejohn.org/blog/cross-window-messaging/
+*
+* @@todo it would be nice if this supported multiple proxy targets (ie to a bright widgets future) 
+*
+*/
+
+loadGM({
+       "mwe-setting-up-proxy": "Setting up proxy" 
+});
+
+(function( $ ) {
+       /**
+        * Base API Proxy object
+        *       
+        */
+       $.proxy = {};
+       
+       /**
+        * The clientApiProxy handles a request to external server
+        * 
+        * This is (Domain A) in the above described setup
+        */
+       $.proxy.client = function( pConf, callback ){
+               var _this = this;
+               //do setup: 
+               if( pConf.server_frame )                
+                       $.proxy.server_frame = pConf.server_frame;
+               
+               if( pConf.client_frame_path )
+                       $.proxy.client_frame_path = pConf.client_frame_path;
+               
+               //setup a dialog to manage proxy setup:
+               $j.addLoaderDialog( gM('mwe-setting-up-proxy') );
+                       
+               if( parseUri( $.proxy.server_frame).host ==  parseUri( document.URL ).host ){
+                       js_log("Error: why are you trying to proxy yourself? " );
+                       return false;                           
+               }                                               
+               //add an iframe to domain B with request for proxy just do the setup
+               $.proxy.doFrameProxy( { 'init' : 'echo' } );
+                       
+               //if we have a setup callback 
+               $.proxy.callback =      callback;
+       }
+       /* setup a iframe request hash */
+       $.proxy.doFrameProxy = function( reqObj ){              
+               var hashPack = {
+                       'cd': parseUri( document.URL ).host,
+                       'cfp': $.proxy.client_frame_path,
+                       'req': reqObj                   
+               }
+               js_log( "Do frame proxy request on src: \n" + $.proxy.server_frame + "\n" + 
+                                       JSON.stringify(  reqObj ) );
+               //we can't update src's so we have to remove and add all the time :(
+               //@@todo we should support frame msg system 
+               $j('#frame_proxy').remove();
+               $j('body').append('<iframe id="frame_proxy" name="frame_proxy" ' +
+                               'src="' + $.proxy.server_frame +
+                                '#' + escape( JSON.stringify( hashPack ) ) + 
+                                '"></iframe>' );
+       }
+       
+       /* the do_api_request with callback: */
+       $.proxy.doRequest = function( reqObj, callback){
+               js_log("doRequest:: " + JSON.stringify( reqObj ) );             
+               //setup the callback:
+               $.proxy.callback = callback;
+               //do the proxy req:
+               $.proxy.doFrameProxy( reqObj );
+       }
+       /**
+        * The nested iframe action that passes its msg back up to the top instance      
+        */
+       $.proxy.nested = function( hashResult ){
+               js_log( 'got $.proxy.nested callback!! :: ' + hashResult );
+               //try to parse the hash result: 
+               try{
+                       var rObj = JSON.parse( unescape( hashResult ) );
+               }catch (e) {
+                       js_log("Error could not parse hashResult");
+               }               
+               //hide the loader if the initial state = ready msg is fired: 
+               if( rObj && rObj.state == 'ready')
+                       $j.closeLoaderDialog();
+               //if all good pass it to the callback:
+               $.proxy.callback( rObj ); 
+       }
+       /**
+        * The serverApiProxy handles the actual proxy 
+        * and child frames pointing to the parent "blank" frames
+        * 
+        * This is (Domain B) in the above described setup
+        */      
+       $.proxy.server = function( pConf, callback){                                                            
+               /* clear the body of any html */                                                
+               $j('body').html( 'proxy setup' );                                       
+               
+               //read the anchor action from the requesting url
+               var jmsg = unescape( parseUri( document.URL ).anchor );
+               try{
+                       var aObj = JSON.parse( jmsg );
+               }catch ( e ){
+                       js_log("ProxyServer:: could not parse anchor");
+               }
+               if( !aObj.cd ){
+                       js_log("Error: no client domain provided ");
+                       return false;
+               }       
+               
+               js_log("Setup server on: "  + parseUri( document.URL ).host +
+                       ' client from: ' + aObj.cd + 
+                       ' to nested target: ' + aObj.cfp );
+               
+               // make sure we are logged in 
+               // (its a normal mediaWiki page so all site vars should be defined)             
+               if( !wgUserName ){
+                       js_log('error Not logged in');
+                       return false;
+               }
+                       
+               var domain =  parseUri( document.URL ).host;
+               var nested_frame_src = 'http://' + aObj.cd + aObj.cfp;
+               //check the master whitelist
+               for(var i in pConf.master_whitelist){
+                       if( domain ==  pConf.master_whitelist[ i ] ){
+                               //do the request:                       
+                               return doNestedProxy( aObj.req );
+                       }
+               }               
+               //check master blacklist
+               for(var i in pConf.master_blacklist ){
+                       if( domain == pConf.master_blacklist ){
+                               js_log('domain: ' + domain + ' is blacklisted');
+                               return false;
+                       }
+               }
+               //@@todo grab the users whitelist for our current domain                                
+               /*var local_api = wgScriptPath + '/index' + wgScriptExtension + '?title=' +
+                               'User:' + wgUserName + '/apiProxyDomainList.js' +
+                               '&action=raw&smaxage=0&gen=js';
+               $j.get( local_api, function( data ){
+                       debugger;
+               });*/
+               
+               //if still not found: 
+               js_log("domain " + domain + " not approved");           
+               
+               function doNestedProxy( reqObj ){               
+                       js_log("doNestedProxy to: " + nested_frame_src);
+                       var outputhash = escape( JSON.stringify( reqObj ) );
+                       //check if its just a "echo" request (no need to hit the api)                   
+                       if( reqObj.init && reqObj.init == 'echo'){
+                               doNestedFrame( {'state': 'ready', "echo": true } );
+                       }else{                  
+                               //add some api stuff: 
+                               reqObj['format'] = 'json';                                                                                              
+                               //process the api request
+                               $j.get(wgScriptPath + '/api' + wgScriptExtension,
+                                       reqObj,
+                                       function( data ){                                       
+                                               js_log("Proxy GOT Res: " +  data );
+                                               //put it into the nested frame hash string: 
+                                               doNestedFrame( JSON.parse( data ) );
+                                       }
+                               );                              
+                       }                                       
+               }
+               //add the doNestedFrame iframe: 
+               function doNestedFrame( resultObj ){                    
+                       $j('#nested_push').remove();
+                       //setup the nested proxy that points back to top domain:                        
+                       $j('body').append( '<iframe id="nested_push" name="nested_push" ' +
+                               'src="'+ nested_frame_src +
+                               '#' + escape( JSON.stringify( resultObj ) ) +                                   
+                               '"></iframe>' );
+               }       
+       }
+       
+})(window.$mw);
diff --git a/js2/mwEmbed/libMwApi/mwProxy.js b/js2/mwEmbed/libMwApi/mwProxy.js
new file mode 100644 (file)
index 0000000..8a47921
--- /dev/null
@@ -0,0 +1,17 @@
+
+var mwApiClientProxy = function(iObj){
+       return this.init( iObj );
+}
+mwApiClientProxy.prototype = {
+       init:function( iObj ){
+                       
+       },
+       //Gets the apiResult callback
+       mwApiProxy:resultCb( apiResult ){
+               
+       }
+}
+
+var mwApiServerProxy = function(iObj){
+       return this.init(
+}
\ No newline at end of file
index 86bd200..57aaf06 100644 (file)
@@ -91,7 +91,7 @@ if( !mv_embed_path ) {
        var mv_embed_path = getMvEmbedPath();
 }
 /**
-* wrap the global $mw object here:
+* The global $mw object:
 *
 * Any global functions/classes that are not jQuery plugins should make
 * there way into the $mw namespace
@@ -382,8 +382,9 @@ if( !mv_embed_path ) {
                //@@todo we need a formatNum and we need to request some special packaged info to deal with that case.
                return gM( msg , size );
        };
-
-
+       
+       
+       
        /**
        * MediaWiki wikitext "Parser"
        *
@@ -429,36 +430,15 @@ if( !mv_embed_path ) {
                                this.pOut = '';
                        },
                        parse : function(){
-                               this.pObj = {};
-                               this.pObj.tmpl = new Array();
-
-                               //refrences for swap key
-                               this.pObj.tmpl_text = new Array();
-                               this.pObj.tmpl_key = new Array();
-                               this.pObj.tmpl_ns = '' ; // wikiText with place-holder
-
-                               //get templates losly based on Magnus_Manske/tmpl.js code:
-                               var tcnt = 0 ;
-                               var ts = '' ;
-                               var curt = 0 ;
-                               var schar = 0;
-
-
-                               //build out nested template holders:
-                               var depth = 0;
-                               var tKey = 0;
-                               var ns = '';
-
                                /*
-                                * quickly recursive / parse out templates with top down recurse decent
+                                * quickly recursive / parse out templates:
                                 */
 
                                // ~ probably a better algorithm out there / should mirror php parser flow ~
                                // ... but I am having fun with recursion so here it is...
-                               function rdpp ( txt ){
+                               // or at least mirror: http://www.mediawiki.org/wiki/Extension:Page_Object_Model
+                               function rdpp ( txt , cn){
                                        var node = {};
-                                       //if we should output node text
-                                       var ont = true;
                                        //inspect each char
                                        for(var a=0; a < txt.length; a++){
                                                if( txt[a] == '{' && txt[a+1] == '{' ){
@@ -467,21 +447,20 @@ if( !mv_embed_path ) {
                                                        if(!node['c'])
                                                                node['c'] = new Array();
 
-                                                       node['c'].push( rdpp( txt.substr( a ) ) );
-                                                       ont=true;
+                                                       node['c'].push( rdpp( txt.substr( a ), true ) );                                                                                                                                                                                                                                                                                                                                        
                                                }else if( txt[a] == '}' && txt[a+1] == '}'){
                                                        if( !node['p'] ){
                                                                return node;
                                                        }
                                                        node = node['p'];
-                                                       ont=false;
                                                        a=a+2;
                                                }
                                                if(!node['t'])
                                                        node['t']='';
-
+                                               
                                                if( txt[a] )
                                                                node['t']+=txt[a];
+                                                               
                                        }
                                        return node;
                                }
@@ -503,8 +482,8 @@ if( !mv_embed_path ) {
                                                tObj["arg"] = tname.split(':').pop();
                                        }
 
-                                       js_log("TNAME::" + tObj["arg"] + ' from:: ' + ts);
-
+                                       js_log("TNAME::" + tObj["name"] + ' from:: ' + ts);     
+                                       
                                        var pSet = ts.split('\|');
                                        pSet.splice(0,1);
                                        if( pSet.length ){
@@ -566,25 +545,57 @@ if( !mv_embed_path ) {
                                                return getMagicTxtFromTempNode( node );
                                        }
                                }
-                               //get text node system:
-                               var node = rdpp ( this.wikiText );
-                               //debugger;
-                               //parse out stuff:
-
-                               this.pOut = recurse_magic_swap( node);
+                               //parse out the template node structure:
+                               this.pNode = rdpp ( this.wikiText );
+                               //strip out the parent from the root    
+                               this.pNode['p'] = null;
+                               
+                               //do the recusrive magic swap text:
+                               this.pOut = recurse_magic_swap( this.pNode );
 
                        },
+                       
+                       /*
+                        * parsed template api ~losely based off of ~POM~
+                        * http://www.mediawiki.org/wiki/Extension:Page_Object_Model
+                        */
+                       
+                       /**
+                        * templates
+                        * 
+                        * gets a requested template from the wikitext (if available)
+                        *  
+                        */
+                       templates: function( tname ){
+                               this.parse();
+                               var tmplSet = new Array();
+                               function getMatchingTmpl( node ){
+                                       if( node['c'] ){
+                                               for(var i in node['c']){
+                                                       getMatchingTmpl( node['c'] );
+                                               }
+                                       }                                       
+                                       if( tname && node.tObj){
+                                               if( node.tObj['name'] == tname )
+                                                       tmplSet.push( node.tObj );
+                                       }else if( node.tObj ){
+                                               tmplSet.push( node.tObj );
+                                       }
+                               }                               
+                               getMatchingTmpl( this.pNode );                          
+                               return tmplSet;                         
+                       },
                        /**
                         * Returns the transformed wikitext
-                        *
-                        * Build output from swapable index
-                        *              (all transforms must be expanded in parse stage and linerarly rebuilt)
-                        * Alternativly we could build output using a placeholder & replace system
+                        * 
+                        * Build output from swapable index 
+                        *              (all transforms must be expanded in parse stage and linerarly rebuilt)  
+                        * Alternativly we could build output using a placeholder & replace system 
                         *              (this lets us be slightly more slopty with ordering and indexes, but probably slower)
-                        *
-                        * Ideal: we build a 'wiki DOM'
+                        * 
+                        * Ideal: we build a 'wiki DOM' 
                         *              When editing you update the data structure directly
-                        *              Then in output time you just go DOM->html-ish output without re-parsing anything
+                        *              Then in output time you just go DOM->html-ish output without re-parsing anything                           
                         */
                        getHTML : function(){
                                //wikiText updates should invalidate pOut
@@ -597,8 +608,9 @@ if( !mv_embed_path ) {
                //return the parserObj
                return new parseObj( wikiText, opt) ;
        }
-
+       
 })(window.$mw);
+
 //setup legacy global shortcuts:
 var loadGM = $mw.lang.loadGM;
 var loadRS = $mw.lang.loadRS;
@@ -618,7 +630,8 @@ $mw.lang.loadGM({
        "mwe-size-kilobytes" : "$1 K",
        "mwe-size-bytes" : "$1 B",
        "mwe-error_load_lib" : "Error: JavaScript $1 was not retrievable or does not define $2",
-       "mwe-loading-add-media-wiz": "Loading add media wizard"
+       "mwe-loading-add-media-wiz": "Loading add media wizard",
+       "mwe-apiproxy-setup" : " Setting up API proxy"
 });
 
 
@@ -666,10 +679,6 @@ function lcCssPath( cssSet ) {
  * This is used by the script loader to auto-load classes (so we only define
  * this once for PHP & JavaScript)
  *
- * This is more verbose than the earlier version that compressed paths
- * but it's all good, gzipping helps compress path strings
- * grouped by directory.
- *
  * Right now the PHP AutoLoader only reads this mv_embed.js file.
  * In the future we could have multiple lcPath calls that PHP reads
  * (if our autoloading class list becomes too long) just have to add those
@@ -685,13 +694,15 @@ lcPaths({
        "$j.ui"                         : "jquery/jquery.ui/ui/ui.core.js",
        "$j.fn.ColorPicker"     : "libClipEdit/colorpicker/js/colorpicker.js",
        "$j.Jcrop"                      : "libClipEdit/Jcrop/js/jquery.Jcrop.js",
-       "$j.fn.simpleUploadForm": "libAddMedia/simpleUploadForm.js",
-
+       "$j.fn.simpleUploadForm" : "libAddMedia/simpleUploadForm.js",
+       
+       "$mw.proxy"             : "libMwApi/mw.proxy.js", 
+       
        "ctrlBuilder"   : "skins/ctrlBuilder.js",
        "kskinConfig"   : "skins/kskin/kskin.js",
        "mvpcfConfig"   : "skins/mvpcf/mvpcf.js",
 
-       "$j.secureEvalJSON"     : "jquery/plugins/jquery.secureEvalJSON.js",
+       "JSON"                          : "libMwApi/json2.js",
        "$j.cookie"                     : "jquery/plugins/jquery.cookie.js",
        "$j.contextMenu"        : "jquery/plugins/jquery.contextMenu.js",
        "$j.fn.suggestions"     : "jquery/plugins/jquery.suggestions.js",
@@ -725,12 +736,13 @@ lcPaths({
        "mvAdvFirefogg"                 : "libAddMedia/mvAdvFirefogg.js",
        "mvBaseUploadInterface" : "libAddMedia/mvBaseUploadInterface.js",
        "remoteSearchDriver"    : "libAddMedia/remoteSearchDriver.js",
-       "seqRemoteSearchDriver" : "libAddMedia/seqRemoteSearchDriver.js",
+       "seqRemoteSearchDriver" : "libSequencer/seqRemoteSearchDriver.js",
 
        "baseRemoteSearch"              : "libAddMedia/searchLibs/baseRemoteSearch.js",
        "mediaWikiSearch"               : "libAddMedia/searchLibs/mediaWikiSearch.js",
        "metavidSearch"                 : "libAddMedia/searchLibs/metavidSearch.js",
        "archiveOrgSearch"              : "libAddMedia/searchLibs/archiveOrgSearch.js",
+       "flickrSearch"                  : "libAddMedia/searchLibs/flickrSearch.js",
        "baseRemoteSearch"              : "libAddMedia/searchLibs/baseRemoteSearch.js",
 
        "mvClipEdit"                    : "libClipEdit/mvClipEdit.js",
@@ -778,10 +790,6 @@ function mv_set_loading(target, load_id){
   * mvJsLoader class handles initialization and js file loads
   */
 
-// Shortcut
-function mwLoad( loadSet, callback ) {
-       mvJsLoader.doLoad( loadSet, callback );
-}
 var mvJsLoader = {
        libreq : {},
        libs : {},
@@ -1066,6 +1074,13 @@ var mvJsLoader = {
        }
 }
 
+// Shortcut ( @@todo consolidate shortcuts & re-factor mvJsLoader )
+function mwLoad( loadSet, callback ) {
+       mvJsLoader.doLoad( loadSet, callback );
+}
+//$mw.shortcut
+$mw.load = mwLoad;
+
 // Load an external JS file. Similar to jquery .require plugin,
 // but checks for object availability rather than load state.
 
@@ -1172,15 +1187,30 @@ function mv_remove_modal( speed ) {
 /*
  * Store all the mwEmbed jQuery-specific bindings
  * (set up after jQuery is available).
- * This lets you call rewrites in a jQuery way
  *
- * @@ eventually we should refactor mwCode over to jQuery style plugins
- *       and mv_embed.js will just handle dependency mapping and loading.
+ * These functions are genneraly are loaders that do the dynamic mapping of
+ * dependencies for a given compoent
+ * 
  *
  */
 function mv_jqueryBindings() {
        js_log( 'mv_jqueryBindings' );
        (function( $ ) {
+               /*
+                * apiProxy Loader loader:
+                * 
+                * @param mode is either 'server' or 'client'
+                */                             
+               $.apiProxy = function( mode, pConf, callback ){
+                       js_log('do apiProxy setup');
+                       $.addLoaderDialog( gM('mwe-apiproxy-setup') );
+                       mvJsLoader.doLoad( [
+                               '$mw.proxy',
+                               'JSON'
+                       ], function(){                          
+                               $mw.proxy[mode]( pConf, callback );
+                       });     
+               }
                //non selector based add-media-wizard direct invocation with loader
                $.addMediaWiz = function( iObj, callback ){                     
                        js_log(".addMediaWiz call");
@@ -1253,7 +1283,7 @@ function mv_jqueryBindings() {
                                                'mvPlayList',
                                                '$j.ui',
                                                '$j.contextMenu',
-                                               '$j.secureEvalJSON',
+                                               'JSON',
                                                'mvSequencer'
                                        ],
                                        [
@@ -1421,14 +1451,15 @@ function mv_jqueryBindings() {
                *
                * @param msg text text of the loader msg
                */
-               $.addLoaderDialog = function( msg_txt ){
-                       if( $('#mwe_tmp_loader').length != 0 )
-                               $('#mwe_tmp_loader').remove();
-                       
+               $.addLoaderDialog = function( msg_txt ){                        
+                       $.addDialog( msg_txt, msg_txt + '<br>' + mv_get_loading_img() );                
+               }
+               
+               $.addDialog = function ( title, msg_txt, btn ){
+                       $('#mwe_tmp_loader').remove();
                        //append the style free loader ontop: 
-                       $('body').append('<div id="mwe_tmp_loader" title="' + msg_txt + '" >' +
-                                       msg_txt + '<br>' +
-                                       mv_get_loading_img() +
+                       $('body').append('<div id="mwe_tmp_loader" title="' + title + '" >' +
+                                       msg_txt +
                        '</div>');
                        //turn the loader into a real dialog loader: 
                        mvJsLoader.doLoadDepMode([
@@ -1444,14 +1475,21 @@ function mv_jqueryBindings() {
                                        draggable: false,
                                        resizable: false,
                                        height: 140,
-                                       modal: true
+                                       modal: true,
+                                       buttons: btn
                                });
                        });
                }
-               $.closeLoaderDialog = function(){
+               $.closeLoaderDialog = function(){                       
                        $('#mwe_tmp_loader').dialog('close');
                }
-
+       
+               $.mwProxy = function( apiConf ){
+                       mvJsLoader.doLoad( ['$mw.apiProxy'], 
+                       function(){
+                               $mw.apiProxy( apiConf );
+                       });
+               }
        })(jQuery);
 }
 /*
@@ -1876,7 +1914,11 @@ if ( typeof DOMParser == "undefined" ) {
 * Utility functions
 */
 function js_log( string ) {
-       if( window.console ) {
+       ///add any prepend debug strings if nessesary
+       if( mwConfig['debug_pre'] )
+               string = mwConfig['debug_pre']+ string;
+                       
+       if( window.console ) {                          
                window.console.log( string );
        } else {
                /*
index ffbcd35..5eef782 100644 (file)
@@ -104,6 +104,7 @@ $messages['en'] = array(
        'mwe-size-bytes' => '$1 B',
        'mwe-error_load_lib' => 'Error: JavaScript $1 was not retrievable or does not define $2',
        'mwe-loading-add-media-wiz' => "Loading add media wizard",
+       'mwe-apiproxy-setup' => " Setting up API proxy",
 
        /*
         * js file: /libAddMedia/mvFirefogg.js
diff --git a/js2/mwEmbed/tests/testApiProxy.html b/js2/mwEmbed/tests/testApiProxy.html
new file mode 100644 (file)
index 0000000..f9bf577
--- /dev/null
@@ -0,0 +1,76 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+<title>Api Proxy Test</title>
+<script type="text/javascript" src="../mv_embed.js"></script>
+
+<script type="text/javascript" >
+//HARD coded local test: 
+var remote_wiki_host = 'http://127.1.1.100';
+var remote_script_path = '/wiki_trunk';
+
+js2AddOnloadHook( function(){  
+       $j('#hostName').text( remote_wiki_host );
+       //run the api-proxy setup:
+       $j.apiProxy(
+               'client', 
+               {
+                       'server_frame': remote_wiki_host +  remote_script_path + '/index.php/MediaWiki:ApiProxy',
+                       'client_frame_path'     : '/wiki_trunk/js2/mwEmbed/libMwApi/NestedCallbackIframe.html',
+               },
+               function(){
+                       //callback function here: 
+                       $j('#setupDone').show('slow');
+                       $j('#doAppendCat').click( doCatAppend );                
+               }
+       );                              
+});
+function doCatAppend(){
+       js_log('append cat to User page');
+       //first get our user name:
+       var rObj = {
+               'action':'query',
+               'meta':'userinfo'
+       }
+       //we use normal do_api_req with keywork 'proxy' for the url 
+       $mw.proxy.doRequest( rObj,
+               function(data){                                 
+                       //now we get the data back for that domain
+                       if( !data.query || !data.query.userinfo ){
+                               js_log("Error no query.userinfo ");
+                               return false;
+                       }                       
+                       if( data.query.userinfo.id == 0 ){                                                      
+                               var btn = {};
+                               btn['try again'] = function(){
+                                       doCatAppend();
+                               }
+                               btn['cancel'] = function(){
+                                       $j(this).close();
+                               }
+                               $j.addDialog("Not logged in", 
+                                       "Are you logged in on" + remote_wiki_host + " ? Please loggin", 
+                                       btn
+                               )                               
+                       }else{
+                               $j('#helloTarget').hide().text( data.query.userinfo.name ).fadeIn('slow');
+                       }
+               }
+       );
+       return false;
+}
+</script>
+</head>
+<body>
+<h3> Simple API proxy testing system </h3>
+
+<div id="setupProxy">Setting up Proxy ... ( <span id="hostName"></span> )</div>
+<div id="setupDone" style="display:none;">
+<br> <a href="#" id="doAppendCat" >Hello User</a> <span id="helloTarget"><span>
+<br> Some other fun api stuff here...
+</div>
+
+</body>
+</html>
\ No newline at end of file
index b4d90b0..836b971 100644 (file)
@@ -28,6 +28,15 @@ function doPageSpecificRewrite() {
                        importScriptURI( mwEmbedHostPath + '/uploadPage.js' + reqAguments );
                } );
        }
+       
+       // Special api proxy page
+       if( wgPageName == 'MediaWiki:ApiProxy' ){
+               var wgEnableIframeApiProxy = true;
+               load_mv_embed( function() {
+                       importScriptURI( mwEmbedHostPath + '/ApiProxyPage.js' + reqAguments );
+               });
+       }
+       
 
        // OggHandler rewrite for view pages:
        var vidIdList = [];