Skip to content

Commit

Permalink
Refactored jump-links into a separate JavaScript file
Browse files Browse the repository at this point in the history
  • Loading branch information
rcmiller authored and maxg committed Jun 2, 2020
1 parent ccdcf86 commit 73e117f
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 66 deletions.
1 change: 1 addition & 0 deletions web/handout/handout-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ HANDOUT_SCRIPTDIR = document.querySelector('script[src*=handout-page]').getAttri
require('https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js', function () {
var stages = [
[ './course-setup.js#render',
'./jump-links.js#render',
'./handout-render.js',
'./render/Markdown.Converter.js',
'https://cdnjs.cloudflare.com/ajax/libs/pluralize/7.0.0/pluralize.min.js#render',
Expand Down
77 changes: 11 additions & 66 deletions web/handout/handout-render.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,17 @@ function renderPage() {
if ( ! this.id) { this.id = uniqueIdentifier('id', '^', this.dataset.structureText); }
});

// assign IDs to content chunks
identifyChunks($('.table-of-contents').length);
// assign IDs to content chunks and create # links
makeJumpLinks({
jumpable: 'h1, h2, h3, h4, h5, h6, .panel-heading' +
($('.table-of-contents').length ? ', p, pre, ol:not(li ol), ul:not(li ul), dl, table, .exercise-part-heading' : ''),
exclude: '.exercise-explain *, .exercise-choice *, .faq h3 + div > p:first-child',
nest: {
'ol, ul': 'li',
'dl': 'dt',
'table': 'th, td',
},
});

// build table of contents
$('.table-of-contents').each(function() {
Expand Down Expand Up @@ -452,70 +461,6 @@ function convertExercise(container, category, node) {
body.append(foot);
}

function identifyChunks(dense) {
var jumpable = 'h1, h2, h3, h4, h5, h6, .panel-heading' + (dense ? ', p, pre, ol:not(li ol), ul:not(li ul), dl, table, .exercise-part-heading' : '');
var exclude = '.exercise-explain *, .faq h3 + div > p:first-child';
var nest = {
'ol, ul': 'li',
'dl': 'dt',
'table': 'th, td',
};
var elements = $(jumpable).not(':has(' + jumpable + ')').not(exclude);
var chunks = {};
var stopwords = [
'a', 'an', 'and', 'are', 'as', 'at', 'by', 'for', 'from', 'has', 'have', 'how',
'in', 'is', 'it', 'it-s', 'its', 'let-s', 'of', 'on', 'or', 'that', 'the', 'this', 'to',
'was', 'we', 'were', 'we-ll', 'we-re', 'what', 'when', 'where', 'who', 'will', 'with',
];
elements.map(function(idx, elt) {
var words = $(this).text().toLowerCase().split(/\s+/).map(function(word) {
return word.replace(/^\W+|\W+$/g, '').replace(/\W+/g, '-');
}).filter(function(word) {
return word && (stopwords.indexOf(word) < 0);
});
return { $elt: this, $words: words };
}).each(function() {
var here = chunks;
while (this.$words.length) {
var word = this.$words.shift();
if ( ! here[word]) {
here[word] = this;
return;
}
if (here[word].$elt) {
var current = here[word];
here[word] = {};
if ( ! current.$words.length) { return; }
here[word][current.$words.shift()] = current;
}
here = here[word];
}
});
var size = 3;
(function labeler(labels, tree) {
if (tree.$elt) {
if ( ! tree.$elt.id) {
Array.prototype.push.apply(labels, tree.$words.slice(0, (size - (labels.length % size)) % size));
tree.$elt.id = '@' + labels.join('_');
}
} else {
Object.keys(tree).forEach(function(key) {
labeler(labels.concat(key), tree[key]);
});
}
})([], chunks);
elements.filter('[id]').each(function(idx, elt) {
var parent = $(elt);
$.each(nest, function(outer, inner) {
if (parent.is(outer)) {
parent = $(inner, parent).not(':empty').first();
return false;
}
});
parent.prepend($('<a>').addClass('jump').attr('href', '#' + elt.id));
});
}

function uniqueIdentifier(attr, prefix, text, context) {
var base = prefix + text.toLowerCase().replace(/\s/g, '_').replace(/[^\w-]/g, '').replace(/([_-])\1+/g, '$1');
var val = base;
Expand Down
67 changes: 67 additions & 0 deletions web/handout/jump-links.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@

// assign IDs to content chunks, and create # links in the margin so that user can obtain a link there

// spec: {
// jumpable: string, jQuery selector of elements that should get jump links
// exclude: string, jQuery selector of elements to exclude from jumpable
// nest: { selector:string -> selector:string }
// }
function makeJumpLinks(spec) {
var jumpable = spec.jumpable;
var exclude = spec.exclude;
var nest = spec.nest;
var elements = $(jumpable).not(':has(' + jumpable + ')').not(exclude);
var chunks = {};
var stopwords = [
'a', 'an', 'and', 'are', 'as', 'at', 'by', 'for', 'from', 'has', 'have', 'how',
'in', 'is', 'it', 'it-s', 'its', 'let-s', 'of', 'on', 'or', 'that', 'the', 'this', 'to',
'was', 'we', 'were', 'we-ll', 'we-re', 'what', 'when', 'where', 'who', 'will', 'with',
];
elements.map(function(idx, elt) {
var words = $(this).text().toLowerCase().split(/\s+/).map(function(word) {
return word.replace(/^\W+|\W+$/g, '').replace(/\W+/g, '-');
}).filter(function(word) {
return word && (stopwords.indexOf(word) < 0);
});
return { $elt: this, $words: words };
}).each(function() {
var here = chunks;
while (this.$words.length) {
var word = this.$words.shift();
if ( ! here[word]) {
here[word] = this;
return;
}
if (here[word].$elt) {
var current = here[word];
here[word] = {};
if ( ! current.$words.length) { return; }
here[word][current.$words.shift()] = current;
}
here = here[word];
}
});
var size = 3;
(function labeler(labels, tree) {
if (tree.$elt) {
if ( ! tree.$elt.id) {
Array.prototype.push.apply(labels, tree.$words.slice(0, (size - (labels.length % size)) % size));
tree.$elt.id = '@' + labels.join('_');
}
} else {
Object.keys(tree).forEach(function(key) {
labeler(labels.concat(key), tree[key]);
});
}
})([], chunks);
elements.filter('[id]').each(function(idx, elt) {
var parent = $(elt);
$.each(nest, function(outer, inner) {
if (parent.is(outer)) {
parent = $(inner, parent).not(':empty').first();
return false;
}
});
parent.prepend($('<a>').addClass('jump').attr('href', '#' + elt.id));
});
}

0 comments on commit 73e117f

Please sign in to comment.