2012-10-30 00:51:07 +00:00
|
|
|
"use strict";
|
|
|
|
|
2012-10-12 19:39:43 +00:00
|
|
|
var TokenCollector = require( './ext.util.TokenCollector.js' ).TokenCollector,
|
|
|
|
Util = require( './mediawiki.Util.js' ).Util,
|
|
|
|
$ = require( 'jquery' );
|
2012-05-03 11:05:28 +00:00
|
|
|
|
2011-12-13 14:48:47 +00:00
|
|
|
/**
|
2011-12-13 18:45:09 +00:00
|
|
|
* Simple token transform version of the Cite extension.
|
2011-12-13 14:48:47 +00:00
|
|
|
*
|
2011-12-13 18:45:09 +00:00
|
|
|
* @class
|
|
|
|
* @constructor
|
2011-12-13 14:48:47 +00:00
|
|
|
*/
|
2012-08-19 17:39:16 +00:00
|
|
|
function Cite ( manager, options ) {
|
2012-05-03 11:05:28 +00:00
|
|
|
this.manager = manager;
|
2012-09-05 01:53:33 +00:00
|
|
|
this.options = options;
|
2012-11-16 18:03:01 +00:00
|
|
|
this.reset();
|
2012-05-03 11:05:28 +00:00
|
|
|
// Set up the collector for ref sections
|
|
|
|
new TokenCollector(
|
|
|
|
manager,
|
|
|
|
this.handleRef.bind(this),
|
|
|
|
true, // match the end-of-input if </ref> is missing
|
|
|
|
this.rank,
|
|
|
|
'tag',
|
|
|
|
'ref'
|
|
|
|
);
|
|
|
|
// And register for references tags
|
2012-07-18 00:18:50 +00:00
|
|
|
manager.addTransform( this.onReferences.bind(this), "Cite:onReferences",
|
2012-05-03 11:05:28 +00:00
|
|
|
this.referencesRank, 'tag', 'references' );
|
2012-11-16 18:03:01 +00:00
|
|
|
// And register for cleanup
|
|
|
|
manager.addTransform( this.reset.bind(this), "Cite:reset",
|
|
|
|
this.referencesRank, 'end' );
|
2011-12-13 14:48:47 +00:00
|
|
|
}
|
|
|
|
|
2012-11-16 18:03:01 +00:00
|
|
|
Cite.prototype.reset = function ( token ) {
|
|
|
|
this.refGroups = {};
|
|
|
|
return { token: token };
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2012-11-06 18:47:42 +00:00
|
|
|
// Cite should be the first thing to run in pahse 3 so the <ref>-</ref>
|
|
|
|
// content tokens are pulled out of the token stream and dont pollute
|
|
|
|
// the main token stream with any unbalanced tags/pres and the like.
|
|
|
|
Cite.prototype.rank = 2.01; // after QuoteTransformer, but before PostExpandParagraphHandler
|
2012-05-03 11:05:28 +00:00
|
|
|
Cite.prototype.referencesRank = 2.6; // after PostExpandParagraphHandler
|
|
|
|
//Cite.prototype.rank = 2.6;
|
2011-12-13 14:48:47 +00:00
|
|
|
|
2011-12-13 18:45:09 +00:00
|
|
|
/**
|
2012-05-03 11:05:28 +00:00
|
|
|
* Handle ref section tokens collected by the TokenCollector.
|
2011-12-13 18:45:09 +00:00
|
|
|
*/
|
2012-05-03 11:05:28 +00:00
|
|
|
Cite.prototype.handleRef = function ( tokens ) {
|
|
|
|
// remove the first ref tag
|
2012-09-25 17:40:05 +00:00
|
|
|
var startTsr, endTsr,
|
|
|
|
startTag = tokens.shift();
|
2012-08-30 07:19:19 +00:00
|
|
|
startTsr = startTag.dataAttribs.tsr;
|
2012-05-03 11:05:28 +00:00
|
|
|
if ( tokens[tokens.length - 1].name === 'ref' ) {
|
2012-08-30 07:19:19 +00:00
|
|
|
var endTag = tokens.pop();
|
|
|
|
endTsr = endTag.dataAttribs.tsr;
|
2011-12-13 14:48:47 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var options = $.extend({
|
|
|
|
name: null,
|
|
|
|
group: null
|
2012-08-23 23:26:19 +00:00
|
|
|
}, Util.KVtoHash(startTag.attribs));
|
2011-12-13 14:48:47 +00:00
|
|
|
|
2012-09-25 17:40:05 +00:00
|
|
|
var group = this.getRefGroup(options.group ),
|
|
|
|
ref = group.add(tokens, options ),
|
|
|
|
//console.warn( 'added tokens: ' + JSON.stringify( this.refGroups, null, 2 ));
|
|
|
|
linkback = ref.linkbacks[ref.linkbacks.length - 1];
|
2011-12-13 14:48:47 +00:00
|
|
|
|
|
|
|
|
|
|
|
var bits = [];
|
|
|
|
if (options.group) {
|
|
|
|
bits.push(options.group);
|
|
|
|
}
|
2012-07-18 20:23:12 +00:00
|
|
|
//bits.push(Util.formatNum( ref.groupIndex + 1 ));
|
2011-12-13 14:48:47 +00:00
|
|
|
bits.push(ref.groupIndex + 1);
|
|
|
|
|
2012-08-30 07:19:19 +00:00
|
|
|
var refId = "#mwt" + this.manager.env.generateUID(),
|
2012-09-25 17:40:05 +00:00
|
|
|
text = this.manager.env.text,
|
2012-09-17 19:46:44 +00:00
|
|
|
span = new TagTk('span', [
|
2012-05-03 11:05:28 +00:00
|
|
|
new KV('id', linkback),
|
|
|
|
new KV('class', 'reference'),
|
2012-08-30 07:19:19 +00:00
|
|
|
new KV('about', refId),
|
2012-09-05 01:07:26 +00:00
|
|
|
new KV('typeof', 'mw:Object/Ext/Cite')
|
2012-09-17 19:46:44 +00:00
|
|
|
]);
|
|
|
|
|
|
|
|
if (startTsr) {
|
2012-11-01 03:18:33 +00:00
|
|
|
// For template ref tokens, both start and end tsr's are stripped.
|
|
|
|
// So, if there is a start-tsr, there will also be an end-tsr.
|
|
|
|
// And, if absent, it is safe to go to end-of-text.
|
2012-09-17 19:46:44 +00:00
|
|
|
var start = startTsr[0],
|
|
|
|
end = endTsr ? endTsr[1] : text.length;
|
|
|
|
span.dataAttribs = {
|
2012-10-31 23:43:28 +00:00
|
|
|
tsr: [start, end]
|
2012-09-17 19:46:44 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-11-01 03:18:33 +00:00
|
|
|
// NOTE: endTsr can be undefined below when it has been
|
|
|
|
// stripped from ref-tags coming from template/extension content.
|
2012-09-17 19:46:44 +00:00
|
|
|
var res = [
|
|
|
|
span,
|
2012-05-03 11:05:28 +00:00
|
|
|
new TagTk( 'a', [
|
|
|
|
new KV('href', '#' + ref.target)
|
|
|
|
]
|
|
|
|
),
|
|
|
|
'[' + bits.join(' ') + ']',
|
|
|
|
new EndTagTk( 'a' ),
|
2012-08-30 07:19:19 +00:00
|
|
|
new EndTagTk( 'span' ),
|
2012-11-01 03:18:33 +00:00
|
|
|
new SelfclosingTagTk( 'meta', [
|
2012-08-30 07:19:19 +00:00
|
|
|
new KV( 'typeof', 'mw:Object/Ext/Cite/End' ),
|
2012-11-06 23:09:23 +00:00
|
|
|
new KV( 'about', refId)
|
2012-11-01 03:18:33 +00:00
|
|
|
], { tsr: endTsr } )
|
2011-12-13 14:48:47 +00:00
|
|
|
];
|
2012-05-03 11:05:28 +00:00
|
|
|
//console.warn( 'ref res: ' + JSON.stringify( res, null, 2 ) );
|
|
|
|
return { tokens: res };
|
2011-12-13 14:48:47 +00:00
|
|
|
};
|
|
|
|
|
2011-12-13 18:45:09 +00:00
|
|
|
/**
|
|
|
|
* Handle references tag tokens.
|
|
|
|
*
|
|
|
|
* @method
|
|
|
|
* @param {Object} TokenContext
|
|
|
|
* @returns {Object} TokenContext
|
|
|
|
*/
|
2012-05-03 11:05:28 +00:00
|
|
|
Cite.prototype.onReferences = function ( token, manager ) {
|
|
|
|
if ( token.constructor === EndTagTk ) {
|
|
|
|
return {};
|
|
|
|
}
|
2012-09-17 19:46:44 +00:00
|
|
|
|
2012-05-03 11:05:28 +00:00
|
|
|
//console.warn( 'references refGroups:' + JSON.stringify( this.refGroups, null, 2 ) );
|
2011-12-13 14:48:47 +00:00
|
|
|
|
|
|
|
var refGroups = this.refGroups;
|
2012-09-17 19:46:44 +00:00
|
|
|
|
2011-12-13 14:48:47 +00:00
|
|
|
var arrow = '↑';
|
|
|
|
var renderLine = function( ref ) {
|
2012-05-03 11:05:28 +00:00
|
|
|
var out = [ new TagTk('li', [new KV('id', ref.target)] ) ];
|
2012-09-17 19:46:44 +00:00
|
|
|
if (ref.linkbacks.length === 1) {
|
2011-12-13 18:45:09 +00:00
|
|
|
out = out.concat([
|
2012-05-03 11:05:28 +00:00
|
|
|
new TagTk( 'a', [
|
|
|
|
new KV('href', '#' + ref.linkbacks[0])
|
|
|
|
]
|
|
|
|
),
|
|
|
|
arrow,
|
|
|
|
new EndTagTk( 'a' )
|
2011-12-13 18:45:09 +00:00
|
|
|
],
|
|
|
|
ref.tokens // The original content tokens
|
2011-12-13 14:48:47 +00:00
|
|
|
);
|
|
|
|
} else {
|
2012-05-03 11:05:28 +00:00
|
|
|
out.push( arrow );
|
2011-12-13 14:48:47 +00:00
|
|
|
$.each(ref.linkbacks, function(i, linkback) {
|
2011-12-13 18:45:09 +00:00
|
|
|
out = out.concat([
|
2012-05-03 11:05:28 +00:00
|
|
|
new TagTk( 'a', [
|
|
|
|
new KV('data-type', 'hashlink'),
|
|
|
|
new KV('href', '#' + ref.linkbacks[0])
|
2011-12-13 18:45:09 +00:00
|
|
|
]
|
2012-05-03 11:05:28 +00:00
|
|
|
),
|
2011-12-13 18:45:09 +00:00
|
|
|
// XXX: make formatNum available!
|
|
|
|
//{
|
2012-09-07 16:42:37 +00:00
|
|
|
// type: 'TEXT',
|
2012-07-18 20:23:12 +00:00
|
|
|
// value: Util.formatNum( ref.groupIndex + '.' + i)
|
2011-12-13 18:45:09 +00:00
|
|
|
//},
|
2012-05-03 11:05:28 +00:00
|
|
|
ref.groupIndex + '.' + i,
|
|
|
|
new EndTagTk( 'a' )
|
2011-12-13 18:45:09 +00:00
|
|
|
],
|
|
|
|
ref.tokens // The original content tokens
|
2011-12-13 14:48:47 +00:00
|
|
|
);
|
|
|
|
});
|
|
|
|
}
|
2012-05-03 11:05:28 +00:00
|
|
|
//console.warn( 'renderLine res: ' + JSON.stringify( out, null, 2 ));
|
2011-12-13 14:48:47 +00:00
|
|
|
return out;
|
|
|
|
};
|
2012-09-17 19:46:44 +00:00
|
|
|
|
2012-09-25 17:40:05 +00:00
|
|
|
var res,
|
|
|
|
options = $.extend({
|
2011-12-13 14:48:47 +00:00
|
|
|
name: null,
|
|
|
|
group: null
|
2012-08-23 23:26:19 +00:00
|
|
|
}, Util.KVtoHash(token.attribs));
|
2011-12-13 14:48:47 +00:00
|
|
|
|
2012-10-29 17:07:18 +00:00
|
|
|
var dataAttribs;
|
2011-12-13 14:48:47 +00:00
|
|
|
if (options.group in refGroups) {
|
2012-09-25 17:40:05 +00:00
|
|
|
var group = refGroups[options.group],
|
2012-10-29 17:07:18 +00:00
|
|
|
listItems = $.map(group.refs, renderLine );
|
|
|
|
|
|
|
|
dataAttribs = Util.clone(token.dataAttribs);
|
2012-09-06 02:21:36 +00:00
|
|
|
dataAttribs.src = token.getWTSource(this.manager.env);
|
2012-05-03 11:05:28 +00:00
|
|
|
res = [
|
|
|
|
new TagTk( 'ol', [
|
|
|
|
new KV('class', 'references'),
|
2012-09-05 01:07:26 +00:00
|
|
|
new KV('typeof', 'mw:Object/References')
|
|
|
|
], dataAttribs)
|
2012-05-03 11:05:28 +00:00
|
|
|
].concat( listItems, [ new EndTagTk( 'ol' ) ] );
|
2011-12-13 14:48:47 +00:00
|
|
|
} else {
|
2012-10-29 17:07:18 +00:00
|
|
|
var tsr = token.dataAttribs.tsr;
|
|
|
|
if (tsr) {
|
|
|
|
// src from original src
|
|
|
|
dataAttribs = {
|
|
|
|
tsr: tsr,
|
|
|
|
src: this.manager.env.text.substring(tsr[0], tsr[1])
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
// Use a default string
|
|
|
|
dataAttribs = {
|
|
|
|
src: "<references />"
|
|
|
|
};
|
|
|
|
}
|
|
|
|
res = [ new TagTk('span', [ new KV( 'typeof', 'mw:Placeholder' ) ], dataAttribs) ];
|
2011-12-13 14:48:47 +00:00
|
|
|
}
|
|
|
|
|
2012-05-03 11:05:28 +00:00
|
|
|
//console.warn( 'references res: ' + JSON.stringify( res, null, 2 ) );
|
|
|
|
return { tokens: res };
|
2011-12-13 14:48:47 +00:00
|
|
|
};
|
|
|
|
|
2012-05-03 11:05:28 +00:00
|
|
|
Cite.prototype.getRefGroup = function(group) {
|
|
|
|
var refGroups = this.refGroups;
|
|
|
|
if (!(group in refGroups)) {
|
|
|
|
var refs = [],
|
|
|
|
byName = {};
|
|
|
|
refGroups[group] = {
|
|
|
|
refs: refs,
|
|
|
|
byName: byName,
|
|
|
|
add: function(tokens, options) {
|
|
|
|
var ref;
|
|
|
|
if (options.name && options.name in byName) {
|
|
|
|
ref = byName[options.name];
|
|
|
|
} else {
|
2012-09-25 17:40:05 +00:00
|
|
|
var n = refs.length,
|
|
|
|
key = n + '';
|
2012-05-03 11:05:28 +00:00
|
|
|
if (options.name) {
|
|
|
|
key = options.name + '-' + key;
|
|
|
|
}
|
|
|
|
ref = {
|
|
|
|
tokens: tokens,
|
|
|
|
index: n,
|
|
|
|
groupIndex: n, // @fixme
|
|
|
|
name: options.name,
|
|
|
|
group: options.group,
|
|
|
|
key: key,
|
|
|
|
target: 'cite_note-' + key,
|
|
|
|
linkbacks: []
|
|
|
|
};
|
|
|
|
refs[n] = ref;
|
|
|
|
if (options.name) {
|
|
|
|
byName[options.name] = ref;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ref.linkbacks.push(
|
|
|
|
'cite_ref-' + ref.key + '-' + ref.linkbacks.length
|
|
|
|
);
|
|
|
|
return ref;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return refGroups[group];
|
2011-12-14 23:38:46 +00:00
|
|
|
};
|
2011-12-13 14:48:47 +00:00
|
|
|
|
2012-09-17 19:46:44 +00:00
|
|
|
if (typeof module === "object") {
|
2011-12-13 14:48:47 +00:00
|
|
|
module.exports.Cite = Cite;
|
|
|
|
}
|