For faster navigation, this Iframe is preloading the Wikiwand page for Участник:Js/archiver.js.

Участник:Js/archiver.js

Материал из Википедии — свободной энциклопедии

//*** Script to archive discussion pages, beta version ***
//In edit mode click on "(a)" next to "watch", then follow directions

//Interface: en
//Localization: en & ru (see parseSigStamp())
//compat with secure server: ??



//Customization 
if (mw.config.get('wgServer') == 'http://ru.wikipedia.org'){
 archiveName = mw.config.get('wgPageName') + '/Архив'
 archiveHeader = '{\{закрыто))'
 if (/Википедия:Форум\/./.test(mw.config.get('wgPageName'))){
   archiveByMonth = true
   archivePageDir = -1
   archiveName = mw.config.get('wgPageName').split('/')[0] + '/Архив/' + mw.config.get('wgPageName').split('/')[1]
   archiveHeader = '{\{архив форума))'
 }else if (mw.config.get('wgPageName') == 'Википедия:Вниманию_участников'){
   archiveByMonth = true //archivePageDir = -1
 }else if (mw.config.get('wgPageName') == 'Википедия:Форум_администраторов'){
   archiveByMonth = true
 }else if (mw.config.get('wgPageName') == 'Википедия:Запросы_к_администраторам'){
   archiveByMonth = true //archivePageDir = -1
   archiveThreshold = 4
 }
}else if (mw.config.get('wgServer') == 'http://meta.wikimedia.org'){
 archiveHeader = '{\{archive-header|))'
 switch(mw.config.get('wgPageName')){
 //case 'Requests_for_permissions' // page layout is too complicated 
 case  'Requests_for_bot_status':
   archiveByMonth = true
   archiveStartFrom = '\n==Bot status requests=='
   archiveH3Sections = true
   break
 case 'Requests_for_CheckUser_information':
   break 
   //
 }
}

//LATER: move inside object
//parameters; also: archiveStartFrom, archiverAutoDiff
var archiveName = window.archiveName || mw.config.get('wgPageName') + '/Archive'
var archiveByMonth = window.archiveByMonth || false 
var archiveHeader = window.archiveHeader || '' 
var archiveThreshold = window.archiveThreshold || 7
var archivePageDir = window.archivePageDir || 0 // 1: new sections on bottom, -1: on top, 0: determine automatically
//vars
var secStart, secEnd, hdrStart, hdrEnd
var sec, pageText, pageTextSize, archives, moveTextSize = 0, moveSecN = 0



var archiver = new function(){

 scriptName = 'Archiver'
 this.start = function(){ start() }
 this.autoMarkSections = autoMarkSections
 this.startArchiving = startArchiving
 this.doArchiving = doArchiving
 this.markSection = function(i){ toggleSection(i);  showDialog() }  //on click


function showDialog(){
 var html = '<h2>Archiving</h2>'
 + 'Archive page: ' + archiveName  
 + (archiveByMonth ? '<small>/&lt;year&gt;/&lt;month&gt;</small>' : '') + '<br />'
 + (archivePageDir == -1 ? 'New sections are on top<br />' : '') 
 + 'Auto marked sections older than ' + archiveThreshold + ' days<br />'
// + ' <b><a href="javascript:archiveThreshold--; archiver.autoMarkSections()">-</a>'
// + ' <a href="javascript:archiveThreshold++; archiver.autoMarkSections()">+</a></b><br />'
// + 'Or mark sections manually<br />'
 + '<br />'
 + 'Whole text: ' + pageTextSize + ' bytes in ' + sec.length + ' sections<br />'
 + 'To archive: ' + moveTextSize + ' bytes in ' + moveSecN +   ' sections<br />'
 + '<br />'
 + 'Mark sections, then '
 + '<input type=button id=startArchiving value=Archive onclick=archiver.startArchiving()>'
 jsMsg(html)
}


function start(){

 msg(scriptName + ' started.')
 document.getElementById('mw-js-message').style.backgroundColor = '#F0FAF0'

 if (window.archiveH3Sections){ 
  hdrStart = 'H3'
  hdrEnd = 'H2'
  secStart = /^===[^=].*=== *$/m
  secEnd = /^={1,3}[^=].*={1,3} *$/m
 }else{
  hdrStart = 'H2'
  hdrEnd = 'H1'
  secStart = /^==[^=].*== *$/m
  secEnd = /^==?[^=].*== *$/m
 }

 msg(' analyzing text ...')
 pageText = document.editform.wpTextbox1.value
 pageTextSize = countBytes(pageText)
 currentTime = parseTimestamp(document.editform.wpStarttime.value) 
 var startFrom = 0
 if (window.archiveStartFrom){
   startFrom = pageText.indexOf(archiveStartFrom)
   if (startFrom == -1) err('Unable to find this in text: "' + archiveStartFrom + '"')
 }

 msg(' getting sections ...')
 sec = getTextSections(pageText, startFrom)

 //var wikiPreview = document.getElementById('wikiPreview')
 //if (!wikiPreview) {  jsMsg('<b>Error</b>: archiver needs Page Preview');  return }

 //var 
 toc = document.getElementById('toc')
 if (!toc) err('Script needs preview with TOC')
 toc = getElementsByClassName(toc, 'span', 'toctext')

 /*was trying to get TOC items without API, impossible with complex cases such as when templates are used
   //convert section header into text
   hdr = sec[i].content.match(secStart)[0]
   hdr = hdr.match(/^=+ *([^=].*)/)[1].match(/(.*?[^=]) *=+$/)[1] //trim spaces and "=" on edges
   hdr = hdr.replace(/\[\[:?[^|]+\|([^\]]+)\]\]/g, '$1') //[[foo|bar]] -> bar
   hdr = hdr.replace(/\[\[:?([^\]]+)\]\]/g, '$1') //[[bar]] -> bar
   hdr = hdr.replace(/<.*?>/g, '').replace(/ +/g,' ') //strip tags and double spaces
  // outdated note:  finding corresponding TOC elements is easier than finding H2/H3 directly, because section header can contain e.g. <br>
 */
 
 //convert section headers into TOC text using API
 msg(' getting TOC elements using API query ...')
 var queryText = '', aj = sajax_init_object(), q, i
 tocAPI = []
 for (i=0; i<sec.length; i++){
   queryText += encodeURIComponent(sec[i].content.match(secStart)[0]) + '%0A'
   if (queryText.length < 3000 && i < sec.length-1) continue
   //do API query if URL is too long or this is the last loop
   aj.open('GET', '/w/api.php?format=json&action=parse&prop=sections&text='+queryText+'__TOC__', false)
   aj.send(null)
   if (aj.status != 200) err('query failed:\n' + aj.responseText)
   eval('q='+aj.responseText)
   if (!(q=q.parse) || !(q=q.sections)) err('unrecognized query result:\n' + aj.responseText)
   for (var j=0; j<q.length; j++) tocAPI.push(q[j].line)
   queryText = ''
 }
 if (tocAPI.length != sec.length) err('there are '+sec.length+' sections, query returned '+tocAPI.length+' headers') 



 //for each section in text  find corresponding TOC item and section header in preview
 var el, hh = new Array(sec.length), tocIdx = 0
 for (i=0; i<sec.length; i++){
   hdr = tocAPI[i].replace(/ +/g, ' ').replace(/&#123;/g,'{')
   while (tocIdx < toc.length && toc[tocIdx].firstChild.data.replace(/\xA0/g,' ') != hdr ) tocIdx++
   //about replace: french spaces (?) in http://svn.wikimedia.org/viewvc/mediawiki/trunk/phase3/includes/Parser.php?view=markup
   if (tocIdx >= toc.length) err('Could not find this section header in TOC:\n' + hdr)
  sec[i].toc = toc[tocIdx].parentNode.parentNode //assign custom attribute
  //using anchor, find corresponding H2/H3 in text
  el = document.getElementsByName(toc[tocIdx].parentNode.getAttribute('href', 2).substring(1))[0]
  if (!el) err('Could not find anchor for this section header:\n' + hdr)
  el = el.parentNode //enclosing <p>
  while ((el=el.nextSibling) && el.nodeName != hdrStart);
  if (!el) err('Could not find '+hdrStart+' for this section header:\n' + hdr)
  hh[i] = el
 }

 //enclose each preview section in  div
 var div, daysAgo, toggleLink, toggleDiv
 for (i=0; i<sec.length; i++){
  div = document.createElement('div')
  div.style.cssText = 'margin-top:20px; border:1px dotted gray; padding:5px'
  hh[i].parentNode.insertBefore(div, hh[i])
  sec[i].div = div
  el = div.nextSibling
  do {
    //obj = el
    el=el.nextSibling
    div.appendChild(el.previousSibling)
  } while (el && el.nodeName != hdrStart && el.nodeName != hdrEnd && el.nodeName != '#comment')
  //add toggle link showing section age
  daysAgo = Math.floor(sec[i].age)
  if (daysAgo == -1) daysAgo = '<small>??</small>'
  else if (daysAgo > 10) daysAgo += '<small>d</small> '
  else daysAgo += '<small>d</small> ' + Math.floor((sec[i].age-daysAgo)*24) + '<small>h</small>'
  var toggleLink = document.createElement('a')
  toggleLink.style.cssFloat = toggleLink.style.styleFloat = 'right'
  toggleLink.style.fontSize = '70%'
  toggleLink.href = 'javascript:archiver.markSection('+i+')'
  toggleLink.innerHTML = daysAgo
  hh[i].insertBefore(toggleLink, hh[i].firstChild)
  toggleDiv = document.createElement('div')
  toggleDiv.appendChild(toggleLink.cloneNode(true))
  toggleDiv.appendChild(document.createTextNode('\u00A0'))
  hh[i].parentNode.appendChild(toggleDiv)
 }

 autoMarkSections()

}




function getTextSections(text, startFrom){ //returns array of sections in text; needs currentTime as Date()
 //get all sections
 var sect = new Array (), processedIdx = startFrom || 0, begin, end
 while ((begin=text.substring(processedIdx).search(secStart)) != -1){
   begin += processedIdx //correct relative to whole text
   //find end of section
   processedIdx = text.indexOf('\n', begin)
   end = text.substring(processedIdx).search(secEnd) //search from next line
   if (end == -1) end = text.length
   else end += processedIdx
   //remember section in array
   sect.push({begin:begin, end:end, content:text.substring(begin, end), marked:false})
   //get ready for the next loop
   processedIdx = end
 }
 //look for timestamps and find each section firstDate and age
 var dates, d, firstStamp, lastStamp, age
 for (i=0; i<sect.length; i++){
   dates = sect[i].content.replace(/<blockquote>.*?<\/blockquote>/gi, '') //do not search in blockquote
   dates = dates.match(/\d\d:\d\d, \d\d? \S{3,8} 20\d\d \(UTC\)/g)
   firstStamp = currentTime; lastStamp = 0
   if (dates){
     for (var j=0; j<dates.length; j++){
       d = parseSigStamp(dates[j])
       if (d < firstStamp) firstStamp = d
       if (d > lastStamp) lastStamp = d
     }
     age = (currentTime-lastStamp)/(1000*3600*24) //in days
   }else{
     firstStamp = 0
     age = -1
   }
   sect[i].firstDate = firstStamp
   sect[i].age = age
 }
  //determine if newer sections are on top or bottom
 if (archivePageDir == 0){ 
   for (i=1; i<sect.length; i++)
     if (sect[i-1].firstDate < sect[i].firstDate) archivePageDir++
     else if (sect[i-1].firstDate > sect[i].firstDate) archivePageDir--
   archivePageDir = (archivePageDir >=0) ? 1 : -1
 }
 //fix firstDate for no-timestamps sections  by adding/removing one minute
 for (i=1; i<sect.length; i++)
   if (sect[i].firstDate == 0 && sect[i-1].firstDate != 0){
     sect[i].firstDate = sect[i-1].firstDate
     sect[i].firstDate.setMinutes(sect[i].firstDate.getMinutes() + archivePageDir)
   }
 for (i=sect.length-2; i>=0; i--)
   if (sect[i].firstDate == 0 && sect[i+1].firstDate != 0){
     sect[i].firstDate = sect[i+1].firstDate
     sect[i].firstDate.setMinutes(sect[i].firstDate.getMinutes() - archivePageDir)
   }
 return sect
}



function autoMarkSections(){
 for (var i=0; i<sec.length; i++){
   if ((sec[i].age >= archiveThreshold) != sec[i].marked)
     toggleSection(i)
 }
 showDialog()
} 




function toggleSection(i){
 var marked = ! sec[i].marked
 sec[i].marked = marked
 moveSecN += marked ? 1 : -1
 moveTextSize += (marked ? 1 : -1) * countBytes(sec[i].content)
 sec[i].div.style.background = marked ? '#E5E5F0' : ''
 sec[i].toc.style.background = marked ? '#E5E5F0' : ''
 //document.getElementById('section'+i).style.background = marked ? '#E5E5F0' : ''
 //document.getElementById('tocsec'+i).style.background = marked ? '#E5E5F0' : ''
}


function startArchiving(){
 var pg
 archives = {}
 for (var i=sec.length-1; i>=0; i--){
   if (!sec[i].marked) continue
   pg = archiveName
   if (archiveByMonth) pg += '/' + sec[i].firstDate.getFullYear() 
                           + '/' + zz(sec[i].firstDate.getMonth()+1)
   if (!archives[pg]) archives[pg] = {header:archiveHeader, text:''}
   archives[pg].text = sec[i].content + archives[pg].text
   pageText = pageText.substring(0, sec[i].begin) + pageText.substring(sec[i].end)
 }
 doArchiving()
}


function doArchiving(){
 var pg, win
 for (pg in archives){
   win = window.open(mw.config.get('wgServer') + mw.config.get('wgScript') + '?action=edit&preview=no&title=' + pg)
   win.archiveText = archives[pg].text
   win.archiveHeader = archives[pg].header
   win.onload = archivePageOnLoad
 }
 document.editform.wpTextbox1.value = pageText
 document.editform.wpSummary.value = '::архивировано ' + moveSecN + ' '
  +plural(moveSecN,'секция','секции','секций') + '::' // + aChars + ' символов'
 jsMsg('Archiving is ready. Check that everything is ok and press Save buttons in all open windows.')
 //setTimeout('window.focus()', 2000)
 self.focus()
}


function archivePageOnLoad(){
 var win = this, i
 var box = win.document.editform.wpTextbox1
 var txt = box.value || win.archiveHeader + '\n' || ''
 //append archived text
 if (archivePageDir == -1 && (i=txt.indexOf('\n=='))!=-1) //just after intro
   txt = txt.substring(0,i) + '\n' + win.archiveText + txt.substring(i)
 else //at bottom
   txt += win.archiveText
 //get sections
 //var 
 secs = getTextSections(txt)
 //get intro section, then sort and append all other sections
 txt = txt.substring(0, secs[0].begin)
 secs.sort(function(a,b){return (a.firstDate-b.firstDate) * archivePageDir})
 for (i=0; i<secs.length; i++) txt += secs[i].content
 txt = txt.replace(/\n+==/g, '\n\n==') //make sure ther is exactly one line before each ==header==
 box.value = txt
 win.document.editform.wpSummary.value = '+'
 if (window.archiverAutoDiff) win.document.getElementById('wpDiff').click()

}


function zz(a){ a=a.toString(); return (a.length==1) ? '0'+a : a } // 6 -> '06'

var jsMsgHTML = ''
function msg(t){
 jsMsgHTML += '<br />' + t.replace(/\n/g,'<br />') 
 jsMsg(jsMsgHTML)
}
function err(t){
 msg('<br /><font color=red><b>Error:</b></font><br />' + t)
 throw 'Error in' + scriptName + ' script: ' + t
}


function countBytes(text){
 var bytes = 0, bb
 for (var i=0; i<text.length; i++){
   bb = text.charCodeAt(i)
   if (bb < 128) bytes++
   else if (bb < 2048) bytes += 2
   else if (bb < 65535) bytes += 3
   else bytes += 4 
 }
 return bytes
}


function plural(num, v1, v2, v3){
 num = num % 100
 if (5<=num && num<=20) return v3
 num = num % 10
 if (num == 1) return v1
 else if (2<=num && num<=4) return v2
 else return v3
}


function parseSigStamp(sig){ // '05:53, 7 марта 2007' -> date
 var s = sig.split(' ')
 var sigTime = new Date()
 sigTime.setYear(s[3])
 var month_name = s[2].substring(0,3).toLowerCase()
 var month = 'янвфевмарапрмаяиюниюлавгсеноктноядек'.indexOf(month_name)
 if (month == -1) month = 'janfebmaraprmayjunjulaugsepoctnovdec'.indexOf(month_name)
 if (month == -1) return null
 sigTime.setMonth(month/3)
 sigTime.setDate(s[1])
 sigTime.setHours(s[0].substring(0,2))
 sigTime.setMinutes(s[0].substring(3,5))
 sigTime.setSeconds(0)
 return sigTime
}

function parseTimestamp(ts){ //20071226220605  or  2008-01-26T06:34:19Z   -> date
 if (!ts) return null
 ts = ts.replace(/\D/g,'')
 var d = new Date()
 d.setYear(ts.substring(0,4))
 d.setMonth(ts.substring(4,6)-1)
 d.setDate(ts.substring(6,8))
 d.setHours(ts.substring(8,10))
 d.setMinutes(ts.substring(10,12))
 d.setSeconds(ts.substring(12,14))
 return d
}

}//archiver




//if the script is imported directly
if (!doneOnloadHook && (mw.config.get('wgAction') == 'edit' || mw.config.get('wgAction') == 'sumbit'))
$(function(){
  if (document.URL.indexOf('&section=') == -1 && document.editform && document.editform.wpSection.value == '')
    mw.util.addPortletLink('p-cactions', 'javascript:archiver.start();', '(a)', 't-archive', 'Archive this page with Archiver')
})
{{bottomLinkPreText}} {{bottomLinkText}}
Участник:Js/archiver.js
Listen to this article

This browser is not supported by Wikiwand :(
Wikiwand requires a browser with modern capabilities in order to provide you with the best reading experience.
Please download and use one of the following browsers:

This article was just edited, click to reload
This article has been deleted on Wikipedia (Why?)

Back to homepage

Please click Add in the dialog above
Please click Allow in the top-left corner,
then click Install Now in the dialog
Please click Open in the download dialog,
then click Install
Please click the "Downloads" icon in the Safari toolbar, open the first download in the list,
then click Install
{{::$root.activation.text}}

Install Wikiwand

Install on Chrome Install on Firefox
Don't forget to rate us

Tell your friends about Wikiwand!

Gmail Facebook Twitter Link

Enjoying Wikiwand?

Tell your friends and spread the love:
Share on Gmail Share on Facebook Share on Twitter Share on Buffer

Our magic isn't perfect

You can help our automatic cover photo selection by reporting an unsuitable photo.

This photo is visually disturbing This photo is not a good choice

Thank you for helping!


Your input will affect cover photo selection, along with input from other users.

X

Get ready for Wikiwand 2.0 🎉! the new version arrives on September 1st! Don't want to wait?