|
|
Line 1: |
Line 1: |
| // Modded version of http://en.wikipedia.org/wiki/User:Lupin/editcount.js by Elliott.
| |
| /** <nowiki>
| |
| * A javascript edit counter, using query.php as the backend
| |
| *
| |
| */
| |
|
| |
|
| //<pre>
| |
|
| |
| ec = {
| |
|
| |
| getParamValue: function(paramName) {
| |
| var cmdRe=RegExp('[&?]'+paramName+'=([^&]*)');
| |
| var h=document.location;
| |
| var m;
| |
| if (m=cmdRe.exec(h)) {
| |
| try {
| |
| while(m[1].indexOf('+')!=-1)
| |
| {
| |
| m[1]=m[1].substr(0,m[1].indexOf('+'))+" "+m[1].substr(m[1].indexOf('+')+1);
| |
| }
| |
| return decodeURIComponent(m[1]);
| |
| } catch (someError) {}
| |
| }
| |
| return null;
| |
| },
| |
|
| |
| doEditCount: function(user) {
| |
| if (!user) { return; }
| |
| ec.user=user;
| |
| ec.makeEditCountDivs();
| |
| ec.getContribs(user);
| |
| setTimeout(ec.checkContribs, 1000);
| |
| },
| |
| makeEditCountDivs: function() {
| |
| var d=document.createElement('div');
| |
| d.id='editcount_output';
| |
| ec.appendDivs(d, [ 'editcount_title', 'editcount_intervalselector',
| |
| 'editcount_stats' ]);
| |
| var h=document.getElementById('siteSub');
| |
| h.parentNode.insertBefore(d, h.nextSibling);
| |
| },
| |
| appendDivs: function(parent, list) {
| |
| for (var i=0; i<list.length; ++i) {
| |
| var d=document.createElement('div');
| |
| d.id=list[i];
| |
| parent.appendChild(d);
| |
| }
| |
| },
| |
|
| |
| checkContribs: function() {
| |
| if (ec.complete) {
| |
| ec.doOutput();
| |
| } else {
| |
| ec.doStatus();
| |
| setTimeout(ec.checkContribs, 1000);
| |
| }
| |
| },
| |
|
| |
| doOutput: function(start, end) {
| |
| var d=document.getElementById('editcount_stats');
| |
| if (!ec.count) {
| |
| d.innerHTML='No edits found for ' + ec.user;
| |
| return;
| |
| }
| |
| if (!this.intsel) {
| |
| this.intsel = new IntervalSelector({
| |
| min: ts2unix(this.editlist.first.next.key),
| |
| max: ts2unix(this.editlist.last.prev.key)});
| |
| var this2=this;
| |
| this.intsel.doneDrag=function() {
| |
| //document.title=[this.lo, this.hi];
| |
| this2.doOutput.apply(this2, map(unix2ts, [this.lo, this.hi]));
| |
| };
| |
| this.intsel.dragging=function() {
| |
| var start=unix2ts(this2.intsel.lo);
| |
| var end=unix2ts(this2.intsel.hi);
| |
| document.getElementById('editcount_range').innerHTML=
| |
| formatTs(start) + ' - ' + formatTs(end);
| |
| };
| |
| //this.intsel.dragging=this.intsel.doneDrag; // too slow - pretty cool tho
| |
| var intdiv=document.getElementById('editcount_intervalselector');
| |
| intdiv.appendChild(this.intsel.box);
| |
| this.appendDivs(intdiv, ['editcount_range']);
| |
| this.intsel.dragging();
| |
| this.intseldebug=document.createElement('div');
| |
| this.intsel.box.parentNode.insertBefore(this.intseldebug, this.intsel.box);
| |
| }
| |
| document.getElementById('editcount_title').innerHTML=ec.outputHeading();
| |
| document.getElementById('editcount_stats').innerHTML='<p>Total: ' +
| |
| ec.countFigure() + '<br>First edit: ' + ec.firstEdit.replace(/[TZ]/g, ' ') +
| |
| '(UTC)' + ec.statsTable(start, end);
| |
| },
| |
|
| |
| outputHeading: function() {
| |
| return '<h2>Edit count for ' + ec.user + '</h2>';
| |
| },
| |
|
| |
| doStatus: function() {
| |
| var d=document.getElementById('editcount_stats');
| |
| d.innerHTML=ec.outputHeading() + '<p>Downloaded ' + ec.countFigure() + ' so far' + ec.statsTable();
| |
| },
| |
|
| |
| countFigure: function() {
| |
| return ec.count + ' edits over ' + objSum(ec.namespaces, 'articleCount') + ' pages';
| |
| },
| |
|
| |
| findEdit: function(timestamp, up) { // this is very broken - FIXME!
| |
| if (up) {
| |
| var e=this.editlist.first;
| |
| while(e.key<timestamp && (e=e.next)){};
| |
| //console.log('findEdit, up: got '+timestamp+', found '+(e.prev && e.prev.key || null) );
| |
| return e.prev;
| |
| } else {
| |
| var e=this.editlist.last;
| |
| while(e.key>timestamp && (e=e.prev)){}
| |
| //console.log('findEdit, down: got '+timestamp+', found '+(e.next && e.next.key || null) );
| |
| return e.next;
| |
| }
| |
| },
| |
|
| |
| statsTable: function(start, end) {
| |
| //console.log('start: '+start + ', end: '+end);
| |
| var barTotal=400;
| |
| var endEdit=this.findEdit(end) || this.editlist.last;
| |
| var startEdit=this.findEdit(start,true);
| |
| if (!startEdit || !startEdit.key) { startEdit=this.editlist.first.next; }
| |
| //console.log('endEdit:' + endEdit.key);
| |
| //console.log('startEdit:'+ startEdit.key);
| |
| var sumValue=function(val) {
| |
| return objSum(startEdit.stats, val) - objSum(endEdit.stats, val);
| |
| }
| |
| var total=sumValue('count');
| |
| if (!total) { return ''; }
| |
| var statValue=function(k, val) {
| |
| if (!startEdit.stats[k]) { return 0; }
| |
| var r=startEdit.stats[k][val];
| |
| //console.log(k + ' ' + val + ': ' + r);
| |
| if (!endEdit.stats[k] || !endEdit.stats[k][val]) { return r; }
| |
| return r - endEdit.stats[k][val];
| |
| };
| |
| // FIXME: abstract this away so it's trivial to add new columns
| |
| r='<p>Statistics between '+formatTs(startEdit.key) + ' and '+formatTs(endEdit.key);
| |
| r+='<table><tr><th>' + ['Namespace',
| |
| 'New',
| |
| 'Minor',
| |
| 'Top',
| |
| 'Summaries',
| |
| '(manual)',
| |
| 'Pages',
| |
| 'Count', '%'].join('</th><th>') + '</th></tr>';
| |
| for (var k in ec.namespace_names) {
| |
| if (!ec.namespaces[k]) { continue; }
| |
| r += '<tr><td>'+[ec.namespace_names[k],
| |
| statValue(k, 'newCount'),
| |
| statValue(k, 'minorCount'),
| |
| statValue(k, 'topCount'),
| |
| statValue(k, 'commentCount'),
| |
| statValue(k, 'manualCommentCount'),
| |
| statValue(k, 'articleCount'),
| |
| statValue(k, 'count'),
| |
| percent(statValue(k, 'count'), total)].join('</td><td>') + '</td>';
| |
| r+=ec.ecBar(barTotal, total, statValue(k, 'count'), statValue(k, 'minorCount') || 0);
| |
| r+='</tr>';
| |
| }
| |
| var totalMinor = sumValue('minorCount');
| |
| r+='<tr><td>'+['<b>Total</b>',
| |
| sumValue('newCount'),
| |
| totalMinor,
| |
| sumValue('topCount'),
| |
| sumValue('commentCount'),
| |
| sumValue('manualCommentCount'),
| |
| sumValue('articleCount'),
| |
| sumValue('count'),
| |
| '100'].join('</td><td>') + '</td>';
| |
| r+=ec.ecBar(barTotal, total, sumValue('count'), totalMinor);
| |
| r+='</table>';
| |
| return r;
| |
| },
| |
|
| |
| histogramBar: function(value, scale, colour, hint) {
| |
| var height='2ex';
| |
| var style='height: '+ height;
| |
| style += '; background: ' + colour;
| |
| style += '; width: ' + value * scale + 'px';
| |
| style += '; float: left;';
| |
| return '<span style="' + style + '" title="' + hint + '"></span>';
| |
| },
| |
|
| |
| histogramCell: function(scale, values) {
| |
| var r='<td><div style="width: ' + scale + 'px;">';
| |
| for (var i=0; i<values.length; i+=3) { r+=ec.histogramBar(values[i], scale, values[i+1], values[i+2]); }
| |
| r+='</div></td>';
| |
| return r;
| |
| },
| |
|
| |
| ecBar: function(scale, total, count, minor) {
| |
| var nonMinorColour='blue';
| |
| var minorColour='#0A3';
| |
| return ec.histogramCell( scale, [(count-minor)/total, nonMinorColour, "non-minor edits",
| |
| minor/total, minorColour, "minor edits"]);
| |
| },
| |
|
| |
| ajax: {
| |
| download:function(bundle) {
| |
| // mandatory: bundle.url
| |
| // optional: bundle.onSuccess (xmlhttprequest, bundle)
| |
| // optional: bundle.onFailure (xmlhttprequest, bundle)
| |
| // optional: bundle.otherStuff OK too, passed to onSuccess and onFailure
| |
|
| |
| var x = window.XMLHttpRequest ? new XMLHttpRequest()
| |
| : window.ActiveXObject ? new ActiveXObject("Microsoft.XMLHTTP")
| |
| : false;
| |
|
| |
| if (x) {
| |
| x.onreadystatechange=function() {
| |
| x.readyState==4 && ec.ajax.downloadComplete(x,bundle);
| |
| };
| |
| x.open("GET",bundle.url,true);
| |
| x.send(null);
| |
| }
| |
| return x;
| |
| },
| |
|
| |
| downloadComplete:function(x,bundle) {
| |
| x.status==200 && ( bundle.onSuccess && bundle.onSuccess(x,bundle) || true )
| |
| || ( bundle.onFailure && bundle.onFailure(x,bundle) || alert(x.statusText));
| |
| }
| |
| },
| |
|
| |
|
| |
| getContribs: function(user, startAt) {
| |
| var limit=500; // currently maximum allowed per page by query.php
| |
| var url='http://wiki.hydrogenaudio.org/query.php?what=usercontribs' +
| |
| '&uccomments' + // enable for edit comment analysis
| |
| '&format=json&uclimit=500&titles=User:'+escape(user);
| |
| if (startAt) { url += '&ucend=' + startAt.replace(/[^0-9]/g, ''); }
| |
| ec.ajax.download({ url: url, user: user,
| |
| startAt: startAt, onSuccess: ec.readContribs,
| |
| limit: limit});
| |
| },
| |
|
| |
| readContribs: function(dl, bundle) {
| |
| window.dl=dl;
| |
| window.bundle=bundle;
| |
| try {
| |
| eval('var jsobj=' + dl.responseText);
| |
| var pages=jsobj.pages;
| |
| var child=ec.anyChild(pages);
| |
| var contribs=child.contributions;
| |
| } catch (summat) {
| |
| throw new Error('Badness happened in readContribs: ' + summat.message);
| |
| return;
| |
| }
| |
| var i=0, j=0;
| |
| var minrev=null;
| |
| for (var c in contribs) {
| |
| ++i;
| |
| var cc=contribs[c];
| |
| if (!minrev || cc.revid < minrev) { minrev = cc.revid; }
| |
| if (ec.edits[cc.revid]) { continue; }
| |
| ++j;
| |
| ec.doStats(cc);
| |
| ec.edits[cc.revid] = cc;
| |
| }
| |
| ec.count += j;
| |
| if (i == bundle.limit && ec.edits[minrev]) {
| |
| ec.getContribs(bundle.user, ec.edits[minrev].timestamp);
| |
| } else {
| |
| ec.complete=true;
| |
| minrev && (ec.firstEdit=ec.edits[minrev].timestamp);
| |
| }
| |
| },
| |
|
| |
| doStats: function (c) {
| |
| var k=c.ns || 0;
| |
| //if (!ec.namespaces[k]) { console.log('New namespace: '+k + ', title=' +c['*'] +
| |
| // ', alleged NS=' + ec.namespace_names[k]); }
| |
| if (!ec.namespaces[k]) { ec.namespaces[k] = {articles: {}}; }
| |
| var n = ec.namespaces[k];
| |
| incr(n, 'count');
| |
| if (!n.articles[c['*']]) { incr(n, 'articleCount'); }
| |
| incr(n.articles, c['*']);
| |
| if (typeof c.minor != 'undefined') { incr(n, 'minorCount'); }
| |
| if (typeof c.top != 'undefined') { incr(n, 'topCount'); }
| |
| if (typeof c['new'] != 'undefined') { incr(n, 'newCount'); }
| |
| if (c.comment) {
| |
| incr(n, 'commentCount');
| |
| if (!RegExp("^/[*].*?[*]/ *$").test(c.comment)) {
| |
| incr(n, 'manualCommentCount');
| |
| }
| |
| }
| |
| this.editlist.add({key: parseInt(c.timestamp.replace(/[^0-9]/g, ''), 10),
| |
| edit: c,
| |
| stats: this.saveStats()});
| |
| // more stuff here, perhaps
| |
| },
| |
|
| |
| saveStats: function() {
| |
| var r={};
| |
| var list=['count', 'articleCount', 'minorCount', 'topCount',
| |
| 'newCount', 'commentCount', 'manualCommentCount'];
| |
| for (var k in ec.namespaces) {
| |
| r[k]=getStuff(ec.namespaces[k],list);
| |
| }
| |
| return r;
| |
| },
| |
|
| |
| anyChild: function(obj) {
| |
| for (var p in obj) {
| |
| return obj[p];
| |
| }
| |
| return null;
| |
| },
| |
|
| |
| edits: {},
| |
| count: 0,
| |
| complete: false,
| |
| namespaces: {},
| |
| namespace_names: {0: 'Article', 1: 'Talk',
| |
| 2: 'User', 3: 'User talk',
| |
| 4: 'Hydrogenaudio Knowledgebase', 5: 'Hydrogenaudio Knowledgebase talk',
| |
| 6: 'Image', 7: 'Image talk',
| |
| 8: 'MediaWiki', 9:'MediaWiki talk',
| |
| 10: 'Template', 11: 'Template talk',
| |
| 12: 'Help', 13: 'Help talk',
| |
| 14: 'Category', 15: 'Category talk',
| |
| 16: 'Foobar2000', 17: 'Foobar2000 talk',
| |
| 18: 'Foobar2000redirect', 19: 'Foobar2000redirect talk',
| |
| },
| |
| firstEdit: 0,
| |
| editlist: new linkedList(
| |
| {key: 99990101011200, stats: {}},
| |
| {key: 0, stats: {}}),
| |
|
| |
| dummy: null // no comma
| |
| };
| |
|
| |
|
| |
| window.incr=function(obj, key) {
| |
| if (!obj[key]) { obj[key]=1; }
| |
| else { obj[key]++; }
| |
| }
| |
|
| |
| window.objSum=function(obj, x, y) {
| |
| var r=0;
| |
| if (x && y) { for (var k in obj) { r+= (obj[k][x][y] ? obj[k][x][y] : 0); } }
| |
| else if (x) { for (var k in obj) { r+= (obj[k][x] ? obj[k][x] : 0); } }
| |
| else { for (var k in obj) { r+= (obj[k] ? obj[k] : 0); } }
| |
| return r;
| |
| }
| |
|
| |
| window.percent=function(n, N) {
| |
| return Math.floor(n/N * 1000 + .5)/10;
| |
| };
| |
|
| |
| if((user=ec.getParamValue('ectarget'))!==null) { addOnloadHook(function(){ec.doEditCount(user);}); }
| |
|
| |
| function linkedList(x0,y0) {
| |
| this.first=null;
| |
| this.last=null;
| |
| this.hash={};
| |
| this.add=function(x) {
| |
| this.hash[x.key]=x;
| |
| if (!this.first) {
| |
| this.first=x;
| |
| this.last=x;
| |
| x.prev=x.next=null;
| |
| return;
| |
| }
| |
| var k=x.key;
| |
| if (true || k - this.first.key < this.last.key - k) {
| |
| this.pushTop(x);
| |
| } else {
| |
| this.pushTail(x);
| |
| }
| |
| };
| |
| this.pushTop=function(x) {
| |
| if (x.key < this.first.key) {
| |
| this.first.prev=x;
| |
| x.next=this.first;
| |
| this.first=x;
| |
| x.prev=null;
| |
| return;
| |
| }
| |
| if (x.key > this.last.key) {
| |
| this.last.next=x;
| |
| x.prev=this.last;
| |
| this.last=x;
| |
| x.next=null;
| |
| }
| |
| for (var y=this.first; y.next; y=y.next) {
| |
| if (y.key < x.key && x.key <= y.next.key) {
| |
| this.insertAfter(y, x);
| |
| return;
| |
| }
| |
| }
| |
| };
| |
| this.pushTail=function(x) {
| |
| for (var y=this.last; y.prev; y=y.prev) {
| |
| if (y.prev.key < x.key && x.key <= y.key) {
| |
| this.insertAfter(y.prev, x);
| |
| return;
| |
| }
| |
| }
| |
| this.first.prev=x;
| |
| x.next=this.first;
| |
| this.first=x;
| |
| x.prev=null;
| |
| };
| |
| this.insertAfter=function(y,x) {
| |
| x.next=y.next;
| |
| x.prev=y;
| |
| y.next.prev=x;
| |
| y.next=x;
| |
| };
| |
| if (x0) { this.add(x0); }
| |
| if (y0) { this.add(y0); }
| |
| }
| |
|
| |
| window.getStuff=function(obj, list) {
| |
| var r={};
| |
| for (var i=0; i<list.length; ++i) {
| |
| if (typeof obj[list[i]] != 'undefined') { r[list[i]]=obj[list[i]]; }
| |
| }
| |
| return r;
| |
| }
| |
|
| |
| window.IntervalSelector=function(data) {
| |
| if (!data) { data={}; }
| |
| this.min=data.min || 10;
| |
| this.max=data.max || 100;
| |
| this.span=this.max-this.min;
| |
| this.lo=data.lo || this.min;
| |
| this.hi=data.hi || this.max;
| |
| this.width=data.width || 400;
| |
| this.height=data.height || 20;
| |
| this.scale=this.width/this.span;
| |
| this.minBarWidth=data.minBarWidth || 10;
| |
| this.oldmousemove = null;
| |
| this.createDiv();
| |
| }
| |
|
| |
|
| |
| IntervalSelector.prototype.createDiv=function() {
| |
| var d=document.createElement('div');
| |
| d.className='intervalselectorbox';
| |
| //d.style.position='absolute';
| |
| d.style.border='1px solid black'; // FIXME
| |
| var s=document.createElement('div');
| |
| s.className='intervalselector';
| |
| s.style.position='relative';
| |
| s.style.background='orange'; // FIXME
| |
| //s.style.border='2px solid red'; // FIXME
| |
| d.appendChild(s);
| |
| this.box=d;
| |
| this.bar=s;
| |
| var this2=this;
| |
| this.bar.onmousedown=function(e){ this2.mouseDown.apply(this2, [e]); }
| |
| this.box.onmousedown=function(e){ this2.mouseDown.apply(this2, [e]); }
| |
| this.updatePosition();
| |
| };
| |
|
| |
| IntervalSelector.prototype.updatePosition=function() {
| |
| var d=this.box;
| |
| d.style.width=this.width+'px';
| |
| d.style.height=this.height+'px';
| |
| var s=this.bar;
| |
| s.style.left=(this.lo-this.min)*this.scale+ 'px';
| |
| s.style.width=(this.hi-this.lo)*this.scale + 'px';
| |
| s.style.height=this.height + 'px';
| |
| };
| |
|
| |
| IntervalSelector.prototype.mouseDown=function(e) {
| |
| var endWidth=8;
| |
| var pos=this.getMousePos(e);
| |
| var this2=this;
| |
|
| |
| var dragFunction=null;
| |
| var leftPos=findPosX(this.bar);
| |
| if (pos.x - leftPos < endWidth) { dragFunction=this2.dragLo; }
| |
| else if ( leftPos + parseInt(this.bar.style.width, 10) - pos.x < endWidth) { dragFunction=this2.dragHi; }
| |
| else { dragFunction = this2.dragBar; }
| |
| var x=pos.x, lo=this.lo;
| |
| if (document.onmousemove && document.onmousemove.origin != 'IntervalSelector') {
| |
| this.oldmousemove = document.onmousemove;
| |
| }
| |
| document.onmousemove=function(e) {
| |
| dragFunction.apply(this2, [e, x, lo]);
| |
| this2.dragging.apply(this2);
| |
| };
| |
| document.onmousemove.origin='IntervalSelector';
| |
| document.onmouseup=function() {
| |
| //console.log(this2.oldmousemove.toString());
| |
| document.onmousemove= this2.oldmousemove;
| |
| this2.doneDrag.apply(this2);
| |
| };
| |
| document.onmouseup.origin='IntervalSelector';
| |
| //document.title=pos.x;
| |
| };
| |
|
| |
| IntervalSelector.prototype.doneDrag=function(){};
| |
| IntervalSelector.prototype.dragging=function(){};
| |
|
| |
| IntervalSelector.prototype.dragLo=function(e) {
| |
| var pos=this.getMousePos(e);
| |
| var newLo=this.min + (pos.x - findPosX(this.box))/this.scale;
| |
| if (newLo < this.min) { newLo=this.min; }
| |
| else if (newLo > this.hi - this.minBarWidth/this.scale) { newLo=this.hi - this.minBarWidth/this.scale; }
| |
| this.lo=newLo;
| |
| this.updatePosition();
| |
| };
| |
|
| |
| IntervalSelector.prototype.dragHi=function(e) {
| |
| var pos=this.getMousePos(e);
| |
| var newHi=this.min + (pos.x - findPosX(this.box))/this.scale;
| |
| if (newHi > this.max) { newHi=this.max; }
| |
| else if (newHi < this.lo + this.minBarWidth/this.scale) { newHi=this.lo + this.minBarWidth/this.scale; }
| |
| this.hi=newHi;
| |
| this.updatePosition();
| |
| };
| |
|
| |
| IntervalSelector.prototype.dragBar=function(e, x0, l0) {
| |
| var pos=this.getMousePos(e);
| |
| var delta=pos.x-x0;
| |
| var newLo=l0 + delta/this.scale;
| |
| var newHi=newLo + this.hi-this.lo;
| |
| if (newLo < this.min) { newLo=this.min; newHi=newLo+this.hi-this.lo; }
| |
| else if (newHi > this.max) { newHi=this.max; newLo=newHi-(this.hi-this.lo); }
| |
| this.hi=newHi; this.lo=newLo;
| |
| this.updatePosition();
| |
| };
| |
|
| |
| IntervalSelector.prototype.getMousePos=function(e) {
| |
| e = e || window.event;
| |
| var x, y;
| |
| if (e) {
| |
| if (e.pageX) { x=e.pageX; y=e.pageY; }
| |
| else if (typeof e.clientX!='undefined') {
| |
| var left, top, docElt = window.document.documentElement;
| |
|
| |
| if (docElt) { left=docElt.scrollLeft; }
| |
| left = left || window.document.body.scrollLeft || window.document.scrollLeft || 0;
| |
|
| |
| if (docElt) { top=docElt.scrollTop; }
| |
| top = top || window.document.body.scrollTop || window.document.scrollTop || 0;
| |
|
| |
| x=e.clientX + left;
| |
| y=e.clientY + top;
| |
| } else { throw new Error ('bad mouse wiggle event in getMousePos'); return; }
| |
| }
| |
| return {x:x, y:y};
| |
| };
| |
|
| |
| window.findPosX=function(obj)
| |
| {
| |
| var curleft = 0;
| |
| if (obj.offsetParent)
| |
| {
| |
| while (obj.offsetParent)
| |
| {
| |
| curleft += obj.offsetLeft
| |
| obj = obj.offsetParent;
| |
| }
| |
| }
| |
| else if (obj.x)
| |
| curleft += obj.x;
| |
| return curleft;
| |
| }
| |
|
| |
| window.ts2unix=function(ts) {
| |
| var t=ts.toString();
| |
| return +(Date.UTC( t.substring(0,4), parseInt(t.substring(4,6),10)-1, t.substring(6,8),
| |
| t.substring(8,10), t.substring(10,12), t.substring(12,14)));
| |
| }
| |
| window.unix2ts=function(u) {
| |
| var d=new Date(u);
| |
| return map(zeroFill, [d.getUTCFullYear(), d.getUTCMonth()+1,
| |
| d.getUTCDate(), d.getUTCHours(),
| |
| d.getUTCMinutes(), d.getUTCSeconds()]).join('');
| |
| }
| |
|
| |
| window.zeroFill=function(s, min) {
| |
| min = min || 2;
| |
| var t=s.toString();
| |
| return repeatString('0', min - t.length) + t;
| |
| }
| |
|
| |
| window.map=function(f, o) {
| |
| if (isArray(o)) { return map_array(f,o); }
| |
| return map_object(f,o);
| |
| }
| |
| window.isArray =function(x) { return x instanceof Array; }
| |
|
| |
| window.map_array=function(f,o) {
| |
| var ret=[];
| |
| for (var i=0; i<o.length; ++i) {
| |
| ret.push(f(o[i]));
| |
| }
| |
| return ret;
| |
| }
| |
|
| |
| window.map_object=function(f,o) {
| |
| var ret={};
| |
| for (var i in o) { ret[o]=f(o[i]); }
| |
| return ret;
| |
| }
| |
|
| |
| window.repeatString=function(s,mult) {
| |
| var ret='';
| |
| for (var i=0; i<mult; ++i) { ret += s; }
| |
| return ret;
| |
| };
| |
|
| |
| window.formatTs=function(ts) {
| |
| ts=ts.toString();
| |
| if (ts.substring(0,4)=='9999') { return 'now'; }
| |
| return [ts.substring(0,4), ts.substring(4,6), ts.substring(6,8)].join('-') +
| |
| ' ' + [ts.substring(8,10),ts.substring(10,12),ts.substring(12,14)].join(':');
| |
| };
| |
|
| |
| function isMethodOf(klass, fn) {
| |
| for (var f in klass.prototype) {
| |
| if (fn===klass.prototype[f]) { return true; }
| |
| }
| |
| return false;
| |
| }
| |
|
| |
| //</nowiki></pre>
| |
| //ec.doEditCount('Amanda77')
| |
| // ec.doEditCount('Llama man')
| |