r76409 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r76408‎ | r76409 | r76410 >
Date:19:53, 9 November 2010
Author:questpc
Status:deferred (Comments)
Tags:
Comment:
Built-in simple scheduler. Local settings stored in cookies. v0.3.1a
Modified paths:
  • /trunk/extensions/WikiSync/INSTALL (modified) (history)
  • /trunk/extensions/WikiSync/README (modified) (history)
  • /trunk/extensions/WikiSync/WikiSync.css (modified) (history)
  • /trunk/extensions/WikiSync/WikiSync.i18n.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSync.js (modified) (history)
  • /trunk/extensions/WikiSync/WikiSync.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncApi.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncBasic.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncClient.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncExporter.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSyncPage.php (modified) (history)
  • /trunk/extensions/WikiSync/WikiSync_utils.js (modified) (history)
  • /trunk/extensions/WikiSync/md5.js (added) (history)

Diff [purge]

Index: trunk/extensions/WikiSync/WikiSyncExporter.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.2.1
 32+ * @version 0.3.1
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
Index: trunk/extensions/WikiSync/WikiSyncApi.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.2.1
 32+ * @version 0.3.1
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
Index: trunk/extensions/WikiSync/WikiSyncPage.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.2.1
 32+ * @version 0.3.1
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
@@ -40,9 +40,6 @@
4141
4242 class WikiSyncPage extends SpecialPage {
4343
44 - var $sync_direction_tpl;
45 - var $remote_login_form_tpl;
46 - var $remote_log_tpl;
4744 var $page_tpl;
4845
4946 var $initUser;
@@ -51,9 +48,9 @@
5249 $remote_wiki_root = _QXML::specialchars( WikiSyncSetup::$remote_wiki_root );
5350 $remote_wiki_user = _QXML::specialchars( WikiSyncSetup::$remote_wiki_user );
5451 $js_remote_change = 'return WikiSync.remoteRootChange(this)';
55 - $js_sync_files = 'return WikiSync.setSyncFiles(this);';
56 - $this->remote_login_form_tpl =
57 - array( '__tag'=>'table', 'class'=>'wikisync_remote_login',
 52+ $js_blur = 'return WikiSync.blurElement(this);';
 53+ return
 54+ array( '__tag'=>'table', 'style'=>'width:100%; ',
5855 array( '__tag'=>'form', 'id'=>'remote_login_form', 'onsubmit'=>'return WikiSync.submitRemoteLogin(this);',
5956 array( '__tag'=>'tr',
6057 array( '__tag'=>'th', 'colspan'=>'2', 'style'=>'text-align:center; ', wfMsgHtml( 'wikisync_login_to_remote_wiki' ) )
@@ -71,7 +68,13 @@
7269 array( '__tag'=>'td', array( '__tag'=>'input', 'type'=>'password', 'name'=>'remote_wiki_pass' ) )
7370 ),
7471 array( '__tag'=>'tr',
75 - array( '__tag'=>'td', 'colspan'=>'2', wfMsgHtml( 'wikisync_sync_files' ), array( '__tag'=>'input', 'type'=>'checkbox', 'id'=>'ws_sync_files', 'name'=>'ws_sync_files', 'onchange'=>$js_sync_files, 'onmouseup'=>$js_sync_files, 'checked'=>'' ) )
 72+ array( '__tag'=>'td', 'colspan'=>'2',
 73+ wfMsgHtml( 'wikisync_sync_files' ),
 74+ array( '__tag'=>'input', 'type'=>'checkbox', 'id'=>'ws_sync_files', 'name'=>'ws_sync_files', 'onchange'=>$js_blur, 'onmouseup'=>$js_blur, 'checked'=>'' ),
 75+ array( '__tag'=>'br', 'clear'=>'all', '' ),
 76+ wfMsgHtml( 'wikisync_store_password' ),
 77+ array( '__tag'=>'input', 'type'=>'checkbox', 'id'=>'ws_store_password', 'name'=>'ws_store_password', 'onchange'=>$js_blur, 'onmouseup'=>$js_blur )
 78+ )
7679 ),
7780 array( '__tag'=>'tr',
7881 array( '__tag'=>'td', array( '__tag'=>'input', 'id'=>'wikisync_synchronization_button', 'type'=>'button', 'value'=>wfMsgHtml( 'wikisync_synchronization_button' ), 'disabled'=>'', 'onclick'=>'return WikiSync.process(\'init\')' ) ),
@@ -81,20 +84,48 @@
8285 );
8386 }
8487
85 - function initRemoteLogTpl() {
86 - $this->remote_log_tpl =
87 - array( '__tag'=>'table', 'class'=>'wikisync_remote_log',
 88+ function initSchedulerTpl() {
 89+ $js_blur = 'return WikiSync.blurElement(this);';
 90+ return
 91+ array( '__tag'=>'table', 'style'=>'width:100%; ',
 92+ array( '__tag'=>'form', 'id'=>'scheduler_form', 'onsubmit'=>'return WikiSyncScheduler.setup(this);',
 93+ array( '__tag'=>'tr',
 94+ array( '__tag'=>'th', 'colspan'=>'2', 'style'=>'text-align:center; ', wfMsgHtml( 'wikisync_scheduler_setup' ) )
 95+ ),
 96+ array( '__tag'=>'tr',
 97+ array( '__tag'=>'td', 'colspan'=>'2',
 98+ wfMsgHtml( 'wikisync_scheduler_turn_on' ),
 99+ array( '__tag'=>'input', 'type'=>'checkbox', 'name'=>'ws_auto_sync', 'onchange'=>$js_blur, 'onmouseup'=>$js_blur ),
 100+ array( '__tag'=>'br', 'clear'=>'all', '' ),
 101+ wfMsgHtml( 'wikisync_scheduler_switch_direction' ),
 102+ array( '__tag'=>'input', 'type'=>'checkbox', 'name'=>'ws_auto_switch_direction', 'onchange'=>$js_blur, 'onmouseup'=>$js_blur ),
 103+ array( '__tag'=>'br', 'clear'=>'all', '' ),
 104+ wfMsgHtml( 'wikisync_scheduler_time_interval' ),
 105+ array( '__tag'=>'input', 'type'=>'text', 'style'=>'margin-left:3px; width:3em; ', 'name'=>'ws_auto_sync_time_interval' )
 106+ )
 107+ ),
 108+ array( '__tag'=>'tr',
 109+ array( '__tag'=>'td', 'id'=>'ws_scheduler_countdown', '' ), // a placeholder for scheduled time countdown in javascript
 110+ array( '__tag'=>'td', 'style'=>'text-align:right; ', array( '__tag'=>'input', 'id'=>'wikisync_scheduler_apply_button', 'type'=>'submit', 'value'=>wfMsgHtml( 'wikisync_apply_button' ) ) )
 111+ )
 112+ )
 113+ );
 114+ }
 115+
 116+ function initLogTpl( $log_id ) {
 117+ return
 118+ array( '__tag'=>'table', 'style'=>'width:100%; ',
88119 array( '__tag'=>'tr',
89 - array( '__tag'=>'th', 'style'=>'text-align:center; ', wfMsgHtml( 'wikisync_remote_log' ) )
 120+ array( '__tag'=>'th', 'style'=>'text-align:center; ', wfMsgHtml( $log_id ) )
90121 ),
91122 array( '__tag'=>'tr',
92123 array( '__tag'=>'td',
93 - array( '__tag'=>'div', 'id'=>'wikisync_remote_log' )
 124+ array( '__tag'=>'div', 'class'=>'wikisync_log', 'id'=>$log_id )
94125 )
95126 ),
96127 array( '__tag'=>'tr',
97128 array( '__tag'=>'td',
98 - array( '__tag'=>'input', 'type'=>'button', 'value'=>wfMsgHtml( 'wikisync_clear_log' ), 'onclick'=>'return WikiSync.clearLog()' )
 129+ array( '__tag'=>'input', 'type'=>'button', 'value'=>wfMsgHtml( 'wikisync_clear_log' ), 'onclick'=>'return WikiSync.clearLog(\'' . $log_id . '\')' )
99130 )
100131 )
101132 );
@@ -102,13 +133,13 @@
103134
104135 function initSyncDirectionTpl() {
105136 global $wgServer, $wgScriptPath;
106 - $this->sync_direction_tpl =
 137+ return
107138 array(
108139 array( '__tag'=>'div', 'style'=>'width:100%; font-weight:bold; text-align:center; ', wfMsgHTML( 'wikisync_direction' ) ),
109140 array( '__tag'=>'table', 'style'=>'margin:0 auto 0 auto; ',
110141 array( '__tag'=>'tr',
111142 array( '__tag'=>'td', 'style'=>'text-align:right; ', wfMsgHTML( 'wikisync_local_root' ) ),
112 - array( '__tag'=>'td', 'rowspan'=>'2', 'style'=>'vertical-align:middle; ', array( '__tag'=>'input', 'id'=>'wikisync_direction_button', 'type'=>'button', 'value'=>'&lt;=', 'onclick'=>'return WikiSync.setDirection(this)' ) ),
 143+ array( '__tag'=>'td', 'rowspan'=>'2', 'style'=>'vertical-align:middle; ', array( '__tag'=>'input', 'id'=>'wikisync_direction_button', 'type'=>'button', 'value'=>'&lt;=', 'onclick'=>'return WikiSync.switchDirection(this)' ) ),
113144 array( '__tag'=>'td', wfMsgHTML( 'wikisync_remote_root' ) )
114145 ),
115146 array( '__tag'=>'tr',
@@ -134,15 +165,28 @@
135166 }
136167
137168 function initPageTpl() {
 169+ $tr_style = 'border:2px dashed lightgray; ';
138170 $this->page_tpl =
139171 array( '__tag'=>'table',
140 - array( '__tag'=>'tr',
141 - array( '__tag'=>'td', 'colspan'=>'2', &$this->sync_direction_tpl )
 172+ array( '__tag'=>'tr', 'style'=>$tr_style,
 173+ array( '__tag'=>'td', 'colspan'=>'2', $this->initSyncDirectionTpl() )
142174 ),
143 - array( '__tag'=>'tr',
144 - array( '__tag'=>'td', 'style'=>'width:50%; ', &$this->remote_log_tpl ),
145 - array( '__tag'=>'td', 'style'=>'width:50%; ', &$this->remote_login_form_tpl )
 175+ array( '__tag'=>'tr', 'style'=>$tr_style,
 176+ array( '__tag'=>'td', 'style'=>'width:50%; ',
 177+ $this->initLogTpl( 'wikisync_remote_log' ),
 178+ ),
 179+ array( '__tag'=>'td', 'style'=>'width:50%; ',
 180+ $this->initRemoteLoginFormTpl(),
 181+ )
146182 ),
 183+ array( '__tag'=>'tr', 'style'=>$tr_style,
 184+ array( '__tag'=>'td', 'style'=>'width:50%; ',
 185+ $this->initLogTpl( 'wikisync_scheduler_log' ),
 186+ ),
 187+ array( '__tag'=>'td', 'style'=>'width:50%; ',
 188+ $this->initSchedulerTpl()
 189+ )
 190+ ),
147191 array( '__tag'=>'tr',
148192 array( '__tag'=>'td', 'colspan'=>'2',
149193 $this->initPercentsIndicatorTpl( 'wikisync_xml_percents' ),
@@ -156,6 +200,7 @@
157201 array( '__tag'=>'td', 'colspan'=>'2',
158202 // Have to explicitly set empty contents for the iframe, or we'll produce
159203 // <iframe /> which browsers consider an unclosed tag
 204+ // todo: fix in _QXML class
160205 array( '__tag'=> 'iframe', 'id'=>'wikisync_iframe', 'style' => 'width:100%; height:200px; display:none; ', '' )
161206 )
162207 )
@@ -186,9 +231,6 @@
187232 }
188233 WikiSyncSetup::headScripts( $wgOut, $wgContLang->isRTL() );
189234 $wgOut->setPagetitle( wfMsgHtml( 'wikisync' ) );
190 - $this->initSyncDirectionTpl();
191 - $this->initRemoteLoginFormTpl();
192 - $this->initRemoteLogTpl();
193235 $this->initPageTpl();
194236 $wgOut->addHTML( _QXML::toText( $this->page_tpl ) );
195237 }
Index: trunk/extensions/WikiSync/WikiSyncClient.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.2.1
 32+ * @version 0.3.1
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
@@ -265,6 +265,8 @@
266266 * @param $args[0] : remote wiki root
267267 * @param $args[1] : remote wiki user
268268 * @param $args[2] : remote wiki password
 269+ * @param $args[3] : string "boolean", whether the login / password should be stored
 270+ * in cookies; "true" - yes, "false" - not
269271 * @return JSON result of second phase login (token confirmed, used logged in) from the remote API
270272 */
271273 static function remoteLogin() {
@@ -279,6 +281,12 @@
280282 # not enough priviledges to run this method
281283 return $json_result->getResult( 'noaccess', $iu );
282284 }
 285+ $store_rlogin = count( $args ) > 3 && $args[3] === 'true';
 286+ if ( !$store_rlogin ) {
 287+ // unset cookies, if there were any
 288+ WikiSyncSetup::setCookie( 'ruser', '', 0 );
 289+ WikiSyncSetup::setCookie( 'rpass', '', 0 );
 290+ }
283291 $snoopy = new WikiSnoopy();
284292 list( $remote_wiki_root, $remote_wiki_user, $remote_wiki_password ) = $args;
285293 $snoopy->setContext( array( 'wikiroot'=>$remote_wiki_root ) );
@@ -324,6 +332,10 @@
325333 }
326334 if ( $response->login->result === 'Success' ) {
327335 $json_result->setStatus( '1' ); // success
 336+ if ( $store_rlogin ) {
 337+ WikiSyncSetup::setCookie( 'ruser', $remote_wiki_user, time() + WikiSyncSetup::COOKIE_EXPIRE_TIME );
 338+ WikiSyncSetup::setCookie( 'rpass', $remote_wiki_password, time() + WikiSyncSetup::COOKIE_EXPIRE_TIME );
 339+ }
328340 $r = array(
329341 'userid' => $response->login->lguserid,
330342 'username' => $response->login->lgusername, // may return a different one ?
Index: trunk/extensions/WikiSync/WikiSync.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.2.1
 32+ * @version 0.3.1
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
@@ -73,6 +73,9 @@
7474 }
7575
7676 class WikiSyncSetup {
 77+
 78+ const COOKIE_EXPIRE_TIME = 2592000; // 60 * 60 * 24 * 30; see also WikiSync.js, WikiSync.cookieExpireTime
 79+
7780 # {{{ changable in LocalSettings.php :
7881 static $remote_wiki_root = 'http://www.mediawiki.org/w';
7982 static $remote_wiki_user = '';
@@ -90,10 +93,14 @@
9194 static $proxy_pass = '';
9295 # }}}
9396
94 - static $version = '0.2.1'; // version of extension
 97+ static $version = '0.3.1'; // version of extension
9598 static $ExtDir; // filesys path with windows path fix
9699 static $ScriptPath; // apache virtual path
97100
 101+ static $user; // current User
 102+ static $cookie_prefix; // an extension's cookie prefix for current User
 103+ static $response; // an extension's WebResponse
 104+
98105 const JS_MSG_PREFIX = 'wikisync_js_';
99106 static $jsMessages = array(
100107 'last_op_error',
@@ -103,7 +110,13 @@
104111 'sync_to_itself',
105112 'diff_search',
106113 'revision',
107 - 'file_size_mismatch'
 114+ 'file_size_mismatch',
 115+ 'invalid_scheduler_time',
 116+ 'scheduler_countdown',
 117+ 'sync_start_ltr',
 118+ 'sync_start_rtl',
 119+ 'sync_end_ltr',
 120+ 'sync_end_rtl'
108121 );
109122
110123 static function init() {
@@ -172,7 +185,7 @@
173186 array(
174187 'ext.wikisync' => new ResourceLoaderFileModule(
175188 array(
176 - 'scripts' => array( 'WikiSync_utils.js', 'WikiSync.js' ),
 189+ 'scripts' => array( 'md5.js', 'WikiSync_utils.js', 'WikiSync.js' ),
177190 'styles' => 'WikiSync.css',
178191 'messages' => array_map( 'self::setJSprefix', self::$jsMessages )
179192 ),
@@ -182,9 +195,9 @@
183196 )
184197 );
185198 return true;
186 - }
 199+ }
187200
188 - /*
 201+ /**
189202 * include stylesheets and scripts; set javascript variables
190203 * @param $outputPage - an instance of OutputPage
191204 * @param $isRTL - whether the current language is RTL
@@ -205,12 +218,13 @@
206219 );
207220 }
208221 $outputPage->addScript(
209 - '<script type="' . $wgJsMimeType . '" src="' . self::$ScriptPath . '/WikiSync_Utils.js?' . self::$version . '"></script>
 222+ '<script type="' . $wgJsMimeType . '" src="' . self::$ScriptPath . '/md5.js?' . self::$version . '"></script>
 223+ <script type="' . $wgJsMimeType . '" src="' . self::$ScriptPath . '/WikiSync_Utils.js?' . self::$version . '"></script>
210224 <script type="' . $wgJsMimeType . '" src="' . self::$ScriptPath . '/WikiSync.js?' . self::$version . '"></script>
211225 <script type="' . $wgJsMimeType . '">
212 - WikiSync.setLocalMessages( ' .
213 - self::getJsObject( 'wsLocalMessages', self::$jsMessages ) .
214 - ');</script>' . "\n"
 226+ WikiSync.setLocalMessages(' . self::getJsObject( 'wsLocalMessages', self::$jsMessages ) . ');
 227+ </script>
 228+'
215229 );
216230 }
217231
@@ -235,7 +249,7 @@
236250 return wfMsg( 'wikisync_api_result_noaccess', $wgLang->commaList( $groups ) );
237251 }
238252
239 - /*
 253+ /**
240254 * should not be called from LocalSettings.php
241255 * should be called only when the wiki is fully initialized
242256 * @param $direction defines the direction of synchronization
@@ -246,7 +260,11 @@
247261 * string error message, when the current user has no access
248262 */
249263 static function initUser( $direction = null) {
 264+ global $wgUser, $wgRequest;
 265+ self::$user = is_object( $wgUser ) ? $wgUser : new User();
 266+ self::$response = $wgRequest->response();
250267 wfLoadExtensionMessages( 'WikiSync' );
 268+ self::$cookie_prefix = 'WikiSync_' . md5( self::$user->getName() ) . '_';
251269 if ( $direction === true ) {
252270 return self::checkUserMembership( self::$rtl_access_groups );
253271 } elseif ( $direction === false ) {
@@ -258,4 +276,42 @@
259277 return 'Bug: direction should be boolean or null, value (' . $direction . ') given in ' . __METHOD__;
260278 }
261279
 280+ static function getFullCookieName( $cookievar ) {
 281+ global $wgCookiePrefix;
 282+ if ( !is_string( self::$cookie_prefix ) ) {
 283+ throw new MWException( 'You have to call CB_Setup::initUser before to use ' . __METHOD__ );
 284+ }
 285+ return $wgCookiePrefix . self::$cookie_prefix . $cookievar;
 286+ }
 287+
 288+ static function getJsCookiePrefix() {
 289+ global $wgCookiePrefix;
 290+ if ( !is_string( self::$cookie_prefix ) ) {
 291+ throw new MWException( 'You have to call CB_Setup::initUser before to use ' . __METHOD__ );
 292+ }
 293+ return Xml::escapeJsString( $wgCookiePrefix . self::$cookie_prefix );
 294+ }
 295+
 296+ /**
 297+ * set a cookie which is accessible in javascript
 298+ */
 299+ static function setCookie( $cookievar, $val, $time ) {
 300+ global $wgCookieHttpOnly;
 301+ // User::setCookies() is not suitable for our needs because it's called only for non-anonymous users
 302+ // our cookie has to be accessible in javascript
 303+ // todo: cookie is not set / read in JS anymore, don't modify $wgCookieHttpOnly
 304+ $wgCookieHttpOnly_save = $wgCookieHttpOnly;
 305+ $wgCookieHttpOnly = false;
 306+ if ( !is_string( self::$cookie_prefix ) || !is_object( self::$response ) ) {
 307+ throw new MWException( 'You have to call CB_Setup::initUser before to use ' . __METHOD__ );
 308+ }
 309+ self::$response->setcookie( self::$cookie_prefix . $cookievar, $val, $time );
 310+ $wgCookieHttpOnly = $wgCookieHttpOnly_save;
 311+ }
 312+
 313+ static function getCookie( $cookievar ) {
 314+ $idx = self::getFullCookieName( $cookievar );
 315+ return isset( $_COOKIE[ $idx ] ) ? $_COOKIE[ $idx ] : null;
 316+ }
 317+
262318 } /* end of WikiSyncSetup class */
Index: trunk/extensions/WikiSync/WikiSync.css
@@ -2,12 +2,12 @@
33 width: 15em;
44 }
55
6 -div#wikisync_remote_log {
 6+div.wikisync_log {
77 color: darkblue;
88 background-color: lightgray;
99 border: 1px solid gray;
1010 width: 30em;
11 - height: 12em;
 11+ height: 9em;
1212 overflow: auto;
1313 padding: 5px;
1414 }
Index: trunk/extensions/WikiSync/WikiSyncBasic.php
@@ -28,7 +28,7 @@
2929 * * Add this line at the end of your LocalSettings.php file :
3030 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3131 *
32 - * @version 0.2.1
 32+ * @version 0.3.1
3333 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3434 * @author Dmitriy Sintsov <questpc@rambler.ru>
3535 * @addtogroup Extensions
Index: trunk/extensions/WikiSync/WikiSync_utils.js
@@ -1,4 +1,14 @@
22 window.WikiSyncUtils = {
 3+
 4+ mathLogBase : function( x, base ) {
 5+ return Math.log( x ) / Math.log( base );
 6+ },
 7+
 8+ getLocalDate : function() {
 9+ var today = new Date();
 10+ return today.toLocaleString();
 11+ },
 12+
313 // browser-independent addevent function
414 addEvent : function ( obj, type, fn ) {
515 if ( document.getElementById && document.createTextNode ) {
@@ -30,6 +40,88 @@
3141 }
3242 }
3343 return obj;
 44+ },
 45+
 46+ /**
 47+ * taken from http://phpjs.org/functions/urldecode:572
 48+ */
 49+ urldecode : function( s ) {
 50+ return decodeURIComponent( s.replace(/\+/g, '%20') );
 51+ },
 52+
 53+ // basename prefix of user's cookies
 54+ cookiePrefix : null,
 55+
 56+ /*
 57+ */
 58+ setCookiePrefix : function( name ) {
 59+ this.cookiePrefix = name;
 60+ },
 61+
 62+ /*
 63+ * @return empty string in case cookie value is empty, null when cookie is not set
 64+ */
 65+ getCookie : function ( cookieName ) {
 66+ var ca, cn, keyval, key, val;
 67+ ca = document.cookie.split( ';' );
 68+ for ( var i=0; i < ca.length; i++ ) {
 69+ keyval = ca[i].split( '=' );
 70+ // trim whitespace
 71+ key = keyval[0].replace(/^\s+|\s+$/g, '');
 72+ if ( key == (this.cookiePrefix + cookieName) ) {
 73+ if ( keyval.length > 1 ) {
 74+ return this.urldecode( keyval[1].replace(/^\s+|\s+$/g, '') );
 75+ } else {
 76+ // cookie exists but has no value
 77+ return "";
 78+ }
 79+ }
 80+ }
 81+ // cookie not found
 82+ return null;
 83+ },
 84+
 85+ /*
 86+ * usage example: WikiSyncUtils.setCookie( 'rootcond', eventObj.value, 24 * 60 * 60, '/' );
 87+ */
 88+ setCookie : function( cookieName, value, expires, path, domain, secure ) {
 89+ // set time, it's in milliseconds
 90+ var today = new Date();
 91+ today.setTime( today.getTime() );
 92+
 93+ /*
 94+ if the expires variable is set, make the correct
 95+ expires time, the current script below will set
 96+ it for x number of days, to make it for hours,
 97+ delete * 24, for minutes, delete * 60 * 24
 98+ */
 99+ if ( expires ) {
 100+ expires = expires * 1000 // * 60 * 60 * 24;
 101+ }
 102+ var expires_date = new Date( today.getTime() + expires );
 103+
 104+ document.cookie = this.cookiePrefix + cookieName + "=" +escape( value ) +
 105+ ( ( expires ) ? ";expires=" + expires_date.toGMTString() : "" ) +
 106+ ( ( path ) ? ";path=" + path : "" ) +
 107+ ( ( domain ) ? ";domain=" + domain : "" ) +
 108+ ( ( secure ) ? ";secure" : "" );
 109+ },
 110+
 111+ cookieToInput : function( cookie, input ) {
 112+ var val = this.getCookie( cookie );
 113+ if ( val !== null ) {
 114+ input.value = val;
 115+ }
 116+ return val;
 117+ },
 118+
 119+ cookieToCheckbox : function( cookie, input ) {
 120+ var val = this.getCookie( cookie );
 121+ if ( val !== null ) {
 122+ val = val === 'true';
 123+ input.checked = val;
 124+ }
 125+ return val;
34126 }
35127
36128 };
@@ -49,9 +141,11 @@
50142 this.td2 = this.td1.nextSibling;
51143 this.reset();
52144 }
 145+
53146 WikiSyncPercentsIndicator.prototype.setVisibility = function( visible ) {
54147 this.topElement.style.display = visible ? 'table' : 'none';
55148 }
 149+
56150 /**
57151 * @access private
58152 */
@@ -59,10 +153,12 @@
60154 element.style.display = (percent > 0) ? 'table-cell' : 'none';
61155 element.style.width = percent + '%';
62156 }
 157+
63158 WikiSyncPercentsIndicator.prototype.reset = function() {
64159 this.iterations = { 'desc' : '', 'curr' : 0, 'min' : 0, 'max' : 0 };
65160 this.display();
66 -},
 161+}
 162+
67163 WikiSyncPercentsIndicator.prototype.display = function( indicator ) {
68164 if ( typeof indicator !== 'undefined' ) {
69165 if ( typeof indicator.desc !== 'undefined' ) {
@@ -104,4 +200,41 @@
105201 // show percent
106202 this.setPercents( this.td1, percent );
107203 this.setPercents( this.td2, 100 - percent );
108 -} /* end of WikiSyncPercentsIndicator class */
 204+}
 205+/* end of WikiSyncPercentsIndicator class */
 206+
 207+/**
 208+ * Debug / output logger class
 209+ * @param logId - id of DIV container for logger
 210+ */
 211+function WikiSyncLog( logId ) {
 212+ this.logContainer = document.getElementById( logId );
 213+}
 214+
 215+WikiSyncLog.prototype.log = function( s, color, type ) {
 216+ var span = document.createElement( 'SPAN' );
 217+ if ( typeof s === 'object' ) {
 218+ s = JSON.stringify( s );
 219+ }
 220+ if ( typeof type !== 'undefined' ) {
 221+ var b = document.createElement( 'B' );
 222+ b.appendChild( document.createTextNode( type + ': ' ) );
 223+ span.appendChild( b );
 224+ }
 225+ span.appendChild( document.createTextNode( s ) );
 226+ if ( typeof color !== 'undefined' ) {
 227+ span.style.color = color;
 228+ }
 229+ this.logContainer.appendChild( span );
 230+ this.logContainer.appendChild( document.createElement( 'HR' ) );
 231+ this.logContainer.scrollTop = this.logContainer.scrollHeight;
 232+}
 233+
 234+/**
 235+ * note: may be used as "inline html" event handler, thus should return true / false
 236+ */
 237+WikiSyncLog.prototype.clear = function() {
 238+ this.logContainer.innerHTML = '';
 239+ return false;
 240+}
 241+/* end of WikiSyncLog class */
\ No newline at end of file
Index: trunk/extensions/WikiSync/README
@@ -1,4 +1,4 @@
2 -MediaWiki extension WikiSync, version 0.2.1
 2+MediaWiki extension WikiSync, version 0.3.1
33
44 WikiSync allows an AJAX-based synchronization of revisions and files between
55 global wiki site and it's local mirror. Files download can optionally be disabled,
Index: trunk/extensions/WikiSync/md5.js
@@ -0,0 +1,363 @@
 2+/*
 3+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
 4+ * Digest Algorithm, as defined in RFC 1321.
 5+ * Version 2.2 Copyright (C) Paul Johnston 1999 - 2009
 6+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
 7+ * Distributed under the BSD License
 8+ * See http://pajhome.org.uk/crypt/md5 for more info.
 9+ */
 10+
 11+// ported to use object notation
 12+// I've choosed WikiSync prefix to make window scope conflict unlikely to happen
 13+window.WikiSync_md5 = {
 14+
 15+/*
 16+ * Configurable variables. You may need to tweak these to be compatible with
 17+ * the server-side, but the defaults work in most cases.
 18+ */
 19+hexcase : 0, /* hex output format. 0 - lowercase; 1 - uppercase */
 20+b64pad : "", /* base-64 pad character. "=" for strict RFC compliance */
 21+
 22+/*
 23+ * These are the functions you'll usually want to call
 24+ * They take string arguments and return either hex or base-64 encoded strings
 25+ */
 26+hex : function (s) { return this.rstr2hex(this.rstr(this.str2rstr_utf8(s))); },
 27+b64 : function (s) { return this.rstr2b64(this.rstr(this.str2rstr_utf8(s))); },
 28+any : function (s, e) { return this.rstr2any(this.rstr(this.str2rstr_utf8(s)), e); },
 29+hex_hmac : function (k, d) { return this.rstr2hex(this.rstr_hmac(this.str2rstr_utf8(k), this.str2rstr_utf8(d))); },
 30+b64_hmac : function(k, d) { return this.rstr2b64(this.rstr_hmac(this.str2rstr_utf8(k), this.str2rstr_utf8(d))); },
 31+any_hmac : function(k, d, e) { return this.rstr2any(this.rstr_hmac(this.str2rstr_utf8(k), this.str2rstr_utf8(d)), e); },
 32+
 33+/*
 34+ * Perform a simple self-test to see if the VM is working
 35+ */
 36+md5_vm_test : function () {
 37+ return this.hex("abc").toLowerCase() == "900150983cd24fb0d6963f7d28e17f72";
 38+},
 39+
 40+/*
 41+ * Calculate the MD5 of a raw string
 42+ */
 43+rstr : function(s) {
 44+ return this.binl2rstr(this.binl(this.rstr2binl(s), s.length * 8));
 45+},
 46+
 47+/*
 48+ * Calculate the HMAC-MD5, of a key and some data (raw strings)
 49+ */
 50+rstr_hmac : function(key, data) {
 51+ var bkey = this.rstr2binl(key);
 52+ if(bkey.length > 16) bkey = this.binl(bkey, key.length * 8);
 53+
 54+ var ipad = Array(16), opad = Array(16);
 55+ for(var i = 0; i < 16; i++)
 56+ {
 57+ ipad[i] = bkey[i] ^ 0x36363636;
 58+ opad[i] = bkey[i] ^ 0x5C5C5C5C;
 59+ }
 60+
 61+ var hash = this.binl(ipad.concat(this.rstr2binl(data)), 512 + data.length * 8);
 62+ return this.binl2rstr(this.binl(opad.concat(hash), 512 + 128));
 63+},
 64+
 65+/*
 66+ * Convert a raw string to a hex string
 67+ */
 68+rstr2hex : function (input) {
 69+ try { this.hexcase } catch(e) { this.hexcase=0; }
 70+ var hex_tab = this.hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
 71+ var output = "";
 72+ var x;
 73+ for(var i = 0; i < input.length; i++)
 74+ {
 75+ x = input.charCodeAt(i);
 76+ output += hex_tab.charAt((x >>> 4) & 0x0F)
 77+ + hex_tab.charAt( x & 0x0F);
 78+ }
 79+ return output;
 80+},
 81+
 82+/*
 83+ * Convert a raw string to a base-64 string
 84+ */
 85+rstr2b64 : function(input) {
 86+ try { this.b64pad } catch(e) { this.b64pad=''; }
 87+ var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 88+ var output = "";
 89+ var len = input.length;
 90+ for(var i = 0; i < len; i += 3)
 91+ {
 92+ var triplet = (input.charCodeAt(i) << 16)
 93+ | (i + 1 < len ? input.charCodeAt(i+1) << 8 : 0)
 94+ | (i + 2 < len ? input.charCodeAt(i+2) : 0);
 95+ for(var j = 0; j < 4; j++)
 96+ {
 97+ if(i * 8 + j * 6 > input.length * 8) output += this.b64pad;
 98+ else output += tab.charAt((triplet >>> 6*(3-j)) & 0x3F);
 99+ }
 100+ }
 101+ return output;
 102+},
 103+
 104+/*
 105+ * Convert a raw string to an arbitrary string encoding
 106+ */
 107+rstr2any : function(input, encoding) {
 108+ var divisor = encoding.length;
 109+ var i, j, q, x, quotient;
 110+
 111+ /* Convert to an array of 16-bit big-endian values, forming the dividend */
 112+ var dividend = Array(Math.ceil(input.length / 2));
 113+ for(i = 0; i < dividend.length; i++)
 114+ {
 115+ dividend[i] = (input.charCodeAt(i * 2) << 8) | input.charCodeAt(i * 2 + 1);
 116+ }
 117+
 118+ /*
 119+ * Repeatedly perform a long division. The binary array forms the dividend,
 120+ * the length of the encoding is the divisor. Once computed, the quotient
 121+ * forms the dividend for the next step. All remainders are stored for later
 122+ * use.
 123+ */
 124+ var full_length = Math.ceil(input.length * 8 /
 125+ (Math.log(encoding.length) / Math.log(2)));
 126+ var remainders = Array(full_length);
 127+ for(j = 0; j < full_length; j++)
 128+ {
 129+ quotient = Array();
 130+ x = 0;
 131+ for(i = 0; i < dividend.length; i++)
 132+ {
 133+ x = (x << 16) + dividend[i];
 134+ q = Math.floor(x / divisor);
 135+ x -= q * divisor;
 136+ if(quotient.length > 0 || q > 0)
 137+ quotient[quotient.length] = q;
 138+ }
 139+ remainders[j] = x;
 140+ dividend = quotient;
 141+ }
 142+
 143+ /* Convert the remainders to the output string */
 144+ var output = "";
 145+ for(i = remainders.length - 1; i >= 0; i--)
 146+ output += encoding.charAt(remainders[i]);
 147+
 148+ return output;
 149+},
 150+
 151+/*
 152+ * Encode a string as utf-8.
 153+ * For efficiency, this assumes the input is valid utf-16.
 154+ */
 155+str2rstr_utf8 : function(input) {
 156+ var output = "";
 157+ var i = -1;
 158+ var x, y;
 159+
 160+ while(++i < input.length)
 161+ {
 162+ /* Decode utf-16 surrogate pairs */
 163+ x = input.charCodeAt(i);
 164+ y = i + 1 < input.length ? input.charCodeAt(i + 1) : 0;
 165+ if(0xD800 <= x && x <= 0xDBFF && 0xDC00 <= y && y <= 0xDFFF)
 166+ {
 167+ x = 0x10000 + ((x & 0x03FF) << 10) + (y & 0x03FF);
 168+ i++;
 169+ }
 170+
 171+ /* Encode output as utf-8 */
 172+ if(x <= 0x7F)
 173+ output += String.fromCharCode(x);
 174+ else if(x <= 0x7FF)
 175+ output += String.fromCharCode(0xC0 | ((x >>> 6 ) & 0x1F),
 176+ 0x80 | ( x & 0x3F));
 177+ else if(x <= 0xFFFF)
 178+ output += String.fromCharCode(0xE0 | ((x >>> 12) & 0x0F),
 179+ 0x80 | ((x >>> 6 ) & 0x3F),
 180+ 0x80 | ( x & 0x3F));
 181+ else if(x <= 0x1FFFFF)
 182+ output += String.fromCharCode(0xF0 | ((x >>> 18) & 0x07),
 183+ 0x80 | ((x >>> 12) & 0x3F),
 184+ 0x80 | ((x >>> 6 ) & 0x3F),
 185+ 0x80 | ( x & 0x3F));
 186+ }
 187+ return output;
 188+},
 189+
 190+/*
 191+ * Encode a string as utf-16
 192+ */
 193+str2rstr_utf16le : function(input) {
 194+ var output = "";
 195+ for(var i = 0; i < input.length; i++)
 196+ output += String.fromCharCode( input.charCodeAt(i) & 0xFF,
 197+ (input.charCodeAt(i) >>> 8) & 0xFF);
 198+ return output;
 199+},
 200+
 201+str2rstr_utf16be : function(input) {
 202+ var output = "";
 203+ for(var i = 0; i < input.length; i++)
 204+ output += String.fromCharCode((input.charCodeAt(i) >>> 8) & 0xFF,
 205+ input.charCodeAt(i) & 0xFF);
 206+ return output;
 207+},
 208+
 209+/*
 210+ * Convert a raw string to an array of little-endian words
 211+ * Characters >255 have their high-byte silently ignored.
 212+ */
 213+rstr2binl : function(input) {
 214+ var output = Array(input.length >> 2);
 215+ for(var i = 0; i < output.length; i++)
 216+ output[i] = 0;
 217+ for(var i = 0; i < input.length * 8; i += 8)
 218+ output[i>>5] |= (input.charCodeAt(i / 8) & 0xFF) << (i%32);
 219+ return output;
 220+},
 221+
 222+/*
 223+ * Convert an array of little-endian words to a string
 224+ */
 225+binl2rstr : function(input) {
 226+ var output = "";
 227+ for(var i = 0; i < input.length * 32; i += 8)
 228+ output += String.fromCharCode((input[i>>5] >>> (i % 32)) & 0xFF);
 229+ return output;
 230+},
 231+
 232+/*
 233+ * Calculate the MD5 of an array of little-endian words, and a bit length.
 234+ */
 235+binl : function(x, len) {
 236+ /* append padding */
 237+ x[len >> 5] |= 0x80 << ((len) % 32);
 238+ x[(((len + 64) >>> 9) << 4) + 14] = len;
 239+
 240+ var a = 1732584193;
 241+ var b = -271733879;
 242+ var c = -1732584194;
 243+ var d = 271733878;
 244+
 245+ for(var i = 0; i < x.length; i += 16)
 246+ {
 247+ var olda = a;
 248+ var oldb = b;
 249+ var oldc = c;
 250+ var oldd = d;
 251+
 252+ a = this.md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
 253+ d = this.md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
 254+ c = this.md5_ff(c, d, a, b, x[i+ 2], 17, 606105819);
 255+ b = this.md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
 256+ a = this.md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
 257+ d = this.md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426);
 258+ c = this.md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
 259+ b = this.md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
 260+ a = this.md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416);
 261+ d = this.md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
 262+ c = this.md5_ff(c, d, a, b, x[i+10], 17, -42063);
 263+ b = this.md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
 264+ a = this.md5_ff(a, b, c, d, x[i+12], 7 , 1804603682);
 265+ d = this.md5_ff(d, a, b, c, x[i+13], 12, -40341101);
 266+ c = this.md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
 267+ b = this.md5_ff(b, c, d, a, x[i+15], 22, 1236535329);
 268+
 269+ a = this.md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
 270+ d = this.md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
 271+ c = this.md5_gg(c, d, a, b, x[i+11], 14, 643717713);
 272+ b = this.md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
 273+ a = this.md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
 274+ d = this.md5_gg(d, a, b, c, x[i+10], 9 , 38016083);
 275+ c = this.md5_gg(c, d, a, b, x[i+15], 14, -660478335);
 276+ b = this.md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
 277+ a = this.md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438);
 278+ d = this.md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
 279+ c = this.md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
 280+ b = this.md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501);
 281+ a = this.md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
 282+ d = this.md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
 283+ c = this.md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473);
 284+ b = this.md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
 285+
 286+ a = this.md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
 287+ d = this.md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
 288+ c = this.md5_hh(c, d, a, b, x[i+11], 16, 1839030562);
 289+ b = this.md5_hh(b, c, d, a, x[i+14], 23, -35309556);
 290+ a = this.md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
 291+ d = this.md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353);
 292+ c = this.md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
 293+ b = this.md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
 294+ a = this.md5_hh(a, b, c, d, x[i+13], 4 , 681279174);
 295+ d = this.md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
 296+ c = this.md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
 297+ b = this.md5_hh(b, c, d, a, x[i+ 6], 23, 76029189);
 298+ a = this.md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
 299+ d = this.md5_hh(d, a, b, c, x[i+12], 11, -421815835);
 300+ c = this.md5_hh(c, d, a, b, x[i+15], 16, 530742520);
 301+ b = this.md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
 302+
 303+ a = this.md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
 304+ d = this.md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415);
 305+ c = this.md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
 306+ b = this.md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
 307+ a = this.md5_ii(a, b, c, d, x[i+12], 6 , 1700485571);
 308+ d = this.md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
 309+ c = this.md5_ii(c, d, a, b, x[i+10], 15, -1051523);
 310+ b = this.md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
 311+ a = this.md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359);
 312+ d = this.md5_ii(d, a, b, c, x[i+15], 10, -30611744);
 313+ c = this.md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
 314+ b = this.md5_ii(b, c, d, a, x[i+13], 21, 1309151649);
 315+ a = this.md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
 316+ d = this.md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
 317+ c = this.md5_ii(c, d, a, b, x[i+ 2], 15, 718787259);
 318+ b = this.md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
 319+
 320+ a = this.safe_add(a, olda);
 321+ b = this.safe_add(b, oldb);
 322+ c = this.safe_add(c, oldc);
 323+ d = this.safe_add(d, oldd);
 324+ }
 325+ return Array(a, b, c, d);
 326+},
 327+
 328+/*
 329+ * These functions implement the four basic operations the algorithm uses.
 330+ */
 331+md5_cmn : function(q, a, b, x, s, t) {
 332+ return this.safe_add(this.bit_rol(this.safe_add(this.safe_add(a, q), this.safe_add(x, t)), s),b);
 333+},
 334+md5_ff : function(a, b, c, d, x, s, t) {
 335+ return this.md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
 336+},
 337+md5_gg : function(a, b, c, d, x, s, t) {
 338+ return this.md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
 339+},
 340+md5_hh : function(a, b, c, d, x, s, t) {
 341+ return this.md5_cmn(b ^ c ^ d, a, b, x, s, t);
 342+},
 343+md5_ii : function(a, b, c, d, x, s, t) {
 344+ return this.md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
 345+},
 346+
 347+/*
 348+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 349+ * to work around bugs in some JS interpreters.
 350+ */
 351+safe_add : function(x, y) {
 352+ var lsw = (x & 0xFFFF) + (y & 0xFFFF);
 353+ var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
 354+ return (msw << 16) | (lsw & 0xFFFF);
 355+},
 356+
 357+/*
 358+ * Bitwise rotate a 32-bit number to the left.
 359+ */
 360+bit_rol : function(num, cnt) {
 361+ return (num << cnt) | (num >>> (32 - cnt));
 362+}
 363+
 364+}
\ No newline at end of file
Property changes on: trunk/extensions/WikiSync/md5.js
___________________________________________________________________
Added: svn:eol-style
1365 + native
Index: trunk/extensions/WikiSync/WikiSync.i18n.php
@@ -19,12 +19,19 @@
2020 'wikisync_clear_log' => 'Clear log',
2121 'wikisync_login_to_remote_wiki' => 'Login to remote wiki',
2222 'wikisync_remote_wiki_root' => 'Remote wiki root',
23 - 'wikisync_remote_wiki_example' => 'Path to api.php, for example: http://www.mediawiki.org/w',
 23+ 'wikisync_remote_wiki_example' => 'path to api.php, for example: http://www.mediawiki.org/w',
2424 'wikisync_remote_wiki_user' => 'Remote wiki user name',
2525 'wikisync_remote_wiki_pass' => 'Remote wiki password',
2626 'wikisync_remote_login_button' => 'Log in',
2727 'wikisync_sync_files' => 'Synchronize files',
 28+ 'wikisync_store_password' => 'Store remote wiki password',
2829 'wikisync_synchronization_button' => 'Synchronize',
 30+ 'wikisync_scheduler_log' => 'Scheduler log',
 31+ 'wikisync_scheduler_setup' => 'Scheduler setup',
 32+ 'wikisync_scheduler_turn_on' => 'Turn on the scheduler',
 33+ 'wikisync_scheduler_switch_direction' => 'Automatically switch the direction of synchronization',
 34+ 'wikisync_scheduler_time_interval' => 'Time in minutes between automatical synchronizations',
 35+ 'wikisync_apply_button' => 'Apply',
2936 'wikisync_log_imported_by' => 'Imported by [[Special:WikiSync|WikiSync]]',
3037 'wikisync_log_uploaded_by' => 'Uploaded by [[Special:WikiSync|WikiSync]]',
3138 'wikisync_api_result_unknown_action' => 'Unknown API action',
@@ -36,7 +43,7 @@
3744 'wikisync_api_result_NoName' => 'You did not set the lgname parameter',
3845 'wikisync_api_result_Illegal' => 'You provided an illegal username',
3946 'wikisync_api_result_NotExists' => 'The username you provided does not exist',
40 - 'wikisync_api_result_EmptyPass' => 'You did not set the lgpassword parameter or you left it empty',
 47+ 'wikisync_api_result_EmptyPass' => 'You didn\'t set the lgpassword parameter or you left it empty',
4148 'wikisync_api_result_WrongPass' => 'The password you provided is incorrect',
4249 'wikisync_api_result_WrongPluginPass' => 'The password you provided is incorrect',
4350 'wikisync_api_result_CreateBlocked' => 'The wiki tried to automatically create a new account for you, but your IP address has been blocked from account creation',
@@ -44,7 +51,7 @@
4552 'wikisync_api_result_Blocked' => 'User is blocked',
4653 'wikisync_api_result_mustbeposted' => 'The login module requires a POST request',
4754 'wikisync_api_result_NeedToken' => 'Either you did not provide the login token or the sessionid cookie. Request again with the token and cookie given in this response',
48 - 'wikisync_api_result_no_import_rights' => 'This user is not allowed to import XML dump files',
 55+ 'wikisync_api_result_no_import_rights' => 'This user is not allowed to import xml dump files',
4956 'wikisync_api_result_Success' => 'Successfully logged into remote wiki site',
5057 'wikisync_js_last_op_error' => 'Last operation returned an error.
5158
@@ -65,9 +72,16 @@
6673 'wikisync_js_sync_to_itself' => 'You cannot synchronize the wiki to itself',
6774 'wikisync_js_diff_search' => 'Looking for difference in destination revisions',
6875 'wikisync_js_revision' => 'Revision $1',
69 - 'wikisync_js_file_size_mismatch' => 'Temporary file "$1" size ($2 bytes) does not match required size ($3 bytes). Make sure the file $4 was not manually overwritten in repository of source wiki.', // FIXME: needs plural support.
 76+ 'wikisync_js_file_size_mismatch' => 'Temporary file "$1" size ($2 {{PLURAL:$2|byte|bytes}}) does not match required size ($3 {{PLURAL:$3|byte|bytes}}). Make sure the file "$4" was not manually overwritten in repository of source wiki.',
 77+ 'wikisync_js_invalid_scheduler_time' => 'Scheduler time must be a positive integer number',
 78+ 'wikisync_js_scheduler_countdown' => '$1 {{PLURAL:$1|minute|minutes}} left',
 79+ 'wikisync_js_sync_start_ltr' => 'Starting the synchronization from local wiki to remote wiki at $1',
 80+ 'wikisync_js_sync_start_rtl' => 'Starting the synchronization from remote wiki to local wiki at $1',
 81+ 'wikisync_js_sync_end_ltr' => 'Finished the synchronization from local wiki to remote wiki at $1',
 82+ 'wikisync_js_sync_end_rtl' => 'Finished the synchronization from remote wiki to local wiki at $1',
7083 );
7184
 85+
7286 /** Message documentation (Message documentation)
7387 * @author Тест
7488 */
@@ -518,6 +532,12 @@
519533 'wikisync_local_root' => 'Корневой адрес локального сайта',
520534 'wikisync_remote_root' => 'Корневой адрес удалённого сайта',
521535 'wikisync_remote_log' => 'Журнал удалённых действий',
 536+ 'wikisync_scheduler_log' => 'Журнал планировщика',
 537+ 'wikisync_scheduler_setup' => 'Настройки планировщика',
 538+ 'wikisync_scheduler_turn_on' => 'Включить планировщик',
 539+ 'wikisync_scheduler_switch_direction' => 'Автоматически изменять направление синхронизации',
 540+ 'wikisync_scheduler_time_interval' => 'Количество минут между автоматическими синхронизациями',
 541+ 'wikisync_apply_button' => 'Применить',
522542 'wikisync_clear_log' => 'Очистить журнал',
523543 'wikisync_login_to_remote_wiki' => 'Зайти на удалённый сайт',
524544 'wikisync_remote_wiki_root' => 'Корневой адрес удалённого сайта',
@@ -526,6 +546,7 @@
527547 'wikisync_remote_wiki_pass' => 'Пароль на удалённом сайте',
528548 'wikisync_remote_login_button' => 'Зайти',
529549 'wikisync_sync_files' => 'Синхронизировать файлы',
 550+ 'wikisync_store_password' => 'Сохранить пароль удалённого сайта',
530551 'wikisync_synchronization_button' => 'Синхронизировать',
531552 'wikisync_log_imported_by' => 'Импортировано с помощью [[Special:WikiSync]]',
532553 'wikisync_log_uploaded_by' => 'Загружено с помощью [[Special:WikiSync]]',
@@ -552,7 +573,13 @@
553574 'wikisync_js_sync_to_itself' => 'Невозможно синхронизировать вики сайт сам в себя',
554575 'wikisync_js_diff_search' => 'Поиск отличий в ревизиях вики-сайта назначения',
555576 'wikisync_js_revision' => 'Ревизия $1',
556 - 'wikisync_js_file_size_mismatch' => 'Размер временного файла $1 ($2 байт) не соответствует требуемому размеру файла ($3 байт). Пожалуйста убедитесь, что файл $4 не был переписан вручную в репозиторий исходного вики-сайта.',
 577+ 'wikisync_js_file_size_mismatch' => 'Размер временного файла "$1" ($2 {{PLURAL:$2|байт|байта|байтов}}) не соответствует требуемому размеру файла ($3 {{PLURAL:$3|байт|байта|байтов}}). Пожалуйста убедитесь, что файл "$4" не был переписан вручную в репозиторий исходного вики-сайта.',
 578+ 'wikisync_js_invalid_scheduler_time' => 'Время планировщика должно быть положительным целым числом',
 579+ 'wikisync_js_scheduler_countdown' => 'Осталось $1 {{PLURAL:$1|минута|минуты|минут}}',
 580+ 'wikisync_js_sync_start_ltr' => 'Запуск синхронизации с локального вики-сайта на удалённый $1',
 581+ 'wikisync_js_sync_start_rtl' => 'Запуск синхронизации с удалённого вики-сайта на локальный $1',
 582+ 'wikisync_js_sync_end_ltr' => 'Окончание синхронизации с локального вики-сайта на удалённый $1',
 583+ 'wikisync_js_sync_end_rtl' => 'Окончание синхронизации с удалённого вики-сайта на локальный $1',
557584 );
558585
559586 /** Telugu (తెలుగు)
@@ -579,4 +606,3 @@
580607 'wikisync_js_sync_to_itself' => 'Ви не можете синхронізувати вікі саму до себе',
581608 'wikisync_js_revision' => 'Версія $1',
582609 );
583 -
Index: trunk/extensions/WikiSync/INSTALL
@@ -1,4 +1,4 @@
2 -MediaWiki extension WikiSync, version 0.2.1
 2+MediaWiki extension WikiSync, version 0.3.1
33
44 * download the latest available version and extract it to your wiki extension directory.
55 * add the following line to LocalSettings.php
Index: trunk/extensions/WikiSync/WikiSync.js
@@ -27,16 +27,99 @@
2828 * * Add this line at the end of your LocalSettings.php file :
2929 * require_once "$IP/extensions/WikiSync/WikiSync.php";
3030 *
31 - * @version 0.2.1
 31+ * @version 0.3.1
3232 * @link http://www.mediawiki.org/wiki/Extension:WikiSync
3333 * @author Dmitriy Sintsov <questpc@rambler.ru>
3434 * @addtogroup Extensions
3535 */
3636
 37+window.WikiSyncScheduler = {
 38+
 39+ // {{{ automatical synchronization settings
 40+ isOn: false,
 41+ switchDirection : false,
 42+ timeout : 300, // default timeout: amount of 1/10 of minutes (30 minutes)
 43+ currTimeout : 300, // current timeout: amount of 1/10 of minutes (30 minutes)
 44+ pollTimeout : 6000, // polling once per 1/10 of minute (setTimeout value in milliseconds)
 45+ // }}}
 46+
 47+ counterNode : null, // DOM object which inner text node will contain countdown number
 48+ syncButton : null, // DOM object input which 'disabled' property indicates that
 49+ // synchronization is already going (scheduling is impossible)
 50+
 51+ setup : function( form ) {
 52+ this.counterNode = document.getElementById( 'ws_scheduler_countdown' );
 53+ this.syncButton = document.getElementById( 'wikisync_synchronization_button' );
 54+ var timeInterval = form.ws_auto_sync_time_interval;
 55+ if ( timeInterval.value == '' ) {
 56+ timeInterval.value = this.timeout;
 57+ }
 58+ var time = parseInt( timeInterval.value );
 59+ if ( isNaN( time ) || time <= 0 ) {
 60+ alert( WikiSync.formatMessage( 'invalid_scheduler_time' ) );
 61+ return false;
 62+ }
 63+ time *= 10; // form has value in minutes; poll will use value in 1/10 of minutes
 64+ this.isOn = form.ws_auto_sync.checked;
 65+ WikiSyncUtils.setCookie( 'auto_sync', this.isOn, WikiSync.cookieExpireTime, '/' );
 66+ this.switchDirection = form.ws_auto_switch_direction.checked;
 67+ WikiSyncUtils.setCookie( 'auto_switch_direction', this.switchDirection, WikiSync.cookieExpireTime, '/' );
 68+ this.timeout = time;
 69+ WikiSyncUtils.setCookie( 'auto_sync_time_interval', timeInterval.value, WikiSync.cookieExpireTime, '/' );
 70+ this.reset();
 71+ return false;
 72+ },
 73+
 74+ reset : function() {
 75+ this.currTimeout = this.timeout;
 76+ this.displayCounter();
 77+ },
 78+
 79+ displayCounter : function() {
 80+ if ( this.isOn && !this.syncButton.disabled ) {
 81+ // display current timeout
 82+ var textNode = document.createTextNode( WikiSync.formatMessage( 'scheduler_countdown', Math.ceil( this.currTimeout / 10 ) ) );
 83+ if ( this.counterNode.firstChild === null ) {
 84+ this.counterNode.appendChild( textNode );
 85+ } else {
 86+ this.counterNode.replaceChild( textNode, this.counterNode.firstChild );
 87+ }
 88+ } else {
 89+ this.counterNode.innerHTML = '';
 90+ }
 91+ },
 92+
 93+ poll : function() {
 94+ if ( !this.isOn ) {
 95+ this.reset();
 96+ } else {
 97+ // scheduler is active
 98+ if ( this.syncButton.disabled ) {
 99+ // not logged in or synchronization is already in progress
 100+ this.reset();
 101+ } else {
 102+ // scheduling is possible (logged in and no sync is already going)
 103+ if ( this.currTimeout > 0 ) {
 104+ // some time is left
 105+ this.displayCounter();
 106+ this.currTimeout--;
 107+ } else {
 108+ // time is out, let's go
 109+ WikiSync.process();
 110+ }
 111+ }
 112+ }
 113+ window.setTimeout( function() { WikiSyncScheduler.poll(); }, this.pollTimeout );
 114+ }
 115+
 116+};
 117+
37118 window.WikiSync = {
38119
39120 _WikiSync : '', // WikiSync context
40121
 122+ cookieExpireTime : 30 * 24 * 60 * 60, // see also WikiSync.php, WikiSync::COOKIE_EXPIRE_TIME
 123+
41124 // by default, synchronize from remote to local
42125 directionToLocal : true,
43126
@@ -101,6 +184,7 @@
102185 // these are not initialized in 1.17+ codepath
103186 localMessages : null,
104187
 188+ // used only when ResourceLoader is not available ( MediaWiki < 1.17)
105189 setLocalMessages : function( localMessages ) {
106190 this.localMessages = localMessages;
107191 },
@@ -109,37 +193,42 @@
110194 // in case of future ResourceLoader adoption in Extension:CategoryBrowser there
111195 // should be few methods with different prefixes instead of just one
112196 var prefix = 'wikisync_js_';
 197+ var formatted;
113198 if ( typeof mediaWiki === 'object' &&
114199 typeof mediaWiki.msg === 'function' ) {
115200 // MW 1.17+
116201 var args = arguments;
117202 args[0] = prefix + args[0];
118 - return mediaWiki.msg.apply( mediaWiki.msg, args );
119 - }
120 - var formatted = this.localMessages[ prefix + arguments[0] ];
121 - var indexes = [];
122 - var pos;
123 - var j;
124 - // gettting $n parameter indexes
125 - // going in reverse order is very important for the second for loop to be correct
126 - for ( var i = arguments.length - 1; i > 0; i-- ) {
127 - if ( ( pos = formatted.indexOf( '$' + i ) ) !== -1 ) {
128 - indexes.push( pos );
 203+ formatted = mediaWiki.msg.apply( mediaWiki.msg, args );
 204+ // probably will not be required when mediaWiki.msg will support plurals
 205+ // todo: figure out how to call replace before msg.apply
 206+ formatted = formatted.replace( /{{PLURAL:.+?\|(.+?)\|.+?}}/g, '$1' );
 207+ } else {
 208+ // MW < 1.17
 209+ formatted = this.localMessages[ prefix + arguments[0] ];
 210+ // replace plurals to their singular values
 211+ // implementing something better is not so easy task, because plurals vary between languages
 212+ formatted = formatted.replace( /{{PLURAL:.+?\|(.+?)\|.+?}}/g, '$1' );
 213+ var indexes = [];
 214+ var pos;
 215+ var j;
 216+ // getting $n parameter indexes
 217+ // going in reverse order is very important for the second for loop to be correct
 218+ for ( var i = arguments.length - 1; i > 0; i-- ) {
 219+ if ( ( pos = formatted.indexOf( '$' + i ) ) !== -1 ) {
 220+ indexes.push( pos );
 221+ }
129222 }
 223+ // substituting the parameters
 224+ for ( i = 0; i < indexes.length; i++ ) {
 225+ pos = indexes[i];
 226+ j = formatted.charAt( pos + 1 );
 227+ formatted = formatted.slice( 0, pos ) + arguments[j] + formatted.slice( pos + 2 );
 228+ }
130229 }
131 - // substituting the parameters
132 - for ( i = 0; i < indexes.length; i++ ) {
133 - pos = indexes[i];
134 - j = formatted.charAt( pos + 1 );
135 - formatted = formatted.slice( 0, pos ) + arguments[j] + formatted.slice( pos + 2 );
136 - }
137230 return formatted;
138231 },
139232
140 - mathLogBase : function( x, base ) {
141 - return Math.log( x ) / Math.log( base );
142 - },
143 -
144233 showIframe : function( url ) {
145234 var text = document.createTextNode( url );
146235 var locElem = document.getElementById( 'wikisync_iframe_location' );
@@ -153,24 +242,12 @@
154243 iframe.src = url;
155244 },
156245
157 - log : function( s, color, type ) {
158 - var logContainer = document.getElementById( 'wikisync_remote_log' );
159 - var span = document.createElement( 'SPAN' );
160 - if ( typeof s === 'object' ) {
161 - s = JSON.stringify( s );
 246+ log : function() {
 247+ // sometimes, when user clicks the "Log in" button too fast,
 248+ // operationLogger might be still uninitialized in onloadHandler
 249+ if ( typeof this.operationLogger !== 'undefined' ) {
 250+ this.operationLogger.log.apply( this.operationLogger, arguments );
162251 }
163 - if ( typeof type !== 'undefined' ) {
164 - var b = document.createElement( 'B' );
165 - b.appendChild( document.createTextNode( type + ': ' ) );
166 - span.appendChild( b );
167 - }
168 - span.appendChild( document.createTextNode( s ) );
169 - if ( typeof color !== 'undefined' ) {
170 - span.style.color = color;
171 - }
172 - logContainer.appendChild( span );
173 - logContainer.appendChild( document.createElement( 'HR' ) );
174 - logContainer.scrollTop = logContainer.scrollHeight;
175252 },
176253
177254 sourceLog : function( s, type ) {
@@ -189,11 +266,6 @@
190267 this.log( s, 'maroon', t );
191268 },
192269
193 - clearLog : function() {
194 - document.getElementById( 'wikisync_remote_log' ).innerHTML = '';
195 - return false;
196 - },
197 -
198270 error : function( s, type ) {
199271 if ( typeof type !== 'undefined' ) {
200272 this.log( s, 'red', type );
@@ -202,7 +274,12 @@
203275 }
204276 },
205277
206 - setDirection : function( eventObj ) {
 278+ clearLog : function( id ) {
 279+ document.getElementById( id ).innerHTML = '';
 280+ return false;
 281+ },
 282+
 283+ switchDirection : function( eventObj ) {
207284 eventObj.blur();
208285 if ( this.directionToLocal = !this.directionToLocal ) {
209286 eventObj.value = '<=';
@@ -212,43 +289,36 @@
213290 return false;
214291 },
215292
216 - setSyncFiles : function( eventObj ) {
 293+ blurElement : function( eventObj ) {
217294 eventObj.blur();
218 - this.syncFiles = eventObj.checked;
219295 return false;
220296 },
221297
222 - remoteRootChange : function( eventObj ) {
223 - var textNode = document.createTextNode( eventObj.value );
224 - var wrr = document.getElementById( 'wikisync_remote_root' );
225 - wrr.replaceChild( textNode , wrr.firstChild );
226 - return false;
227 - },
228 -
229 - submitRemoteLogin : function( form ) {
230 - this.remoteContext.wikiroot = form.remote_wiki_root.value;
231 - this.setSyncFiles( form.ws_sync_files );
232 - sajax_do_call( 'WikiSyncClient::remoteLogin',
233 - [this.remoteContext.wikiroot, form.remote_wiki_user.value, form.remote_wiki_pass.value],
234 - WikiSync.remoteLogin );
235 - return false;
236 - },
237 -
238 - /*
239 - * initializes everything in remoteContext except of wikiroot
 298+ /**
 299+ * called when synchronization was done succesfully
240300 */
241 - setRemoteContext : function( login ) {
242 - this.remoteContext.userid = login.userid;
243 - this.remoteContext.username = login.username;
244 - this.remoteContext.logintoken = login.token;
245 - this.remoteContext.cookieprefix = login.cookieprefix;
246 - this.remoteContext.sessionid = login.sessionid;
 301+ successHandler : function( msg ) {
 302+ // enable all buttons
 303+ this.schedulerLogger.log(
 304+ this.formatMessage(
 305+ this.directionToLocal ? 'sync_end_rtl' : 'sync_end_ltr',
 306+ WikiSyncUtils.getLocalDate()
 307+ )
 308+ );
 309+ this.setButtons( true );
 310+ // check, whether new scheduling is needed
 311+ if ( WikiSyncScheduler.isOn ) {
 312+ // do not make operation log grew too long
 313+ // with automatical sycnronizations
 314+ this.operationLogger.clear();
 315+ if ( WikiSyncScheduler.switchDirection ) {
 316+ this.switchDirection( document.getElementById( 'wikisync_direction_button' ) );
 317+ }
 318+ } else {
 319+ alert( msg );
 320+ }
247321 },
248322
249 - getResponseError : function( request ) {
250 - return 'status=' + request.status + ', text=' + request.responseText;
251 - },
252 -
253323 /**
254324 * enables or disables UI buttons
255325 * arguments[0] - boolean true to disable selected buttons, false to enable
@@ -272,7 +342,38 @@
273343 }
274344 },
275345
 346+ remoteRootChange : function( eventObj ) {
 347+ var textNode = document.createTextNode( eventObj.value );
 348+ var wrr = document.getElementById( 'wikisync_remote_root' );
 349+ wrr.replaceChild( textNode , wrr.firstChild );
 350+ return false;
 351+ },
 352+
276353 /*
 354+ * initializes everything in remoteContext except of wikiroot
 355+ */
 356+ setRemoteContext : function( login ) {
 357+ this.remoteContext.userid = login.userid;
 358+ this.remoteContext.username = login.username;
 359+ this.remoteContext.logintoken = login.token;
 360+ this.remoteContext.cookieprefix = login.cookieprefix;
 361+ this.remoteContext.sessionid = login.sessionid;
 362+ },
 363+
 364+ getResponseError : function( request ) {
 365+ return 'status=' + request.status + ', text=' + request.responseText;
 366+ },
 367+
 368+ submitRemoteLogin : function( form ) {
 369+ this.remoteContext.wikiroot = form.remote_wiki_root.value;
 370+ this.syncFiles = form.ws_sync_files.checked;
 371+ sajax_do_call( 'WikiSyncClient::remoteLogin',
 372+ [this.remoteContext.wikiroot, form.remote_wiki_user.value, form.remote_wiki_pass.value, form.ws_store_password.checked],
 373+ WikiSync.remoteLogin );
 374+ return false;
 375+ },
 376+
 377+ /*
277378 * @param request.responsetext - login "final" response
278379 */
279380 remoteLogin : function( request ) {
@@ -709,7 +810,8 @@
710811 case 'start' :
711812 this.srcSyncId = operation.revid;
712813 this.showIframe( this.srcWikiRoot + '/index.php?oldid=' + operation.revid );
713 - if ( !confirm( this.formatMessage( 'synchronization_confirmation', this.srcWikiRoot, this.dstWikiRoot, operation.revid ) ) ) {
 814+ if ( !WikiSyncScheduler.isOn &&
 815+ !confirm( this.formatMessage( 'synchronization_confirmation', this.srcWikiRoot, this.dstWikiRoot, operation.revid ) ) ) {
714816 this.log( 'Operation was cancelled' );
715817 this.syncPercents.reset();
716818 // enable all buttons
@@ -770,9 +872,8 @@
771873 case 'success' :
772874 this.filesPercents.setVisibility( false );
773875 this.syncPercents.display( { 'desc' : '', 'curr' : 'max' } );
774 - alert( this.formatMessage( 'synchronization_success' ) );
 876+ this.successHandler( this.formatMessage( 'synchronization_success' ) );
775877 // enable all buttons
776 - this.setButtons( true );
777878 return;
778879 }
779880 },
@@ -843,9 +944,7 @@
844945 // binary search is complete
845946 this.syncPercents.display( { 'desc' : '', 'curr' : 'max' } );
846947 if ( this.srcHiId === this.srcLastId && matches > 0 ) {
847 - alert( this.formatMessage( 'already_synchronized' ) );
848 - // enable all buttons
849 - this.setButtons( true );
 948+ this.successHandler( this.formatMessage( 'already_synchronized' ) );
850949 return;
851950 }
852951 this.log( 'Synchronizing from ' + this.srcHiId );
@@ -921,7 +1020,7 @@
9221021 this.srcLastId = this.srcHiId = parseInt( this.popAJAXresult( 'src_rev_last', ['query', 'revisionhistory', 0, 'revid'] ) );
9231022 // uncomment next line for "live" debugging
9241023 // this.srcLastId = this.srcHiId = 75054;
925 - this.syncPercents.display( { 'desc' : this.formatMessage( 'diff_search' ), 'curr' : 0, 'min' : 0, 'max' : Math.ceil( this.mathLogBase( this.srcLastId - this.srcFirstId, 2 ) ) } );
 1024+ this.syncPercents.display( { 'desc' : this.formatMessage( 'diff_search' ), 'curr' : 0, 'min' : 0, 'max' : Math.ceil( WikiSyncUtils.mathLogBase( this.srcLastId - this.srcFirstId, 2 ) ) } );
9261025 this.findCommonRev( { 'opcode' : 'start' } );
9271026 return;
9281027 }
@@ -946,6 +1045,13 @@
9471046 }
9481047 // disable all buttons
9491048 this.setButtons( false );
 1049+ WikiSyncScheduler.reset();
 1050+ this.schedulerLogger.log(
 1051+ this.formatMessage(
 1052+ this.directionToLocal ? 'sync_start_rtl' : 'sync_start_ltr',
 1053+ WikiSyncUtils.getLocalDate()
 1054+ )
 1055+ );
9501056 this.syncPercents.setVisibility( true );
9511057 /* get first and last source revision in parallel */
9521058 this.getSrcRev( { 'opcode' : 'start' } );
@@ -959,14 +1065,35 @@
9601066 return WikiSync.onloadHandler.call( WikiSync );
9611067 }
9621068 // }}}
 1069+ this.operationLogger = new WikiSyncLog( 'wikisync_remote_log' );
 1070+ this.schedulerLogger = new WikiSyncLog( 'wikisync_scheduler_log' );
9631071 this.syncPercents = new WikiSyncPercentsIndicator( 'wikisync_xml_percents' );
9641072 this.filesPercents = new WikiSyncPercentsIndicator( 'wikisync_files_percents' );
9651073 this.syncPercents.setVisibility( false );
9661074 this.filesPercents.setVisibility( false );
9671075 this.showIframe( '' );
9681076 this.errorDefaultAction();
 1077+ var loginForm = document.getElementById( 'remote_login_form' );
 1078+ // {{{ restore remote login / password cookies to login form, if any
 1079+ WikiSyncUtils.cookieToInput( 'ruser', loginForm.remote_wiki_user );
 1080+ var rpass = WikiSyncUtils.cookieToInput( 'rpass', loginForm.remote_wiki_pass );
 1081+ // }}}
 1082+ // {{{ restore scheduler cookies to scheduler form, if any
 1083+ var schedulerForm = document.getElementById( 'scheduler_form' );
 1084+ WikiSyncUtils.cookieToCheckbox( 'auto_sync', schedulerForm.ws_auto_sync );
 1085+ WikiSyncUtils.cookieToCheckbox( 'auto_switch_direction', schedulerForm.ws_auto_switch_direction );
 1086+ WikiSyncUtils.cookieToInput( 'auto_sync_time_interval', schedulerForm.ws_auto_sync_time_interval );
 1087+ // }}}
 1088+ if ( rpass !== null ) {
 1089+ loginForm.ws_store_password.checked = true;
 1090+ // try to autologin
 1091+ this.submitRemoteLogin( loginForm );
 1092+ }
 1093+ WikiSyncScheduler.setup( schedulerForm );
 1094+ window.setTimeout( function() { WikiSyncScheduler.poll(); }, this.pollTimeout );
9691095 }
9701096
9711097 }
9721098
973 -WikiSyncUtils.addEvent(window,"load", WikiSync.onloadHandler);
 1099+WikiSyncUtils.setCookiePrefix( wgDBname + '_wiki_WikiSync_' + WikiSync_md5.hex( wgUserName ) + '_' );
 1100+WikiSyncUtils.addEvent( window, "load", WikiSync.onloadHandler );

Comments

#Comment by Raymond (talk | contribs)   20:06, 9 November 2010

It seems you have overwritten my i18n consistency tweaks from r75867. Accident or a special reason?

#Comment by QuestPC (talk | contribs)   06:54, 10 November 2010

I've preserved WikiSync.alias.php. However, I've rewrote about two 'en' messages accidently, due to "internal" merge of two versions - scheduler and this one. Now I'll commit your messages back.

#Comment by Raymond (talk | contribs)   07:42, 10 November 2010

Thanks for fixing with r76433.

Status & tagging log