Created
April 4, 2017 18:44
-
-
Save Kyuuhachi/3c96e14f4fddd8adff0e85027b6c0a8b to your computer and use it in GitHub Desktop.
An userscript for cleaning up SchoolSoft's schedule's print view
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name Schedule | |
// @namespace c98 | |
// @include https://sms7.schoolsoft.se/nti/jsp/student/right_student_schedule_print.jsp?* | |
// @version 1 | |
// @grant none | |
// ==/UserScript== | |
print=alert; | |
(function() { | |
// {{{ Libs | |
$ = jQuery = window.$ || window.jQuery || window._jQuery; | |
// {{{ randomColor | |
;(function(root, factory) { | |
// Support AMD | |
if (typeof define === 'function' && define.amd) { | |
define([], factory); | |
// Support CommonJS | |
} else if (typeof exports === 'object') { | |
var randomColor = factory(); | |
// Support NodeJS & Component, which allow module.exports to be a function | |
if (typeof module === 'object' && module && module.exports) { | |
exports = module.exports = randomColor; | |
} | |
// Support CommonJS 1.1.1 spec | |
exports.randomColor = randomColor; | |
// Support vanilla script loading | |
} else { | |
root.randomColor = factory(); | |
} | |
}(this, function() { | |
// Seed to get repeatable colors | |
var seed = null; | |
// Shared color dictionary | |
var colorDictionary = {}; | |
// Populate the color dictionary | |
loadColorBounds(); | |
var randomColor = function (options) { | |
options = options || {}; | |
// Check if there is a seed and ensure it's an | |
// integer. Otherwise, reset the seed value. | |
if (options.seed !== undefined && options.seed !== null && options.seed === parseInt(options.seed, 10)) { | |
seed = options.seed; | |
// A string was passed as a seed | |
} else if (typeof options.seed === 'string') { | |
seed = stringToInteger(options.seed); | |
// Something was passed as a seed but it wasn't an integer or string | |
} else if (options.seed !== undefined && options.seed !== null) { | |
throw new TypeError('The seed value must be an integer or string'); | |
// No seed, reset the value outside. | |
} else { | |
seed = null; | |
} | |
var H,S,B; | |
// Check if we need to generate multiple colors | |
if (options.count !== null && options.count !== undefined) { | |
var totalColors = options.count, | |
colors = []; | |
options.count = null; | |
while (totalColors > colors.length) { | |
// Since we're generating multiple colors, | |
// incremement the seed. Otherwise we'd just | |
// generate the same color each time... | |
if (seed && options.seed) options.seed += 1; | |
colors.push(randomColor(options)); | |
} | |
options.count = totalColors; | |
return colors; | |
} | |
// First we pick a hue (H) | |
H = pickHue(options); | |
// Then use H to determine saturation (S) | |
S = pickSaturation(H, options); | |
// Then use S and H to determine brightness (B). | |
B = pickBrightness(H, S, options); | |
// Then we return the HSB color in the desired format | |
return setFormat([H,S,B], options); | |
}; | |
function pickHue (options) { | |
var hueRange = getHueRange(options.hue), | |
hue = randomWithin(hueRange); | |
// Instead of storing red as two seperate ranges, | |
// we group them, using negative numbers | |
if (hue < 0) {hue = 360 + hue;} | |
return hue; | |
} | |
function pickSaturation (hue, options) { | |
if (options.luminosity === 'random') { | |
return randomWithin([0,100]); | |
} | |
if (options.hue === 'monochrome') { | |
return 0; | |
} | |
var saturationRange = getSaturationRange(hue); | |
var sMin = saturationRange[0], | |
sMax = saturationRange[1]; | |
switch (options.luminosity) { | |
case 'bright': | |
sMin = 55; | |
break; | |
case 'dark': | |
sMin = sMax - 10; | |
break; | |
case 'light': | |
sMax = 55; | |
break; | |
} | |
return randomWithin([sMin, sMax]); | |
} | |
function pickBrightness (H, S, options) { | |
var bMin = getMinimumBrightness(H, S), | |
bMax = 100; | |
switch (options.luminosity) { | |
case 'dark': | |
bMax = bMin + 20; | |
break; | |
case 'light': | |
bMin = (bMax + bMin)/2; | |
break; | |
case 'random': | |
bMin = 0; | |
bMax = 100; | |
break; | |
} | |
return randomWithin([bMin, bMax]); | |
} | |
function setFormat (hsv, options) { | |
switch (options.format) { | |
case 'hsvArray': | |
return hsv; | |
case 'hslArray': | |
return HSVtoHSL(hsv); | |
case 'hsl': | |
var hsl = HSVtoHSL(hsv); | |
return 'hsl('+hsl[0]+', '+hsl[1]+'%, '+hsl[2]+'%)'; | |
case 'hsla': | |
var hslColor = HSVtoHSL(hsv); | |
return 'hsla('+hslColor[0]+', '+hslColor[1]+'%, '+hslColor[2]+'%, ' + Math.random() + ')'; | |
case 'rgbArray': | |
return HSVtoRGB(hsv); | |
case 'rgb': | |
var rgb = HSVtoRGB(hsv); | |
return 'rgb(' + rgb.join(', ') + ')'; | |
case 'rgba': | |
var rgbColor = HSVtoRGB(hsv); | |
return 'rgba(' + rgbColor.join(', ') + ', ' + Math.random() + ')'; | |
default: | |
return HSVtoHex(hsv); | |
} | |
} | |
function getMinimumBrightness(H, S) { | |
var lowerBounds = getColorInfo(H).lowerBounds; | |
for (var i = 0; i < lowerBounds.length - 1; i++) { | |
var s1 = lowerBounds[i][0], | |
v1 = lowerBounds[i][1]; | |
var s2 = lowerBounds[i+1][0], | |
v2 = lowerBounds[i+1][1]; | |
if (S >= s1 && S <= s2) { | |
var m = (v2 - v1)/(s2 - s1), | |
b = v1 - m*s1; | |
return m*S + b; | |
} | |
} | |
return 0; | |
} | |
function getHueRange (colorInput) { | |
if (typeof parseInt(colorInput) === 'number') { | |
var number = parseInt(colorInput); | |
if (number < 360 && number > 0) { | |
return [number, number]; | |
} | |
} | |
if (typeof colorInput === 'string') { | |
if (colorDictionary[colorInput]) { | |
var color = colorDictionary[colorInput]; | |
if (color.hueRange) {return color.hueRange;} | |
} | |
} | |
return [0,360]; | |
} | |
function getSaturationRange (hue) { | |
return getColorInfo(hue).saturationRange; | |
} | |
function getColorInfo (hue) { | |
// Maps red colors to make picking hue easier | |
if (hue >= 334 && hue <= 360) { | |
hue-= 360; | |
} | |
for (var colorName in colorDictionary) { | |
var color = colorDictionary[colorName]; | |
if (color.hueRange && | |
hue >= color.hueRange[0] && | |
hue <= color.hueRange[1]) { | |
return colorDictionary[colorName]; | |
} | |
} return 'Color not found'; | |
} | |
function randomWithin (range) { | |
if (seed === null) { | |
return Math.floor(range[0] + Math.random()*(range[1] + 1 - range[0])); | |
} else { | |
//Seeded random algorithm from http://indiegamr.com/generate-repeatable-random-numbers-in-js/ | |
var max = range[1] || 1; | |
var min = range[0] || 0; | |
seed = (seed * 9301 + 49297) % 233280; | |
var rnd = seed / 233280.0; | |
return Math.floor(min + rnd * (max - min)); | |
} | |
} | |
function HSVtoHex (hsv){ | |
var rgb = HSVtoRGB(hsv); | |
function componentToHex(c) { | |
var hex = c.toString(16); | |
return hex.length == 1 ? '0' + hex : hex; | |
} | |
var hex = '#' + componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]); | |
return hex; | |
} | |
function defineColor (name, hueRange, lowerBounds) { | |
var sMin = lowerBounds[0][0], | |
sMax = lowerBounds[lowerBounds.length - 1][0], | |
bMin = lowerBounds[lowerBounds.length - 1][1], | |
bMax = lowerBounds[0][1]; | |
colorDictionary[name] = { | |
hueRange: hueRange, | |
lowerBounds: lowerBounds, | |
saturationRange: [sMin, sMax], | |
brightnessRange: [bMin, bMax] | |
}; | |
} | |
function loadColorBounds () { | |
defineColor( | |
'monochrome', | |
null, | |
[[0,0],[100,0]] | |
); | |
defineColor( | |
'red', | |
[-26,18], | |
[[20,100],[30,92],[40,89],[50,85],[60,78],[70,70],[80,60],[90,55],[100,50]] | |
); | |
defineColor( | |
'orange', | |
[19,46], | |
[[20,100],[30,93],[40,88],[50,86],[60,85],[70,70],[100,70]] | |
); | |
defineColor( | |
'yellow', | |
[47,62], | |
[[25,100],[40,94],[50,89],[60,86],[70,84],[80,82],[90,80],[100,75]] | |
); | |
defineColor( | |
'green', | |
[63,178], | |
[[30,100],[40,90],[50,85],[60,81],[70,74],[80,64],[90,50],[100,40]] | |
); | |
defineColor( | |
'blue', | |
[179, 257], | |
[[20,100],[30,86],[40,80],[50,74],[60,60],[70,52],[80,44],[90,39],[100,35]] | |
); | |
defineColor( | |
'purple', | |
[258, 282], | |
[[20,100],[30,87],[40,79],[50,70],[60,65],[70,59],[80,52],[90,45],[100,42]] | |
); | |
defineColor( | |
'pink', | |
[283, 334], | |
[[20,100],[30,90],[40,86],[60,84],[80,80],[90,75],[100,73]] | |
); | |
} | |
function HSVtoRGB (hsv) { | |
// this doesn't work for the values of 0 and 360 | |
// here's the hacky fix | |
var h = hsv[0]; | |
if (h === 0) {h = 1;} | |
if (h === 360) {h = 359;} | |
// Rebase the h,s,v values | |
h = h/360; | |
var s = hsv[1]/100, | |
v = hsv[2]/100; | |
var h_i = Math.floor(h*6), | |
f = h * 6 - h_i, | |
p = v * (1 - s), | |
q = v * (1 - f*s), | |
t = v * (1 - (1 - f)*s), | |
r = 256, | |
g = 256, | |
b = 256; | |
switch(h_i) { | |
case 0: r = v; g = t; b = p; break; | |
case 1: r = q; g = v; b = p; break; | |
case 2: r = p; g = v; b = t; break; | |
case 3: r = p; g = q; b = v; break; | |
case 4: r = t; g = p; b = v; break; | |
case 5: r = v; g = p; b = q; break; | |
} | |
var result = [Math.floor(r*255), Math.floor(g*255), Math.floor(b*255)]; | |
return result; | |
} | |
function HSVtoHSL (hsv) { | |
var h = hsv[0], | |
s = hsv[1]/100, | |
v = hsv[2]/100, | |
k = (2-s)*v; | |
return [ | |
h, | |
Math.round(s*v / (k<1 ? k : 2-k) * 10000) / 100, | |
k/2 * 100 | |
]; | |
} | |
function stringToInteger (string) { | |
var total = 0 | |
for (var i = 0; i !== string.length; i++) { | |
if (total >= Number.MAX_SAFE_INTEGER) break; | |
total += string.charCodeAt(i) | |
} | |
return total | |
} | |
return randomColor; | |
})); | |
// }}} | |
// {{{ getTable | |
(function($, undefined) { | |
'use strict'; | |
var APP_NAME = 'getTable', | |
tables = []; // array of reference table | |
function parseTable(jq, index) { | |
var table = {rows: [], cols: [], cells: []}, | |
iTable = typeof index === 'number' ? index : tables.length, | |
iColMax = -1, skip = {}, // {N<iRow>: {N<iCol>: B}} | |
elmTable = jq.get(0).nodeName.toLowerCase() === 'table' ? jq.get(0) : | |
(function() { | |
var elm = jq.closest('table'); | |
return elm.length ? elm.get(0) : undefined; | |
})(); | |
if (!elmTable) { return; } | |
table.elm = elmTable; | |
$(elmTable).data(APP_NAME, 'table:' + iTable); | |
function getRow(index) { | |
var i; | |
if (!table.rows[index]) { | |
for (i = 0; i <= index; i++) | |
{ table.rows[i] = table.rows[i] || {cells: [], table: table}; } | |
} | |
return table.rows[index]; | |
} | |
function getCol(index) { | |
var i; | |
if (!table.cols[index]) { | |
for (i = 0; i <= index; i++) | |
{ table.cols[i] = table.cols[i] || {cells: [], table: table}; } | |
} | |
return table.cols[index]; | |
} | |
$.each(elmTable.rows, function(iRow, elmRow) { | |
var row, col, cell, iCol, iCell = 0, elmCell, exRows, exCols, i, j; | |
$(elmRow).data(APP_NAME, 'table:' + iTable + ',row:' + iRow); | |
(function() { | |
var colsLen = 0; | |
$.each(elmRow.cells, function(i, cell) { colsLen += +cell.colSpan || 1; }); | |
if (colsLen - 1 > iColMax) { iColMax = colsLen - 1; } | |
})(); | |
for (iCol = 0; iCol <= iColMax; iCol++) { | |
if (skip[iRow] && skip[iRow][iCol]) { continue; } | |
if (elmCell = elmRow.cells[iCell++]) { | |
$(elmCell).data(APP_NAME, 'table:' + iTable + ',cell:' + table.cells.length); | |
cell = {elm: elmCell, rows: [], cols: [], table: table, iRow: iRow, iCol: iCol}; | |
// extending via colspan="0", colgroup and rowspan="0" isn't supported. | |
// http://dev.w3.org/html5/spec/single-page.html#attr-tdth-colspan | |
exRows = (+elmCell.rowSpan || 1) - 1; | |
exCols = (+elmCell.colSpan || 1) - 1; | |
for (i = 0; i <= exRows; i++) { | |
row = getRow(iRow + i); | |
cell.rows.push(row); | |
row.cells.push(cell); | |
} | |
for (i = 0; i <= exCols; i++) { | |
col = getCol(iCol + i); | |
cell.cols.push(col); | |
col.cells.push(cell); | |
} | |
for (i = 1; i <= exRows; i++) { | |
skip[iRow + i] = skip[iRow + i] || {}; | |
for (j = 0; j <= exCols; j++) { skip[iRow + i][iCol + j] = true; } | |
} | |
iCol += exCols; | |
table.cells.push(cell); | |
} | |
} | |
}); | |
// cross line cells | |
$.each(table.cells, function(i, cell) { | |
var xCells = [cell]; | |
$.each(cell.rows.concat(cell.cols), | |
function(i, rowCol) { uniqueConcat(xCells, rowCol.cells); }); | |
cell.xCells = xCells; | |
}); | |
$.each(table.rows, | |
function(i, row) { row.cells.sort(function(a, b) { return a.iCol - b.iCol; }); }); | |
$.each(table.cols, | |
function(i, col) { col.cells.sort(function(a, b) { return a.iRow - b.iRow; }); }); | |
tables[iTable] = table; | |
return table; | |
} | |
function uniqueConcat(arrBase, arrNew) { | |
$.each(arrNew, function(i, elm) { | |
if ($.inArray(elm, arrBase) < 0) { arrBase.push(elm); } | |
}); | |
} | |
// {table: N, row: N, cell: N} | |
function parseIndex(jq) { | |
var index = {}, indexText = jq.data(APP_NAME) || '', | |
re = /\b(\w+):(\d+)/g, matches; | |
while ((matches = re.exec(indexText)) !== null) { | |
index[matches[1]] = +matches[2]; | |
} | |
return index; | |
} | |
function getParse(jq, force) { | |
var iTable = parseIndex(jq).table; | |
return force || typeof iTable !== 'number' || !tables[iTable] ? | |
parseTable(jq, iTable) : tables[iTable]; | |
} | |
function isTable(tagName) { return tagName === 'table'; } | |
function isRow(tagName) { return tagName === 'tr'; } | |
function isCell(tagName) { return tagName === 'td' || tagName === 'th'; } | |
function isSection(tagName) { return tagName === 'thead' || tagName === 'tfoot' || tagName === 'tbody'; } | |
function isAny(tagName) | |
{ return isTable(tagName) || isRow(tagName) || isCell(tagName) || isSection(tagName); } | |
// Array of cell objects -> Array of elements | |
function cells2Elms(cells) { return $.map(cells, function(cell) { return cell.elm; }); } | |
// Array of cell objects -> jQuery object | |
function cells2Jq(cells) { return $(cells2Elms(cells)); } | |
function selectCells(jq) { | |
var elms = []; | |
jq.each(function() { | |
var that = $(this), tagName = that.get(0).nodeName.toLowerCase(), table; | |
if (isTable(tagName) && (table = getParse(that))) { | |
uniqueConcat(elms, cells2Elms(table.cells)); | |
} else if (isRow(tagName) && (table = getParse(that))) { | |
uniqueConcat(elms, cells2Elms(table.rows[parseIndex(that).row].cells)); | |
} else if (isCell(tagName) && (table = getParse(that))) { | |
uniqueConcat(elms, [table.cells[parseIndex(that).cell].elm]); // same as that.get(0) | |
} else if (isSection(tagName) && (table = getParse(that))) { | |
$.each(that.get(0).rows, function(i, elmRow) { | |
uniqueConcat(elms, cells2Elms(table.rows[parseIndex($(elmRow)).row].cells)); | |
}); | |
} | |
}); | |
return $(elms.length ? elms : null); | |
} | |
function selectXCells(jq) { | |
var elms = []; | |
jq.each(function() { | |
var that = $(this), tagName = that.get(0).nodeName.toLowerCase(), table; | |
if (isCell(tagName) && (table = getParse(that))) { | |
uniqueConcat(elms, cells2Elms(table.cells[parseIndex(that).cell].xCells)); | |
} | |
}); | |
return $(elms.length ? elms : null); | |
} | |
function selectRows(jq) { | |
return $.map(selectRowsArray(jq), function(row) { return cells2Jq(row.cells); }); | |
} | |
function selectRowsCells(jq) { | |
var elms = []; | |
$.each(selectRowsArray(jq), | |
function(i, row) { uniqueConcat(elms, cells2Elms(row.cells)); }); | |
return $(elms.length ? elms : null); | |
} | |
function selectRowsArray(jq) { | |
var rows = []; | |
jq.each(function() { | |
var that = $(this), tagName = that.get(0).nodeName.toLowerCase(), table; | |
if (isTable(tagName) && (table = getParse(that))) { | |
uniqueConcat(rows, table.rows); | |
} else if (isRow(tagName) && (table = getParse(that))) { | |
uniqueConcat(rows, [table.rows[parseIndex(that).row]]); | |
} else if (isCell(tagName) && (table = getParse(that))) { | |
uniqueConcat(rows, table.cells[parseIndex(that).cell].rows); | |
} else if (isSection(tagName) && (table = getParse(that))) { | |
uniqueConcat(rows, $.map(that.get(0).rows, function(elmRow) | |
{ return table.rows[parseIndex($(elmRow)).row]; })); | |
} | |
}); | |
return rows; | |
} | |
function selectCols(jq) { | |
return $.map(selectColsArray(jq), function(col) { return cells2Jq(col.cells); }); | |
} | |
function selectColsCells(jq) { | |
var elms = []; | |
$.each(selectColsArray(jq), | |
function(i, col) { uniqueConcat(elms, cells2Elms(col.cells)); }); | |
return $(elms.length ? elms : null); | |
} | |
function selectColsArray(jq) { | |
var cols = []; | |
jq.each(function() { | |
var that = $(this), tagName = that.get(0).nodeName.toLowerCase(), table; | |
if ((isTable(tagName) || isRow(tagName) || isSection(tagName)) && | |
(table = getParse(that))) { | |
uniqueConcat(cols, table.cols); | |
} else if (isCell(tagName) && (table = getParse(that))) { | |
uniqueConcat(cols, table.cells[parseIndex(that).cell].cols); | |
} | |
}); | |
return cols; | |
} | |
function selectTable(jq) { | |
var elms = []; | |
jq.each(function() { | |
var that = $(this), tagName = that.get(0).nodeName.toLowerCase(), table; | |
if (isAny(tagName) && (table = getParse(that))) { | |
uniqueConcat(elms, [table.elm]); // same as that.get(0) | |
} | |
}); | |
return $(elms.length ? elms : null); | |
} | |
function reParse(jq) { | |
return jq.each(function() { | |
var that = $(this), tagName = that.get(0).nodeName.toLowerCase(); | |
if (isAny(tagName)) { getParse(that, true); } | |
}); | |
} | |
$.fn[APP_NAME] = function(action) { | |
return ( | |
action === 'cells' ? selectCells(this) : | |
action === 'xCells' ? selectXCells(this) : | |
action === 'rows' ? selectRows(this) : | |
action === 'rowsCells' ? selectRowsCells(this) : | |
action === 'cols' ? selectCols(this) : | |
action === 'colsCells' ? selectColsCells(this) : | |
action === 'table' ? selectTable(this) : | |
reParse(this)); | |
}; | |
})(jQuery); | |
// }}} | |
// {{{ sprintf | |
/* globals window, exports, define */ | |
(function(window) { | |
'use strict' | |
var re = { | |
not_string: /[^s]/, | |
not_bool: /[^t]/, | |
not_type: /[^T]/, | |
not_primitive: /[^v]/, | |
number: /[diefg]/, | |
numeric_arg: /bcdiefguxX/, | |
json: /[j]/, | |
not_json: /[^j]/, | |
text: /^[^\x25]+/, | |
modulo: /^\x25{2}/, | |
placeholder: /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-gijostTuvxX])/, | |
key: /^([a-z_][a-z_\d]*)/i, | |
key_access: /^\.([a-z_][a-z_\d]*)/i, | |
index_access: /^\[(\d+)\]/, | |
sign: /^[\+\-]/ | |
} | |
function sprintf() { | |
var key = arguments[0], cache = sprintf.cache | |
if (!(cache[key] && cache.hasOwnProperty(key))) { | |
cache[key] = sprintf.parse(key) | |
} | |
return sprintf.format.call(null, cache[key], arguments) | |
} | |
sprintf.format = function(parse_tree, argv) { | |
var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length, is_positive = true, sign = '' | |
for (i = 0; i < tree_length; i++) { | |
node_type = get_type(parse_tree[i]) | |
if (node_type === 'string') { | |
output[output.length] = parse_tree[i] | |
} | |
else if (node_type === 'array') { | |
match = parse_tree[i] // convenience purposes only | |
if (match[2]) { // keyword argument | |
arg = argv[cursor] | |
for (k = 0; k < match[2].length; k++) { | |
if (!arg.hasOwnProperty(match[2][k])) { | |
throw new Error(sprintf('[sprintf] property "%s" does not exist', match[2][k])) | |
} | |
arg = arg[match[2][k]] | |
} | |
} | |
else if (match[1]) { // positional argument (explicit) | |
arg = argv[match[1]] | |
} | |
else { // positional argument (implicit) | |
arg = argv[cursor++] | |
} | |
if (re.not_type.test(match[8]) && re.not_primitive.test(match[8]) && get_type(arg) == 'function') { | |
arg = arg() | |
} | |
if (re.numeric_arg.test(match[8]) && (get_type(arg) != 'number' && isNaN(arg))) { | |
throw new TypeError(sprintf("[sprintf] expecting number but found %s", get_type(arg))) | |
} | |
if (re.number.test(match[8])) { | |
is_positive = arg >= 0 | |
} | |
switch (match[8]) { | |
case 'b': | |
arg = parseInt(arg, 10).toString(2) | |
break | |
case 'c': | |
arg = String.fromCharCode(parseInt(arg, 10)) | |
break | |
case 'd': | |
case 'i': | |
arg = parseInt(arg, 10) | |
break | |
case 'j': | |
arg = JSON.stringify(arg, null, match[6] ? parseInt(match[6]) : 0) | |
break | |
case 'e': | |
arg = match[7] ? parseFloat(arg).toExponential(match[7]) : parseFloat(arg).toExponential() | |
break | |
case 'f': | |
arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg) | |
break | |
case 'g': | |
arg = match[7] ? parseFloat(arg).toPrecision(match[7]) : parseFloat(arg) | |
break | |
case 'o': | |
arg = arg.toString(8) | |
break | |
case 's': | |
arg = String(arg) | |
arg = (match[7] ? arg.substring(0, match[7]) : arg) | |
break | |
case 't': | |
arg = String(!!arg) | |
arg = (match[7] ? arg.substring(0, match[7]) : arg) | |
break | |
case 'T': | |
arg = get_type(arg) | |
arg = (match[7] ? arg.substring(0, match[7]) : arg) | |
break | |
case 'u': | |
arg = parseInt(arg, 10) >>> 0 | |
break | |
case 'v': | |
arg = arg.valueOf() | |
arg = (match[7] ? arg.substring(0, match[7]) : arg) | |
break | |
case 'x': | |
arg = parseInt(arg, 10).toString(16) | |
break | |
case 'X': | |
arg = parseInt(arg, 10).toString(16).toUpperCase() | |
break | |
} | |
if (re.json.test(match[8])) { | |
output[output.length] = arg | |
} | |
else { | |
if (re.number.test(match[8]) && (!is_positive || match[3])) { | |
sign = is_positive ? '+' : '-' | |
arg = arg.toString().replace(re.sign, '') | |
} | |
else { | |
sign = '' | |
} | |
pad_character = match[4] ? match[4] === '0' ? '0' : match[4].charAt(1) : ' ' | |
pad_length = match[6] - (sign + arg).length | |
pad = match[6] ? (pad_length > 0 ? str_repeat(pad_character, pad_length) : '') : '' | |
output[output.length] = match[5] ? sign + arg + pad : (pad_character === '0' ? sign + pad + arg : pad + sign + arg) | |
} | |
} | |
} | |
return output.join('') | |
} | |
sprintf.cache = {} | |
sprintf.parse = function(fmt) { | |
var _fmt = fmt, match = [], parse_tree = [], arg_names = 0 | |
while (_fmt) { | |
if ((match = re.text.exec(_fmt)) !== null) { | |
parse_tree[parse_tree.length] = match[0] | |
} | |
else if ((match = re.modulo.exec(_fmt)) !== null) { | |
parse_tree[parse_tree.length] = '%' | |
} | |
else if ((match = re.placeholder.exec(_fmt)) !== null) { | |
if (match[2]) { | |
arg_names |= 1 | |
var field_list = [], replacement_field = match[2], field_match = [] | |
if ((field_match = re.key.exec(replacement_field)) !== null) { | |
field_list[field_list.length] = field_match[1] | |
while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') { | |
if ((field_match = re.key_access.exec(replacement_field)) !== null) { | |
field_list[field_list.length] = field_match[1] | |
} | |
else if ((field_match = re.index_access.exec(replacement_field)) !== null) { | |
field_list[field_list.length] = field_match[1] | |
} | |
else { | |
throw new SyntaxError("[sprintf] failed to parse named argument key") | |
} | |
} | |
} | |
else { | |
throw new SyntaxError("[sprintf] failed to parse named argument key") | |
} | |
match[2] = field_list | |
} | |
else { | |
arg_names |= 2 | |
} | |
if (arg_names === 3) { | |
throw new Error("[sprintf] mixing positional and named placeholders is not (yet) supported") | |
} | |
parse_tree[parse_tree.length] = match | |
} | |
else { | |
throw new SyntaxError("[sprintf] unexpected placeholder") | |
} | |
_fmt = _fmt.substring(match[0].length) | |
} | |
return parse_tree | |
} | |
var vsprintf = function(fmt, argv, _argv) { | |
_argv = (argv || []).slice(0) | |
_argv.splice(0, 0, fmt) | |
return sprintf.apply(null, _argv) | |
} | |
/** | |
* helpers | |
*/ | |
function get_type(variable) { | |
if (typeof variable === 'number') { | |
return 'number' | |
} | |
else if (typeof variable === 'string') { | |
return 'string' | |
} | |
else { | |
return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase() | |
} | |
} | |
var preformattedPadding = { | |
'0': ['', '0', '00', '000', '0000', '00000', '000000', '0000000'], | |
' ': ['', ' ', ' ', ' ', ' ', ' ', ' ', ' '], | |
'_': ['', '_', '__', '___', '____', '_____', '______', '_______'], | |
} | |
function str_repeat(input, multiplier) { | |
if (multiplier >= 0 && multiplier <= 7 && preformattedPadding[input]) { | |
return preformattedPadding[input][multiplier] | |
} | |
return Array(multiplier + 1).join(input) | |
} | |
/** | |
* export to either browser or node.js | |
*/ | |
if (typeof exports !== 'undefined') { | |
exports.sprintf = sprintf | |
exports.vsprintf = vsprintf | |
} | |
else { | |
window.sprintf = sprintf | |
window.vsprintf = vsprintf | |
if (typeof define === 'function' && define.amd) { | |
define(function() { | |
return { | |
sprintf: sprintf, | |
vsprintf: vsprintf | |
} | |
}) | |
} | |
} | |
})(typeof window === 'undefined' ? this : window); | |
// }}} | |
// }}} | |
var lessons = [[], [], [], [], []]; | |
$("table.print > tbody > tr:first > *:gt(1)").each(function(day) { // All headers, except the first two | |
$(this).getTable("colsCells").filter(":gt(0):not(.printLight)").each(function() { | |
table = []; | |
$("> table.inline > tbody > tr", $(this)).each(function() { | |
table.push(row2 = []); | |
$("td", $(this)).each(function() { | |
row2.push($(this).text().trim()); | |
}); | |
}); | |
var name, start, end, room, name2, teacher, term; | |
if(table[1].length == 1) { | |
name = table[0][0]; | |
start = table[1][0]; | |
end = table[2][0].substring(1); | |
room = table[3][0]; | |
name2 = table[4][0]; | |
} else { | |
name = table[0][0]; | |
start = table[0][1]; | |
end = table[1][1].substring(1); | |
room = table[1][0]; | |
if(table.length > 2) name2 = table[2][0]; | |
if(table.length > 3) teacher = table[3][0]; | |
} | |
function ptime(stamp) { | |
var p = stamp.split(":"); | |
return parseInt(p[0], 10) * 60 + parseInt(p[1], 10); | |
} | |
lessons[day].push({ | |
"name": name, | |
"name2": (name2 || name).replace(/^IV-/, "").replace(/-.*$/, "").trim(), | |
"start": ptime(start), | |
"end": ptime(end), | |
"room": room, | |
"teacher": (teacher || "").toLowerCase(), | |
}); | |
}); | |
}); | |
var start = 8*60, end = 17*60; | |
function percent(n) (n / (end - start) * 100) + "%" | |
function time(n) sprintf("%02d:%02d", Math.floor(n / 60), Math.floor(n % 60)) | |
function schedule(dayName, lessons) { | |
var el = $() | |
for(l of lessons) { | |
var seed = 0; | |
for(n in l.name2) seed ^= l.name2.charCodeAt(n) << (8 * (n % 8)); | |
el = el.add( | |
$("<div class=lesson>") | |
.css({ | |
"top": percent(l["start"] - 8 * 60), | |
"height": percent(l["end"] - l["start"]), | |
"background-color": randomColor({ "luminosity": "light", "seed": seed & 0xFFFFFFFF }) | |
}) | |
.append($("<div class=content>") | |
.append($("<div>").text(l.name2)) | |
.append($("<div>").text(time(l.start) + '-' + time(l.end))) | |
.append($("<div>").text(l.room)) | |
.append($("<div>").text(l.teacher)) | |
) | |
); | |
} | |
console.log(el) | |
return $("<div class='col sched'>") | |
.append($("<div class=head>").text(dayName)) | |
.append($("<div class=col-cont>").append(el)) | |
} | |
function ruler() { | |
var el = $(); | |
var n = 30; | |
for(var i = start; i < end; i += n) | |
el = el.add($("<div class=ruler-item>").css("height", percent(n)).text(time(i))) | |
return $("<div class='col ruler-col'>") | |
.append($("<div class=head>").text($(".printLarge").text().trim().split(" ").pop())) | |
.append($("<div class=col-cont>").append(el)) | |
} | |
var shadow = "0 0 1px 0px #0F0F0F" | |
var css = ` | |
html, body { | |
margin: 0; | |
padding: 0; | |
width: 100%; | |
height: 100%; | |
} | |
body { | |
display: flex; | |
flex-direction: row; | |
font: 10px sans-serif; | |
} | |
.head { | |
box-shadow: ${shadow} inset, ${shadow}; | |
overflow: hidden; | |
background: white; | |
font-size: 150%; | |
padding: .25em; | |
height: 1em; | |
flex: 0 0 auto; | |
} | |
.col { | |
align-self: stretch; | |
display: flex; | |
flex-direction: column; | |
} | |
.col-cont { | |
box-shadow: ${shadow} inset; | |
overflow: hidden; | |
position: relative; | |
flex: 1 0 auto; | |
} | |
.sched { | |
flex: 1 0 auto; | |
text-align: center; | |
} | |
.sched > .col-cont { | |
background: #AFAFAF; | |
} | |
.lesson { | |
position: absolute; | |
width: 100%; | |
box-shadow: ${shadow} inset, ${shadow}; | |
overflow: hidden; | |
display: flex; | |
flex-direction: row; | |
justify-content: center; | |
align-content: center; | |
align-items: center; | |
} | |
.ruler { | |
flex: 0 0 auto; | |
width: 8em; | |
} | |
.ruler > .col-cont { | |
} | |
.ruler-item { | |
box-shadow: ${shadow} inset, ${shadow}; | |
overflow: hidden; | |
display: flex; | |
flex-direction: row; | |
justify-content: center; | |
align-content: center; | |
align-items: center; | |
} | |
` | |
$(":root").replaceWith( | |
$("<html>") | |
.append( | |
$("<head>") | |
.append($("<meta charset=utf-8>")) | |
.append($("<title>").text("Schedule")) | |
.append($("<style>").html(css)) | |
) | |
.append( | |
$("<body>") | |
.append(ruler()) | |
.append(schedule("Mon", lessons[0])) | |
.append(schedule("Tue", lessons[1])) | |
.append(schedule("Wed", lessons[2])) | |
.append(schedule("Thu", lessons[3])) | |
.append(schedule("Fri", lessons[4])) | |
) | |
); | |
})(); | |
// vim: foldmethod=marker |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment