User:PhiLiP/iWiki.js

维基百科,自由的百科全书

注意:保存之后,你必须清除浏览器缓存才能看到做出的更改。Google ChromeFirefoxMicrosoft EdgeSafari:按住⇧ Shift键并单击工具栏的“刷新”按钮。参阅Help:绕过浏览器缓存以获取更多帮助。

( function( $, mw ) {

	var pass = function() {};

	mw.api = {
		/* cache */
		cache : {},
		
		normalized : {},
		
		/**
		 * Send an API request to server and retrieve the result
		 *
		 * @param query: the query to be sent
		 * @param ready: optional, callback function when API response is ready for using
		 */
		request : function( method, query, ready ) {
			if ( typeof method != 'string' || !$.inArray( method, ['get', 'post'] ) ) {
				ready = query;
				query = method;
				method = 'get';
			}
			ready = ready || pass;
			query.format = 'json';
			$[method]( wgScriptPath + '/api.php', query, ready, 'json' );
		},
		
		/**
		 * Get raw text of pages
		 *
		 * @param pages: require page(s), string or array
		 * @param ready: optional, callback function receive raw content
		 * @param purge: purge the cache? boolean
		 */
		raw : function( pages, ready, purge ) {
			if ( typeof pages == 'string' ) {
				pages = [pages];
			}
			if ( typeof ready == 'boolean' ) {
				purge = ready;
				ready = pass;
			}
			ready = ready || pass;
			purge = purge || false;
			
			var _raw_from_cache = function( pages ) {
				var ret = {};
				var pagelen = pages.length;
				for ( var id = 0; id < pagelen; id ++ ) {
					var page = pages[id];
					var title = mw.api.normalized[page] || page;
					if ( typeof mw.api.cache[title] == 'object' ) {
						ret[page] = mw.api.cache[title]['*'];
					}
				}
				return ret;
			}
			
			var ready_data = {};
			var titles = [];
			
			if ( !purge ) {
				$.extend( ready_data, _raw_from_cache( pages ) );
				var pagelen = pages.length;
				for ( var id = 0; id < pagelen; id ++ ) {
					var page = pages[id];
					if ( !ready_data[page] ) {
						titles.push( page );
					}
				}
			} else {
				titles = pages;
			}
			
			if ( titles.length ) {
				mw.api.request(
					{ 'action' : 'query', 'prop' : 'revisions',
					'titles' : titles.join( '|' ), 'rvprop' : 'timestamp|content' },
					function( data ) {
						if ( data.query.normalized ) {
							normlen = data.query.normalized.length;
							for ( var normid = 0; normid < normlen; normid ++ ) {
								var norm = data.query.normalized[normid];
								mw.api.normalized[norm.from] = norm.to;
							}
						}
						for ( var pageid in data.query.pages ) {
							var page = data.query.pages[pageid];
							var cache = mw.api.cache[page.title] = {};
							cache.missing = pageid < 0;
							if ( cache.missing ) {
								cache.timestamp = null;
								cache['*'] = null;
							} else {
								$.extend( cache, page.revisions[0] );
							}
						}
						
						$.extend( ready_data, _raw_from_cache( titles ) );
						ready( ready_data );
					}
				);
			} else {
				ready( ready_data );
			}
		},
		
		/**
		 * Edit a page with content
		 */
		edit : function( page, text, summary, ready ) {
			page = mw.api.normalized[page] || page;
			
			if ( typeof summary == 'function' ) {
				ready = summary;
				summary = '';
			} else {
				summary = summary || '';
				ready = ready || pass;
			}
			
			// request an edit token
			mw.api.request( { 'action' : 'query', 'prop' : 'info', 'intoken' : 'edit', 'titles' : page },
				function( data ) {
					var token = '';
					var starttimestamp = '';
					for ( var pageid in data.query.pages ) {
						token = data.query.pages[pageid].edittoken;
						starttimestamp = data.query.pages[pageid].starttimestamp;
					}
					
					var query = { 'action' : 'edit', 'title' : page, 'starttimestamp' : starttimestamp,
						'summary' : summary, 'text' : text, 'token' : token };
					if ( mw.api.cache[page] ) {
						// use basetimestamp to prevent edit conflict
						query.basetimestamp = mw.api.cache[page].timestamp;
					}
					
					mw.api.request( 'post', query, ready );
				}
			);
		},
		
		/**
		 * Parse a page content
		 */
		parse : function( page, variant, ready ) {
			if ( typeof variant == 'function' ) {
				ready = variant;
				variant = window.wgUserVariant || false;
			} else {
				ready = ready || pass;
				variant = variant || window.wgUserVariant || false;
			}
			
			var query = { 'action' : 'parse', 'page' : page }
			if ( variant ) {
				query.variant = variant;
			}
			mw.api.request( query, function( data ) {
				ready( data.parse.text['*'], data.parse.displaytitle, data.parse.links );
			} );
		}
	};

	window.iWiki = function() {
		
		if ( wgPageName != wgMainPageTitle || wgAction != 'view' ) {
			return;
		}
		
		var self = this;
		var edited = false;
		
		this.debug_create = function() {
			self.config.set( 'columns', [{
				'style' : 'width: 60%',
				'templates' : ['feature', 'itn', 'good', 'dyk', 'otd', 'featurepic']
			}, {
				'style' : 'width: 37%',
				'templates' : ['welcome', 'participate', 'community', 'knowledge', 'projects', 'donation']
			}] );
			self.config.update();
		}
		
		var init = function() {
			start();
		};
		
		/* Replace the main page content to user content */
		var start = function() {
			var is_global = self.config.get( 'is_global', false );
			//var elements = self.config.get( 'elements', [] );
			var page = is_global ? self.config.site_content : self.config.user_content;
			mw.api.parse( page, function( parsed ) {
				var removeit = false;
				mw.util.$content.children().each( function() {
					var el = $( this );
					if ( removeit ) {
						if ( el.hasClass( 'printfooter' ) ) {
							removeit = false;
						} else {
							el.remove();
						}
					} else {
						if ( el.attr( 'id' ) == 'jump-to-nav' ) {
							removeit = true;
						}
					}
				} );
				$( '#jump-to-nav', mw.util.$content ).after( parsed );
				
				if ( !$( '#p-iwiki' ).length ) {
					// add the iWiki button
					mw.util.addPortletLink(
						'p-views', '#', 'iWiki', 'p-iwiki',	'Configure iWiki', 'i', '#ca-history'
					);
				}
				
				$( '#p-iwiki' ).unbind( 'click' ).click( enableEdit );
			} );

		};
		
		var enableEdit = function() {
			self.config.load( function() {
				$( '.iwiki-column' ).sortable( {
					'connectWith' : '.iwiki-column',
					'opacity' : 0.6,
					'update' : function() {
						self.edited = true;
					}
				} ).addClass( 'iwiki-column-editable' );
			} );
			$( '#p-iwiki' ).unbind( 'click' ).click( disableEdit );
		};
		
		var disableEdit = function() {
			if ( self.edited && confirm( 'Your changes hasn\'t been saved, do you want to save it?' ) ) {
				var columns = [];
				$( '.iwiki-column' ).removeClass( 'iwiki-column-editable' ).each( function() {
					var col = $( this );
					var column = {};
					column.style = col.attr( 'style' );
					column.templates = [];
					$( '.iwiki-portlet', col ).each( function() {
						column.templates.push( $( this ).attr( 'id' ).slice( 6 ) );
					} );
					columns.push( column );
				} );
				self.config.set( 'columns', columns );
				self.config.update( start );
			} else {
				start();
			}
		};
		
		/**
		 * Load a jsonp script and excute a callback
		 * mw.loader.load doesn't provide readiness support yet, so I can only create it by myself.
		 *
		 * @param page: the wiki page's name
		 * @param ready: callback function
		 */
		var jsonp = function( page, ready ) {
			ready = ready || pass;
			$.ajax( {
				'url' : wgScript + '?title=' + mw.util.wikiUrlencode( page ) + '&action=raw&ctype=text/javascript',
				'dataType' : 'jsonp', 'success' : ready, 'jsonpCallback' : 'iWiki_jsonp'
			} );
		}
		
		this.config = {
			
			/* using JsSubpage to store user config because it can not be edited by others except admins */
			user_config : wgFormattedNamespaces[2] + ':' + wgUserName + '/iWiki-config.js',
			site_config : /*wgFormattedNamespaces[8] + ':' + 'iWiki-config.js'*/'User:PhiLiP/iWiki-config.js',
			user_content : wgFormattedNamespaces[2] + ':' + wgUserName + '/iWiki-content.js',
			site_content : /*wgFormattedNamespaces[8] + ':' + 'iWiki-content'*/'User:PhiLiP/iWiki-content.js',
			data : {},
			
			/**
			 * Load a default/user configure
			 *
			 * @param ready: callback function
			 */
			load : function( ready ) {
				ready = ready || pass;
				var page = self.config.user_config;
				
				// query if the user configure exist
				mw.api.request( { 'action' : 'query', 'prop' : 'info', 'titles' : page },
					function ( data ) {
						if ( data.query.pages[-1] ) {
							// user configure not exist, load the default one
							page = self.config.site_config;
						}
						jsonp( page, function( data ) {
							self.config.data = data;
							ready();
						} );
					}
				);
			},
		
			/**
			 * Update the user configure
			 *
			 * @param ready: callback function
			 */
			update : function( ready ) {
				ready = ready || pass;
				
				var readyCount = 0;
				var _ready = function( data ) {
					readyCount ++;
					if ( readyCount == 2 ) {
						ready( data );
					}
				};
				mw.api.edit( self.config.user_config,
					"iWiki_jsonp(" + JSON.stringify( self.config.data ) + ");",
					'iWiki: Update user configure.', _ready
				);
				mw.api.edit( self.config.user_content,
					self.config.parse(), 'iWiki: Update user content.', _ready
				);
			},
		
			/**
			 * Parse configure wikitext
			 *
			 * @return string: wikitext
			 */
			parse : function() {
				var columns = self.config.get( 'columns', [] );
				var text = '__NOTOC__ __NOEDITSECTION__<div class="iwiki-header">{{:User:PhiLiP/iWiki/header}}</div>\n';
				var collen = columns.length;
				for ( var colid = 0; colid < collen; colid ++ ) {
					var column = columns[colid];
					if ( column.style ) {
						text += '<div class="iwiki-column" style="' + column.style + '">\n';
					} else {
						text += '<div class="iwiki-column">\n';
					}
					var tplen = column.templates.length;
					for ( var tplid = 0; tplid < tplen; tplid ++ ) {
						var tpl = column.templates[tplid];
						text += '\t<div id="iwiki-' + tpl + '" class="iwiki-portlet">';
						text += '{{:User:PhiLiP/iWiki/' + tpl + '}}';
						text += '</div>\n';
					}
					text += '</div>\n';
				}
				text += '<div class="iwiki-footer">{{:User:PhiLiP/iWiki/footer}}</div>\n';
				return text;
			},
		
			get : function( name, fallback ) {
				fallback = fallback || null;
				if ( typeof self.config.data[name] != 'undefined' ) {
					return self.config.data[name];
				} else {
					return fallback;
				}
			},
		
			set : function( name, value ) {
				self.config.data[name] = value;
			},
		
			unset : function( name, value ) {
				delete self.config.data[name];
			}
		};
		
		$( init );
	};

	mw.loader.using( 'jquery.ui', function() {
		window.iw = new iWiki();
	} );

	/* iWiki.debug_init = function() {
		mw.loader.using( 'jquery.ui', function() {
			window.iw = new iWiki();
		} );
	};*/

} )( jQuery, mediaWiki );