diff --git a/cpm/how-to-markup-tablature.mr-ukegeek.cpm.txt b/cpm/how-to-markup-tablature.mr-ukegeek.cpm.txt index 9956c39..69657d9 100644 --- a/cpm/how-to-markup-tablature.mr-ukegeek.cpm.txt +++ b/cpm/how-to-markup-tablature.mr-ukegeek.cpm.txt @@ -49,3 +49,22 @@ C|-0-----------|-0--------- G|-------------|----------- {eot} A pen-ny a kiss | A pen-ny a hug + +{c: Mulitple Tab Staffs In One Block} + +These begin/end tab block markers wrap two Staffs. +Also, note that the second groups lines are "uneven"; +in this case the longest line sets final width/length. + +{start_of_tab} +A----------------------------------------------0----------0---2---2--| +E---0-------0---2-------0---2---3------2---3----------3--------------| +C-------3------------------------------------------------------------| +G--------------------------------------------------------------------| + +A----------2---0-----------------------------------------------------| +E---0--------------3---2---0----------- +C----------------------------------------- +G--------------- +{eot} + diff --git a/js/editor/ugsChordBuilder.js b/js/editor/ugsChordBuilder.js index 732effe..996dae3 100644 --- a/js/editor/ugsChordBuilder.js +++ b/js/editor/ugsChordBuilder.js @@ -106,9 +106,10 @@ ugsChordBuilder.settings = (function() { //'Geneva, "Lucida Sans", "Lucida Grande", "Lucida Sans Unicode", Verdana, Arial, sans-serif'; /** - * San-Serif font stack used on Canvas - * @constant FONT_STACK - * @type {String} + * San-serif font stack used when drawing text on Canvas. + * @property {String} FONT_STACK + * @final + * @constant */ var FONT_STACK = 'Arial, "Helvetica Neue", Helvetica, Verdana, sans-serif'; @@ -333,7 +334,8 @@ ugsChordBuilder.fretDots = new function() { var index = find(dot); if (index < 0) { _dots.push(dot); - } else { + } + else { _dots.splice(index, 1); } }; @@ -502,7 +504,8 @@ ugsChordBuilder.cursorCanvas = new function() { erase(_lastPos); if (!_imgOk || _dotCursor) { drawDotCursor(pos); - } else { + } + else { drawHandCursor(pos); } _lastPos = pos; diff --git a/js/editor/ugsEditorPlus.typeahead.js b/js/editor/ugsEditorPlus.typeahead.js index 53fb9f2..9ef7948 100644 --- a/js/editor/ugsEditorPlus.typeahead.js +++ b/js/editor/ugsEditorPlus.typeahead.js @@ -44,8 +44,6 @@ ugsEditorPlus.typeahead = function(){ var $this = $(this); var plainText = crushText($this.text()); - plainText = plainText.toLowerCase(); - var href = $this.children('a').attr('href'); var key = href.toLowerCase(); diff --git a/js/scriptasaurus/ukeGeeks.definitions.sopranoUkuleleGcea.js b/js/scriptasaurus/ukeGeeks.definitions.sopranoUkuleleGcea.js index b6be107..60f49fd 100644 --- a/js/scriptasaurus/ukeGeeks.definitions.sopranoUkuleleGcea.js +++ b/js/scriptasaurus/ukeGeeks.definitions.sopranoUkuleleGcea.js @@ -157,7 +157,7 @@ ukeGeeks.definitions.sopranoUkuleleGcea = [ // ------------------------------------------------------- '{define: F# frets 3 1 2 1 fingers 3 1 2 1 add: string 1 fret 1 finger 1 add: string 3 fret 1 finger 1}', '{define: F#m frets 2 1 2 0 fingers 2 1 3 0}', - '{define: F#7 frets 3 4 2 1 fingers 3 4 2 1}', + '{define: F#7 frets 3 4 2 4 fingers 2 3 1 4}', '{define: F#7sus4 frets 4 4 2 4 fingers 2 3 1 4}', '{define: F#m7 frets 2 4 2 4 fingers 1 3 2 4}', '{define: F#dim frets 2 3 2 3 fingers 1 3 2 4}', diff --git a/js/scriptasaurus/ukeGeeks.tabs.js b/js/scriptasaurus/ukeGeeks.tabs.js index 2cd04ed..14176ff 100644 --- a/js/scriptasaurus/ukeGeeks.tabs.js +++ b/js/scriptasaurus/ukeGeeks.tabs.js @@ -6,53 +6,63 @@ * @constructor * @namespace ukeGeeks */ -ukeGeeks.tabs = function(){}; +ukeGeeks.tabs = function() { -ukeGeeks.tabs.prototype = { + /** + * alias for external Settings dependencies (helps with complression, too) + * @property tab_settings + * @private + * @type {JSON} + */ + var tab_settings = ukeGeeks.settings.tabs; + + // TODO: use ukeGeeks.settings.tuning for NUM_STRINGS and LAST_STRING_NAME?? /** * (Constant) Number of Strings (dashed lines of tablature notation) expected. (For now * a constant -- ukueleles "always" have four). Making a variable to help support port * for other instruments. - * @property _numStrings + * @property NUM_STRINGS * @private * @type int */ - _numStrings: 4, + var NUM_STRINGS= 4; /** * (Constant) Last String Name (Note), as above, on Ukulele is a "G". Here for other instruments. - * @property _lastStringName + * @property LAST_STRING_NAME * @private * @type string */ - _lastStringName: 'G', + var LAST_STRING_NAME= 'G'; /* PUBLIC METHODS ---------------------------------------------- */ /** * Again this is a constructor replacement * @method init + * @public * @return {void} */ - init: function() {}, + var init= function() {}; /** * Races through all <pre> tags within h, any with the CSS class of "ugsTabs" will be replaced with the canvas element. * @method replace + * @public * @param h {DOM-element} * @return {void} */ - replace: function(h){ + var replace= function(h) { var tabBlocks = h.getElementsByTagName('pre'); for (var i in tabBlocks){ if (tabBlocks[i].className == 'ugsTabs'){ var s = tabBlocks[i].innerHTML; tabBlocks[i].innerHTML = ''; - this.loadBlocks(s,tabBlocks[i]); + loadBlocks(s, tabBlocks[i]); } } - }, + }; /** * @@ -61,7 +71,7 @@ ukeGeeks.tabs.prototype = { * @param outElement {string or DOM} Either: (string) the Id to a DOM element, or DOM element handle where the canvas/converted text will be placed. * @return {void} */ - loadBlocks: function(text, outElement){ + var loadBlocks= function(text, outElement) { var lines = text.split('\n'); var tab = []; for (var i in lines) { @@ -69,12 +79,12 @@ ukeGeeks.tabs.prototype = { if (s.length > 0){ tab.push(s); } - if (tab.length == this._numStrings) { - this.redraw(tab, outElement); + if (tab.length == NUM_STRINGS) { + redraw(tab, outElement); tab = []; } } - }, + }; /** * @@ -83,162 +93,172 @@ ukeGeeks.tabs.prototype = { * @param outElement {string or DOM} Either: (string) the Id to a DOM element, or DOM element handle where the canvas/converted text will be placed. * @return {void} */ - redraw: function(inTabs, outElement){ + var redraw= function(inTabs, outElement) { // validate inTabs input... // TODO: instead of this if it's text pop the entire processing back to loadBlocks! inTabs = (typeof(inTabs) == 'string') ? (inTabs.split('\n')) : inTabs; - if (inTabs.length < this._numStrings) { + if (inTabs.length < NUM_STRINGS) { return; } // read tabs - var tabInfo = this._readTabs(inTabs); - var labelOffset = (tabInfo.hasLabels) ? ukeGeeks.settings.tabs.labelWidth: 0; + var tabInfo = readTabs(inTabs); + var labelOffset = (tabInfo.hasLabels) ? tab_settings.labelWidth : 0; var tabs = tabInfo.tabs; // how much space? - var height = ((this._numStrings - 1) * ukeGeeks.settings.tabs.lineSpacing) + (2 * ukeGeeks.settings.tabs.dotRadius) + ukeGeeks.settings.tabs.bottomPadding; + var height = ((NUM_STRINGS - 1) * tab_settings.lineSpacing) + (2 * tab_settings.dotRadius) + tab_settings.bottomPadding; // prep canvas outElement = (typeof(outElement) == 'string') ? document.getElementById(outElement) : outElement; - var ctx = ukeGeeks.canvasTools.addCanvas(outElement, this._getWidth(tabs, labelOffset, false), height); + + var ctx = ukeGeeks.canvasTools.addCanvas(outElement, getWidth(tabs, labelOffset, false), height); var pos = { - x: ukeGeeks.settings.tabs.dotRadius + labelOffset, - y: 1 + ukeGeeks.settings.tabs.dotRadius + x: tab_settings.dotRadius + labelOffset, + y: 1 + tab_settings.dotRadius }; - this._drawStaff(ctx, pos, this._getWidth(tabs, labelOffset, true), ukeGeeks.settings.tabs); - this._drawNotes(ctx, pos, tabs, ukeGeeks.settings.tabs); + var lineWidth = getWidth(tabs, labelOffset, true); + drawStaff(ctx, pos, lineWidth, tab_settings); + drawNotes(ctx, pos, tabs, tab_settings, lineWidth); if (tabInfo.hasLabels){ - this._drawLabels(ctx, pos, ukeGeeks.settings.tabs); + drawLabels(ctx, pos, tab_settings); } - }, + }; /** * This is insanely long, insanely kludgy, but, insanely, it works. This will read break a block of text into * four lines (the ukulele strings), then find which frets are used by each. Then, the hard part, pack un-needed * dashes. Once it's done that a 2-dimentional array (strings X frets) is created and returned. - * @method _readTabs + * @method readTabs * @private * @param ukeStrings {array} Block of tablbabure to be parsed * @return {2-dimentional array} */ - _readTabs: function(ukeStrings){ - var hasLabels = ukeStrings[this._numStrings - 1][0] == this._lastStringName; + var readTabs= function(ukeStrings) { + var hasLabels = ukeStrings[NUM_STRINGS - 1][0] == LAST_STRING_NAME; if (hasLabels){ - this._stripStringLabels(ukeStrings); + stripStringLabels(ukeStrings); } - var frets = this._getFretNumbers(ukeStrings); - var symbols = this._getSymbols(ukeStrings); - var minLength = this._getMinLineLength(ukeStrings); - var guide = this._getGuideLine(symbols, minLength); + var frets = getFretNumbers(ukeStrings); + var symbols = getSymbols(ukeStrings); + var minLength = getMinLineLength(ukeStrings); + var guide = getGuideLine(symbols, minLength); + return { - tabs: this._getPackedLines(frets, symbols, guide, minLength), + tabs: getPackedLines(frets, symbols, guide, minLength), hasLabels: hasLabels }; - }, + }; /** - * @method _getWidth + * @method getWidth * @private * @param tabs {2Darray} * @param labelOffset {int} * @param isTruncate {bool} If TRUE returns the length of the line, allowing for a terminating "|" character, othwrwise, it's for canvas width * @return {int} */ - _getWidth : function(tabs, labelOffset, isTruncate){ + var getWidth= function(tabs, labelOffset, isTruncate) { if (!isTruncate){ - return (ukeGeeks.settings.tabs.noteSpacing * tabs[0].length) + labelOffset + ukeGeeks.settings.tabs.dotRadius; + return (tab_settings.noteSpacing * tabs[0].length) + labelOffset + tab_settings.dotRadius; } var len = tabs[0].length; - var plusDot = ukeGeeks.settings.tabs.dotRadius; + var plusDot = tab_settings.dotRadius; if (tabs[0][len - 1] == '|'){ // TODO: too much??? retest len -= 1; plusDot = 0; } - return ukeGeeks.settings.tabs.noteSpacing * len + labelOffset + plusDot; - }, + return tab_settings.noteSpacing * len + labelOffset + plusDot; + }; /** * Processes ukeStrings stripping the first character from each line - * @method _stripStringLabels + * @method stripStringLabels * @private * @param ukeStrings {array} * @return {void} */ - _stripStringLabels: function(ukeStrings) { - for (var i = 0; i < this._numStrings; i++) { + var stripStringLabels= function(ukeStrings) { + for (var i = 0; i < NUM_STRINGS; i++) { ukeStrings[i] = ukeStrings[i].substr(1); } - }, + }; /** * Finds the frets in used for each line. In other words, ignoring * spacers ("-" or "|") this returns arrays of numbers, the frets * in use, for each line. - * @method _getFretNumbers + * @method getFretNumbers * @private * @param ukeStrings {array} * @return {void} */ - _getFretNumbers: function(ukeStrings) { + var getFretNumbers= function(ukeStrings) { // first, get the frets var reInts = /([0-9]+)/g; var frets = []; - for (var i = 0; i < this._numStrings; i++) { + for (var i = 0; i < NUM_STRINGS; i++) { frets[i] = ukeStrings[i].match(reInts); } return frets; - }, + }; /** * Returns array of the strings with placeholders instead of the numbers. * This helps us pack because "12" and "7" now occupy the same space horizontally. - * @method _getSymbols + * @method getSymbols * @private * @param ukeStrings {array} * @return {void} */ - _getSymbols: function(ukeStrings) { + var getSymbols= function(ukeStrings) { // convert to symbols var reDoubles = /([0-9]{2})/g; var reSingle = /([0-9])/g; var symbols = []; - for (var i = 0; i < this._numStrings; i++) { + // TODO: verify why using NUM_STRINGS instead of ukeStrings.length (appears in other methods, again, do you recall why?) + for (var i = 0; i < NUM_STRINGS; i++) { symbols[i] = ukeStrings[i].replace(reDoubles,'-*'); symbols[i] = symbols[i].replace(reSingle,'*'); } return symbols; - }, + }; /** * Run through all of the strings (array) and return the length of the shortest one. * would prefer the max length, but then I'd need to pad the shorter ones and ... well, it's complicated. * this gets a TODO: get max! - * @method _getMinLineLength + * @method getMinLineLength * @private * @param ukeStrings {array} * @return {void} */ - _getMinLineLength: function(ukeStrings) { - var minLength = 10000; - for (var i = 0; i < this._numStrings; i++) { - minLength = (ukeStrings[i].length < minLength)? ukeStrings[i].length : minLength; + var getMinLineLength = function(ukeStrings){ + var minLength = 0; + var line; + var re = /-+$/gi; + + for (var i = 0; i < ukeStrings.length; i++) { + line = ukeStrings[i].trim().replace(re, ''); + if (line.length > minLength){ + minLength = line.length; + } } return minLength; - }, + }; /** - * OK, having created symbolic representations fo the lines in earlier steps + * OK, having created symbolic representations for the lines in earlier steps * here we go through and "merge" them into a single, master "guide" -- saying * "somewhere on this beat you'll pluck (or not) one note". This normalized * guide will be the master for the next step. - * @method _getGuideLine + * @method getGuideLine * @private * @param symbols {undefined} * @param minLength {int} * @return {void} */ - _getGuideLine: function(symbols, minLength) { + var getGuideLine= function(symbols, minLength) { // Build a master pattern "guide" and eliminate double dashes var guide = ''; for(var i=0; i < minLength; i++){ @@ -246,6 +266,7 @@ ukeGeeks.tabs.prototype = { guide += '|'; } else{ + // TODO: assumes 4 strings, use NUM_STRINGS guide += ((symbols[0][i] == '*') || (symbols[1][i] == '*') || (symbols[2][i] == '*') || (symbols[3][i] == '*')) ? '*' : '-'; } } @@ -261,53 +282,57 @@ ukeGeeks.tabs.prototype = { lastGuide = guide; } return guide; - }, + }; /** * Using the packed "guide" line we loop over the strings, rebuilding each string * with either a space, measure marker, or the note -- as an integer! Now the frets * are the same regardless of whether they are single or double digit numbers: * a "12" occupies no more horizontal space than a "5". - * @method _getPackedLines + * @method getPackedLines * @private * @param frets {undefined} * @param symbols {undefined} * @param guide {undefined} - * @param minLength {undefined} + * @param minLength {int} * @return {void} */ - _getPackedLines: function(frets, symbols, guide, minLength) { + var getPackedLines= function(frets, symbols, guide, minLength) { // pack it! - var packed = [ - [], - [], - [], - [] - ]; - var chrNote = ''; // a temp variable to hold the 'note' - for (var j = 0; j < this._numStrings; j++) { // loop over lines - var p = 0; // packed counter - var f = 0; // fret counter - for(var i=0; i < minLength; i++){ // loop over guide - if (guide[i] != ' '){ - if (symbols[j][i] == '*'){ - chrNote = frets[j][f]; - f++; + var packed = [], + chrNote = '', // a temp variable to hold the 'note' + guideIdx, // loop index for guide string + stringIdx, // loop index for instrument's strings (uke's 4) + lineIdx, // index to single line within packed array (along a string) + fretCount; // fret marker counter + + for (stringIdx = 0; stringIdx < NUM_STRINGS; stringIdx++) { + packed.push([]); + } + + for (stringIdx = 0; stringIdx < NUM_STRINGS; stringIdx++) { // loop over lines + lineIdx = 0; + fretCount = 0; + for (guideIdx = 0; guideIdx < minLength; guideIdx++) { // loop over guide + if (guide[guideIdx] != ' ') { + if (symbols[stringIdx][guideIdx] == '*') { + chrNote = frets[stringIdx][fretCount]; + fretCount++; } else{ - chrNote = ((guide[i] == '|')) ? '|' : '-'; + chrNote = ((guide[guideIdx] == '|')) ? '|' : '-'; } - packed[j][p] = chrNote; - p++; + packed[stringIdx][lineIdx] = chrNote; + lineIdx++; } } } return packed; - }, + }; /** * Create the staff -- really the four tablature strings - * @method _drawStaff + * @method drawStaff * @private * @param ctx {canvasContext} Handle to active canvas context * @param pos {xyPos} JSON (x,y) position @@ -315,12 +340,12 @@ ukeGeeks.tabs.prototype = { * @param settings {settingsObj} * @return {voie} */ - _drawStaff: function(ctx, pos, length, settings){ + var drawStaff= function(ctx, pos, length, settings) { var offset = settings.lineWidth / 2; var x = pos.x + offset; var y = pos.y + offset; ctx.beginPath(); - for (var i = 0; i < this._numStrings; i++) { + for (var i = 0; i < NUM_STRINGS; i++) { ctx.moveTo(x, y); ctx.lineTo(x + length, y); y += settings.lineSpacing; @@ -329,39 +354,39 @@ ukeGeeks.tabs.prototype = { ctx.lineWidth = settings.lineWidth; ctx.stroke(); ctx.closePath(); - }, + }; /** * Loop over the normalized tabs emitting the dots/fingers on the passed in canvase - * @method _drawNotes + * @method drawNotes * @private * @param ctx {canvasContext} Handle to active canvas context * @param pos {xyPos} JSON (x,y) position * @param tabs {array} Array of normalized string data -- space (character) or int (fret number) * @param settings {settingsObj} + * @param lineWidth {int} Length in pixels (used only when line ends with a measure mark) * @return {void} */ - _drawNotes: function(ctx, pos, tabs, settings){ + var drawNotes= function(ctx, pos, tabs, settings, lineWidth) { var c; var center = { x: 0, y: pos.y }; - for(var i in tabs){ - if (i > 3) { + for (var strIdx in tabs) { + if (strIdx > 3) { return; } center.x = pos.x; - for (var j in tabs[i]){ - c = tabs[i][j]; + for (var chrIdx in tabs[strIdx]) { + c = tabs[strIdx][chrIdx]; // (c != '-'){ if (c == '|'){ - var jnum = parseInt(j, 10); - var heavy = - (((jnum + 1) < (tabs[i].length - 1)) && (tabs[i][jnum + 1] == '|')) || ((jnum == (tabs[i].length - 1)) && (tabs[i][jnum - 1] == '|')); - this._drawMeasure(ctx, { - x: center.x, + var jnum = parseInt(chrIdx, 10); + var heavy = (((jnum + 1) < (tabs[strIdx].length - 1)) && (tabs[strIdx][jnum + 1] == '|')) || ((jnum == (tabs[strIdx].length - 1)) && (tabs[strIdx][jnum - 1] == '|')); + drawMeasure(ctx, { + x: (chrIdx == tabs[strIdx].length - 1) ? pos.x + lineWidth : center.x, y: pos.y }, settings, heavy); } @@ -376,11 +401,11 @@ ukeGeeks.tabs.prototype = { } center.y += settings.lineSpacing; } - }, + }; /** - * Draws a vertical "measure" demarcation line on the convas - * @method _drawMeasure + * Draws a vertical "measure" demarcation line + * @method drawMeasure * @private * @param ctx {canvasContext} Handle to active canvas context * @param pos {xyPos} JSON (x,y) position @@ -388,34 +413,40 @@ ukeGeeks.tabs.prototype = { * @param heavy {bool} if TRUE hevy line * @return {void} */ - _drawMeasure: function(ctx, pos, settings, heavy){ + var drawMeasure= function(ctx, pos, settings, heavy) { var offset = settings.lineWidth / 2; ctx.beginPath(); ctx.moveTo(pos.x + offset, pos.y); - ctx.lineTo(pos.x + offset, pos.y + (this._numStrings - 1) * settings.lineSpacing); + ctx.lineTo(pos.x + offset, pos.y + (NUM_STRINGS - 1) * settings.lineSpacing); ctx.strokeStyle = settings.lineColor; ctx.lineWidth = (heavy ? 4.5 : 1) * settings.lineWidth; ctx.stroke(); ctx.closePath(); - }, + }; /** * Adds the string letters on the left-side of the canvas, before the tablature string lines - * @method _drawLabels + * @method drawLabels * @private * @param ctx {canvasContext} Handle to active canvas context * @param pos {xyPos} JSON (x,y) position * @param settings {settingsObj} * @return {void} */ - _drawLabels: function(ctx, pos, settings){ + var drawLabels= function(ctx, pos, settings) { // ['A','E','C','G']; var labels = ukeGeeks.settings.tuning.slice(0).reverse(); - for (var i = 0; i < this._numStrings; i++) { + for (var i = 0; i < NUM_STRINGS; i++) { ukeGeeks.canvasTools.drawText(ctx, { x: 1, y: (pos.y + (i + 0.3) * settings.lineSpacing) }, labels[i], settings.labelFont, settings.lineColor, 'left'); } - } -}; \ No newline at end of file + }; + + /* return our public interface */ + return { + init: init, + replace: replace + }; +}; diff --git a/js/startup.js b/js/startup.js index a391b27..01a346f 100644 --- a/js/startup.js +++ b/js/startup.js @@ -4,9 +4,8 @@ * @return {void} */ function checkUrlOpts(){ - var s = new String(window.location); var re = new RegExp("[?&]inline=([^&]*)", "i"); - var m = s.match(re) + var m = ('' + window.location).match(re); if (!m || m.length < 1){ return; } @@ -30,4 +29,4 @@ else{ ukeGeeks.scriptasaurus.init(false); ukeGeeks.scriptasaurus.run(); })(); -} +} \ No newline at end of file diff --git a/js/ukeGeeks.scriptasaurus.merged.js b/js/ukeGeeks.scriptasaurus.merged.js index 219eb3e..e01addf 100644 --- a/js/ukeGeeks.scriptasaurus.merged.js +++ b/js/ukeGeeks.scriptasaurus.merged.js @@ -1492,7 +1492,7 @@ ukeGeeks.definitions.sopranoUkuleleGcea = [ // ------------------------------------------------------- '{define: F# frets 3 1 2 1 fingers 3 1 2 1 add: string 1 fret 1 finger 1 add: string 3 fret 1 finger 1}', '{define: F#m frets 2 1 2 0 fingers 2 1 3 0}', - '{define: F#7 frets 3 4 2 1 fingers 3 4 2 1}', + '{define: F#7 frets 3 4 2 4 fingers 2 3 1 4}', '{define: F#7sus4 frets 4 4 2 4 fingers 2 3 1 4}', '{define: F#m7 frets 2 4 2 4 fingers 1 3 2 4}', '{define: F#dim frets 2 3 2 3 fingers 1 3 2 4}', @@ -2651,53 +2651,63 @@ ukeGeeks.chordPainter = function() { * @constructor * @namespace ukeGeeks */ -ukeGeeks.tabs = function() {}; +ukeGeeks.tabs = function() { -ukeGeeks.tabs.prototype = { + /** + * alias for external Settings dependencies (helps with complression, too) + * @property tab_settings + * @private + * @type {JSON} + */ + var tab_settings = ukeGeeks.settings.tabs; + + // TODO: use ukeGeeks.settings.tuning for NUM_STRINGS and LAST_STRING_NAME?? /** * (Constant) Number of Strings (dashed lines of tablature notation) expected. (For now * a constant -- ukueleles "always" have four). Making a variable to help support port * for other instruments. - * @property _numStrings + * @property NUM_STRINGS * @private * @type int */ - _numStrings: 4, + var NUM_STRINGS= 4; /** * (Constant) Last String Name (Note), as above, on Ukulele is a "G". Here for other instruments. - * @property _lastStringName + * @property LAST_STRING_NAME * @private * @type string */ - _lastStringName: 'G', + var LAST_STRING_NAME= 'G'; /* PUBLIC METHODS ---------------------------------------------- */ /** * Again this is a constructor replacement * @method init + * @public * @return {void} */ - init: function() {}, + var init= function() {}; /** * Races through all <pre> tags within h, any with the CSS class of "ugsTabs" will be replaced with the canvas element. * @method replace + * @public * @param h {DOM-element} * @return {void} */ - replace: function(h) { + var replace= function(h) { var tabBlocks = h.getElementsByTagName('pre'); for (var i in tabBlocks) { if (tabBlocks[i].className == 'ugsTabs') { var s = tabBlocks[i].innerHTML; tabBlocks[i].innerHTML = ''; - this.loadBlocks(s, tabBlocks[i]); + loadBlocks(s, tabBlocks[i]); } } - }, + }; /** * @@ -2706,7 +2716,7 @@ ukeGeeks.tabs.prototype = { * @param outElement {string or DOM} Either: (string) the Id to a DOM element, or DOM element handle where the canvas/converted text will be placed. * @return {void} */ - loadBlocks: function(text, outElement) { + var loadBlocks= function(text, outElement) { var lines = text.split('\n'); var tab = []; for (var i in lines) { @@ -2714,12 +2724,12 @@ ukeGeeks.tabs.prototype = { if (s.length > 0) { tab.push(s); } - if (tab.length == this._numStrings) { - this.redraw(tab, outElement); + if (tab.length == NUM_STRINGS) { + redraw(tab, outElement); tab = []; } } - }, + }; /** * @@ -2728,163 +2738,172 @@ ukeGeeks.tabs.prototype = { * @param outElement {string or DOM} Either: (string) the Id to a DOM element, or DOM element handle where the canvas/converted text will be placed. * @return {void} */ - redraw: function(inTabs, outElement) { + var redraw= function(inTabs, outElement) { // validate inTabs input... // TODO: instead of this if it's text pop the entire processing back to loadBlocks! inTabs = (typeof(inTabs) == 'string') ? (inTabs.split('\n')) : inTabs; - if (inTabs.length < this._numStrings) { + if (inTabs.length < NUM_STRINGS) { return; } // read tabs - var tabInfo = this._readTabs(inTabs); - var labelOffset = (tabInfo.hasLabels) ? ukeGeeks.settings.tabs.labelWidth : 0; + var tabInfo = readTabs(inTabs); + var labelOffset = (tabInfo.hasLabels) ? tab_settings.labelWidth : 0; var tabs = tabInfo.tabs; // how much space? - var height = ((this._numStrings - 1) * ukeGeeks.settings.tabs.lineSpacing) + (2 * ukeGeeks.settings.tabs.dotRadius) + ukeGeeks.settings.tabs.bottomPadding; + var height = ((NUM_STRINGS - 1) * tab_settings.lineSpacing) + (2 * tab_settings.dotRadius) + tab_settings.bottomPadding; // prep canvas outElement = (typeof(outElement) == 'string') ? document.getElementById(outElement) : outElement; - var ctx = ukeGeeks.canvasTools.addCanvas(outElement, this._getWidth(tabs, labelOffset, false), height); + var ctx = ukeGeeks.canvasTools.addCanvas(outElement, getWidth(tabs, labelOffset, false), height); var pos = { - x: ukeGeeks.settings.tabs.dotRadius + labelOffset, - y: 1 + ukeGeeks.settings.tabs.dotRadius + x: tab_settings.dotRadius + labelOffset, + y: 1 + tab_settings.dotRadius }; - this._drawStaff(ctx, pos, this._getWidth(tabs, labelOffset, true), ukeGeeks.settings.tabs); - this._drawNotes(ctx, pos, tabs, ukeGeeks.settings.tabs); + var lineWidth = getWidth(tabs, labelOffset, true); + drawStaff(ctx, pos, lineWidth, tab_settings); + drawNotes(ctx, pos, tabs, tab_settings, lineWidth); if (tabInfo.hasLabels) { - this._drawLabels(ctx, pos, ukeGeeks.settings.tabs); + drawLabels(ctx, pos, tab_settings); } - }, + }; /** * This is insanely long, insanely kludgy, but, insanely, it works. This will read break a block of text into * four lines (the ukulele strings), then find which frets are used by each. Then, the hard part, pack un-needed * dashes. Once it's done that a 2-dimentional array (strings X frets) is created and returned. - * @method _readTabs + * @method readTabs * @private * @param ukeStrings {array} Block of tablbabure to be parsed * @return {2-dimentional array} */ - _readTabs: function(ukeStrings) { - var hasLabels = ukeStrings[this._numStrings - 1][0] == this._lastStringName; + var readTabs= function(ukeStrings) { + var hasLabels = ukeStrings[NUM_STRINGS - 1][0] == LAST_STRING_NAME; if (hasLabels) { - this._stripStringLabels(ukeStrings); + stripStringLabels(ukeStrings); } - var frets = this._getFretNumbers(ukeStrings); - var symbols = this._getSymbols(ukeStrings); - var minLength = this._getMinLineLength(ukeStrings); - var guide = this._getGuideLine(symbols, minLength); + var frets = getFretNumbers(ukeStrings); + var symbols = getSymbols(ukeStrings); + var minLength = getMinLineLength(ukeStrings); + var guide = getGuideLine(symbols, minLength); + return { - tabs: this._getPackedLines(frets, symbols, guide, minLength), + tabs: getPackedLines(frets, symbols, guide, minLength), hasLabels: hasLabels }; - }, + }; /** - * @method _getWidth + * @method getWidth * @private * @param tabs {2Darray} * @param labelOffset {int} * @param isTruncate {bool} If TRUE returns the length of the line, allowing for a terminating "|" character, othwrwise, it's for canvas width * @return {int} */ - _getWidth: function(tabs, labelOffset, isTruncate) { + var getWidth= function(tabs, labelOffset, isTruncate) { if (!isTruncate) { - return (ukeGeeks.settings.tabs.noteSpacing * tabs[0].length) + labelOffset + ukeGeeks.settings.tabs.dotRadius; + return (tab_settings.noteSpacing * tabs[0].length) + labelOffset + tab_settings.dotRadius; } var len = tabs[0].length; - var plusDot = ukeGeeks.settings.tabs.dotRadius; + var plusDot = tab_settings.dotRadius; if (tabs[0][len - 1] == '|') { // TODO: too much??? retest len -= 1; plusDot = 0; } - return ukeGeeks.settings.tabs.noteSpacing * len + labelOffset + plusDot; - }, + return tab_settings.noteSpacing * len + labelOffset + plusDot; + }; /** * Processes ukeStrings stripping the first character from each line - * @method _stripStringLabels + * @method stripStringLabels * @private * @param ukeStrings {array} * @return {void} */ - _stripStringLabels: function(ukeStrings) { - for (var i = 0; i < this._numStrings; i++) { + var stripStringLabels= function(ukeStrings) { + for (var i = 0; i < NUM_STRINGS; i++) { ukeStrings[i] = ukeStrings[i].substr(1); } - }, + }; /** * Finds the frets in used for each line. In other words, ignoring * spacers ("-" or "|") this returns arrays of numbers, the frets * in use, for each line. - * @method _getFretNumbers + * @method getFretNumbers * @private * @param ukeStrings {array} * @return {void} */ - _getFretNumbers: function(ukeStrings) { + var getFretNumbers= function(ukeStrings) { // first, get the frets var reInts = /([0-9]+)/g; var frets = []; - for (var i = 0; i < this._numStrings; i++) { + for (var i = 0; i < NUM_STRINGS; i++) { frets[i] = ukeStrings[i].match(reInts); } return frets; - }, + }; /** * Returns array of the strings with placeholders instead of the numbers. * This helps us pack because "12" and "7" now occupy the same space horizontally. - * @method _getSymbols + * @method getSymbols * @private * @param ukeStrings {array} * @return {void} */ - _getSymbols: function(ukeStrings) { + var getSymbols= function(ukeStrings) { // convert to symbols var reDoubles = /([0-9]{2})/g; var reSingle = /([0-9])/g; var symbols = []; - for (var i = 0; i < this._numStrings; i++) { + // TODO: verify why using NUM_STRINGS instead of ukeStrings.length (appears in other methods, again, do you recall why?) + for (var i = 0; i < NUM_STRINGS; i++) { symbols[i] = ukeStrings[i].replace(reDoubles, '-*'); symbols[i] = symbols[i].replace(reSingle, '*'); } return symbols; - }, + }; /** * Run through all of the strings (array) and return the length of the shortest one. * would prefer the max length, but then I'd need to pad the shorter ones and ... well, it's complicated. * this gets a TODO: get max! - * @method _getMinLineLength + * @method getMinLineLength * @private * @param ukeStrings {array} * @return {void} */ - _getMinLineLength: function(ukeStrings) { - var minLength = 10000; - for (var i = 0; i < this._numStrings; i++) { - minLength = (ukeStrings[i].length < minLength) ? ukeStrings[i].length : minLength; + var getMinLineLength = function(ukeStrings){ + var minLength = 0; + var line; + var re = /-+$/gi; + + for (var i = 0; i < ukeStrings.length; i++) { + line = ukeStrings[i].trim().replace(re, ''); + if (line.length > minLength){ + minLength = line.length; + } } return minLength; - }, + }; /** - * OK, having created symbolic representations fo the lines in earlier steps + * OK, having created symbolic representations for the lines in earlier steps * here we go through and "merge" them into a single, master "guide" -- saying * "somewhere on this beat you'll pluck (or not) one note". This normalized * guide will be the master for the next step. - * @method _getGuideLine + * @method getGuideLine * @private * @param symbols {undefined} * @param minLength {int} * @return {void} */ - _getGuideLine: function(symbols, minLength) { + var getGuideLine= function(symbols, minLength) { // Build a master pattern "guide" and eliminate double dashes var guide = ''; for (var i = 0; i < minLength; i++) { @@ -2892,6 +2911,7 @@ ukeGeeks.tabs.prototype = { guide += '|'; } else { + // TODO: assumes 4 strings, use NUM_STRINGS guide += ((symbols[0][i] == '*') || (symbols[1][i] == '*') || (symbols[2][i] == '*') || (symbols[3][i] == '*')) ? '*' : '-'; } } @@ -2907,53 +2927,57 @@ ukeGeeks.tabs.prototype = { lastGuide = guide; } return guide; - }, + }; /** * Using the packed "guide" line we loop over the strings, rebuilding each string * with either a space, measure marker, or the note -- as an integer! Now the frets * are the same regardless of whether they are single or double digit numbers: * a "12" occupies no more horizontal space than a "5". - * @method _getPackedLines + * @method getPackedLines * @private * @param frets {undefined} * @param symbols {undefined} * @param guide {undefined} - * @param minLength {undefined} + * @param minLength {int} * @return {void} */ - _getPackedLines: function(frets, symbols, guide, minLength) { + var getPackedLines= function(frets, symbols, guide, minLength) { // pack it! - var packed = [ - [], - [], - [], - [] - ]; - var chrNote = ''; // a temp variable to hold the 'note' - for (var j = 0; j < this._numStrings; j++) { // loop over lines - var p = 0; // packed counter - var f = 0; // fret counter - for (var i = 0; i < minLength; i++) { // loop over guide - if (guide[i] != ' ') { - if (symbols[j][i] == '*') { - chrNote = frets[j][f]; - f++; + var packed = [], + chrNote = '', // a temp variable to hold the 'note' + guideIdx, // loop index for guide string + stringIdx, // loop index for instrument's strings (uke's 4) + lineIdx, // index to single line within packed array (along a string) + fretCount; // fret marker counter + + for (stringIdx = 0; stringIdx < NUM_STRINGS; stringIdx++) { + packed.push([]); + } + + for (stringIdx = 0; stringIdx < NUM_STRINGS; stringIdx++) { // loop over lines + lineIdx = 0; + fretCount = 0; + for (guideIdx = 0; guideIdx < minLength; guideIdx++) { // loop over guide + if (guide[guideIdx] != ' ') { + if (symbols[stringIdx][guideIdx] == '*') { + chrNote = frets[stringIdx][fretCount]; + fretCount++; } else { - chrNote = ((guide[i] == '|')) ? '|' : '-'; + chrNote = ((guide[guideIdx] == '|')) ? '|' : '-'; } - packed[j][p] = chrNote; - p++; + packed[stringIdx][lineIdx] = chrNote; + lineIdx++; } } } return packed; - }, + }; /** * Create the staff -- really the four tablature strings - * @method _drawStaff + * @method drawStaff * @private * @param ctx {canvasContext} Handle to active canvas context * @param pos {xyPos} JSON (x,y) position @@ -2961,12 +2985,12 @@ ukeGeeks.tabs.prototype = { * @param settings {settingsObj} * @return {voie} */ - _drawStaff: function(ctx, pos, length, settings) { + var drawStaff= function(ctx, pos, length, settings) { var offset = settings.lineWidth / 2; var x = pos.x + offset; var y = pos.y + offset; ctx.beginPath(); - for (var i = 0; i < this._numStrings; i++) { + for (var i = 0; i < NUM_STRINGS; i++) { ctx.moveTo(x, y); ctx.lineTo(x + length, y); y += settings.lineSpacing; @@ -2975,39 +2999,39 @@ ukeGeeks.tabs.prototype = { ctx.lineWidth = settings.lineWidth; ctx.stroke(); ctx.closePath(); - }, + }; /** * Loop over the normalized tabs emitting the dots/fingers on the passed in canvase - * @method _drawNotes + * @method drawNotes * @private * @param ctx {canvasContext} Handle to active canvas context * @param pos {xyPos} JSON (x,y) position * @param tabs {array} Array of normalized string data -- space (character) or int (fret number) * @param settings {settingsObj} + * @param lineWidth {int} Length in pixels (used only when line ends with a measure mark) * @return {void} */ - _drawNotes: function(ctx, pos, tabs, settings) { + var drawNotes= function(ctx, pos, tabs, settings, lineWidth) { var c; var center = { x: 0, y: pos.y }; - for (var i in tabs) { - if (i > 3) { + for (var strIdx in tabs) { + if (strIdx > 3) { return; } center.x = pos.x; - for (var j in tabs[i]) { - c = tabs[i][j]; + for (var chrIdx in tabs[strIdx]) { + c = tabs[strIdx][chrIdx]; // (c != '-'){ if (c == '|') { - var jnum = parseInt(j, 10); - var heavy = - (((jnum + 1) < (tabs[i].length - 1)) && (tabs[i][jnum + 1] == '|')) || ((jnum == (tabs[i].length - 1)) && (tabs[i][jnum - 1] == '|')); - this._drawMeasure(ctx, { - x: center.x, + var jnum = parseInt(chrIdx, 10); + var heavy = (((jnum + 1) < (tabs[strIdx].length - 1)) && (tabs[strIdx][jnum + 1] == '|')) || ((jnum == (tabs[strIdx].length - 1)) && (tabs[strIdx][jnum - 1] == '|')); + drawMeasure(ctx, { + x: (chrIdx == tabs[strIdx].length - 1) ? pos.x + lineWidth : center.x, y: pos.y }, settings, heavy); } @@ -3022,11 +3046,11 @@ ukeGeeks.tabs.prototype = { } center.y += settings.lineSpacing; } - }, + }; /** - * Draws a vertical "measure" demarcation line on the convas - * @method _drawMeasure + * Draws a vertical "measure" demarcation line + * @method drawMeasure * @private * @param ctx {canvasContext} Handle to active canvas context * @param pos {xyPos} JSON (x,y) position @@ -3034,37 +3058,44 @@ ukeGeeks.tabs.prototype = { * @param heavy {bool} if TRUE hevy line * @return {void} */ - _drawMeasure: function(ctx, pos, settings, heavy) { + var drawMeasure= function(ctx, pos, settings, heavy) { var offset = settings.lineWidth / 2; ctx.beginPath(); ctx.moveTo(pos.x + offset, pos.y); - ctx.lineTo(pos.x + offset, pos.y + (this._numStrings - 1) * settings.lineSpacing); + ctx.lineTo(pos.x + offset, pos.y + (NUM_STRINGS - 1) * settings.lineSpacing); ctx.strokeStyle = settings.lineColor; ctx.lineWidth = (heavy ? 4.5 : 1) * settings.lineWidth; ctx.stroke(); ctx.closePath(); - }, + }; /** * Adds the string letters on the left-side of the canvas, before the tablature string lines - * @method _drawLabels + * @method drawLabels * @private * @param ctx {canvasContext} Handle to active canvas context * @param pos {xyPos} JSON (x,y) position * @param settings {settingsObj} * @return {void} */ - _drawLabels: function(ctx, pos, settings) { + var drawLabels= function(ctx, pos, settings) { // ['A','E','C','G']; var labels = ukeGeeks.settings.tuning.slice(0).reverse(); - for (var i = 0; i < this._numStrings; i++) { + for (var i = 0; i < NUM_STRINGS; i++) { ukeGeeks.canvasTools.drawText(ctx, { x: 1, y: (pos.y + (i + 0.3) * settings.lineSpacing) }, labels[i], settings.labelFont, settings.lineColor, 'left'); } - } + }; + + /* return our public interface */ + return { + init: init, + replace: replace + }; }; + ;/** * Singleton to correct overlapping chord names/diagrams in songs rendered by UGS * @class overlapFixer diff --git a/js/ukeGeeks.scriptasaurus.min.js b/js/ukeGeeks.scriptasaurus.min.js index 5f60c1f..f248d93 100644 --- a/js/ukeGeeks.scriptasaurus.min.js +++ b/js/ukeGeeks.scriptasaurus.min.js @@ -20,55 +20,52 @@ */ var ukeGeeks = window.ukeGeeks || {}; -;ukeGeeks.definitions=function(){var a={},c=[],b=[],d=[],e=0,f=[];a.instrument={sopranoUke:0,baritoneUke:5};a.addInstrument=function(a){d.push(a)};a.useInstrument=function(b){b=0e)return k(a);g=h(a);for(b in f)if(g==f[b].original&&(d=k(f[b].transposed)))return a= -new ukeGeeks.data.expandedChord(a),a.dots=d.dots,a.muted=d.muted,a;return null};var g={"A#":"Bb",Db:"C#","D#":"Eb",Gb:"F#",Ab:"G#"},h=function(a){var b=a.substr(0,2);return g[b]?g[b]+a.substr(2):a},k=function(a){var d,c=h(a);for(d=0;dd)return h(a);g=l(a);for(b in e)if(g==e[b].original&&(f=h(e[b].transposed)))return a= +new ukeGeeks.data.expandedChord(a),a.dots=f.dots,a.muted=f.muted,a;return null};var g={"A#":"Bb",Db:"C#","D#":"Eb",Gb:"F#",Ab:"G#"},l=function(a){var b=a.substr(0,2);return g[b]?g[b]+a.substr(2):a},h=function(a){var f,d=l(a);for(f=0;fl.length||(k*=parseInt(l[1],10),h=h.replace(b,k+l[2]));f[g]=h}this.fretBox=c(this.fretBox,a)}};return a}(); -ukeGeeks.data=function(){return{expandedChord:function(a){this.name=a;this.dots=[];this.muted=[]},song:function(){this.body=this.st2=this.st=this.artist=this.album=this.title="";this.hasChords=!1;this.ugsMeta=[];this.defs=[];this.chords=[]},dot:function(a,c,b){this.string=a;this.fret=c;this.finger=b},instrument:function(a,c,b,d){this.key=a;this.name=c;this.tuning=b;this.chords=d},htmlHandles:function(a,c,b){this.wrap=a;this.diagrams=c;this.text=b}}}(); -ukeGeeks.toolsLite=function(){var a={},c=/\s{2,}/g,b=/^\s+|\s+$/g;a.addClass=function(b,c){a.hasClass(b,c)||(b.className+=" "+c)};a.hasClass=function(a,b){return a.className.match(RegExp("(\\s|^)"+b+"(\\s|$)"))};a.removeClass=function(b,c){a.hasClass(b,c)&&(b.className=b.className.replace(RegExp("(\\s|^)"+c+"(\\s|$)")," "))};a.setClass=function(b,c,f){f?a.addClass(b,c):a.removeClass(b,c)};a.trim=function(a){return a.replace(b,"")};a.pack=function(a){return a.replace(c," ").replace(b,"")};a.getElementsByClass= -function(a,b,c){var g;b||(b=document);if(b.getElementsByClassName)return b.getElementsByClassName(a);var h=[];c||(c="*");b=b.getElementsByTagName(c);c=b.length;var k=RegExp("(^|\\s)"+a+"(\\s|$)");for(g=a=0;a=r?parseInt(m[r],10):0))}if(b&&!(1>b.length))for(var u in b)(c=b[u].match(h))&&2b.length&&(b=a.split("{"));var c=b,b=[],d;for(d in c){var e=m(c[d]);e&&b.push(e)}d=(d=a.match(k))?ukeGeeks.toolsLite.pack(d[1]):null;a=(a=a.match(l))?[a[1],a[2],a[3],a[4]]:null;var c=ukeGeeks.data.instrument,e=d.replace(" ","-"),f;for(f in a)e+="-"+a[f];f=e.toLowerCase();var e=[],g=null,h;for(h in b)(g=q(b[h].define,b[h].adds))&&e.push(g);return new c(f,d,a,e)};return a}(); -ukeGeeks.transpose=function(){var a={},c=/^([A-G][#b]?)(.*)/,b={A:0,"A#":1,Bb:1,B:2,C:3,"C#":4,Db:4,D:5,"D#":6,Eb:6,E:7,F:8,"F#":9,Gb:9,G:10,"G#":11,Ab:11};a.shift=function(a,e){var f;f=a.match(c);f=!f||1>f.length?null:{tone:parseInt(b[f[1]],10),prefix:f[1],suffix:f[2]};if(null===f)return null;var g=(f.tone+e)%12;0>g&&(g+=12);for(var h in b)if(g==b[h])return h+f.suffix;return null};a.retune=function(){var b=0n;n++){var m=h+n*b.stringSpace+f;a.moveTo(m,k+f);a.lineTo(m,k+g+f)}for(n=1;ng&&(g=f[m].fret),f[m].fretp?p:0;g=0=g?1:g-4;for(m=0;m'+b+""+c[e]+""+d+"")).length)}return a},_packChords:function(a){var c;if(ukeGeeks.settings.inlineDiagrams)return c=/(<\/strong><\/code>)[ \t]*()/ig,a.replace(c,'$1 $2');c=/<\/strong><\/code>[ \t]*/ig;return a.replace(c, +labelWidth:12,labelFont:"10pt Arial, Helvetica, Verdana, Geneva, sans-serif",dotColor:"#eaeaea",dotRadius:10,textFont:"bold 12pt Arial, Helvetica, Verdana, Geneva, sans-serif",textColor:"#000000",bottomPadding:10};a.environment={isIe:!1};a.commonChords="A B C D E F G Am".split(" ");var c=function(a,b){if("number"==typeof a)return a*b;if("object"==typeof a)for(var e in a)a[e]=c(a[e],b);return a},b=/\b(\d+)(pt|px)\b/;a.scale=function(a){if(1!=a){for(var d in this.fonts){var e=this.fonts,g=d,l;l=this.fonts[d]; +var h=a,k=l.match(b);2>k.length||(h*=parseInt(k[1],10),l=l.replace(b,h+k[2]));e[g]=l}this.fretBox=c(this.fretBox,a)}};return a}(); +ukeGeeks.data=function(){return{expandedChord:function(a){this.name=a;this.dots=[];this.muted=[]},song:function(){this.body=this.st2=this.st=this.artist=this.album=this.title="";this.hasChords=!1;this.ugsMeta=[];this.defs=[];this.chords=[]},dot:function(a,c,b){this.string=a;this.fret=c;this.finger=b},instrument:function(a,c,b,f){this.key=a;this.name=c;this.tuning=b;this.chords=f},htmlHandles:function(a,c,b){this.wrap=a;this.diagrams=c;this.text=b}}}(); +ukeGeeks.toolsLite=function(){var a={},c=/\s{2,}/g,b=/^\s+|\s+$/g;a.addClass=function(b,d){a.hasClass(b,d)||(b.className+=" "+d)};a.hasClass=function(a,b){return a.className.match(RegExp("(\\s|^)"+b+"(\\s|$)"))};a.removeClass=function(b,d){a.hasClass(b,d)&&(b.className=b.className.replace(RegExp("(\\s|^)"+d+"(\\s|$)")," "))};a.setClass=function(b,d,c){c?a.addClass(b,d):a.removeClass(b,d)};a.trim=function(a){return a.replace(b,"")};a.pack=function(a){return a.replace(c," ").replace(b,"")};a.getElementsByClass= +function(a,b,c){var g;b||(b=document);if(b.getElementsByClassName)return b.getElementsByClassName(a);var l=[];c||(c="*");b=b.getElementsByTagName(c);c=b.length;var h=RegExp("(^|\\s)"+a+"(\\s|$)");for(g=a=0;a=x?parseInt(m[x],10):0))}if(b&&!(1>b.length))for(var B in b)(f=b[B].match(l))&&2b.length&&(b=a.split("{"));var f=b,b=[],c;for(c in f){var d=p(f[c]);d&&b.push(d)}c=(c=a.match(h))?ukeGeeks.toolsLite.pack(c[1]):null;a=(a=a.match(k))?[a[1],a[2],a[3],a[4]]:null;var f=ukeGeeks.data.instrument,d=c.replace(" ","-"),g;for(g in a)d+="-"+a[g];g=d.toLowerCase();var d=[],e=null,l;for(l in b)(e=m(b[l].define,b[l].adds))&&d.push(e);return new f(g,c,a,d)};return a}(); +ukeGeeks.transpose=function(){var a={},c=/^([A-G][#b]?)(.*)/,b={A:0,"A#":1,Bb:1,B:2,C:3,"C#":4,Db:4,D:5,"D#":6,Eb:6,E:7,F:8,"F#":9,Gb:9,G:10,"G#":11,Ab:11};a.shift=function(a,d){var e;e=a.match(c);e=!e||1>e.length?null:{tone:parseInt(b[e[1]],10),prefix:e[1],suffix:e[2]};if(null===e)return null;var g=(e.tone+d)%12;0>g&&(g+=12);for(var l in b)if(g==b[l])return l+e.suffix;return null};a.retune=function(){var b=0n;n++){var p=l+n*b.stringSpace+e;a.moveTo(p,h+e);a.lineTo(p,h+g+e)}for(n=1;ng&&(g=e[p].fret),e[p].fretq?q:0;g=0=g?1:g-4;for(p=0;p'+b+""+c[d]+""+f+"")).length;);return a},_packChords:function(a){var c;if(ukeGeeks.settings.inlineDiagrams)return c=/(<\/strong><\/code>)[ \t]*()/ig,a.replace(c,'$1 $2');c=/<\/strong><\/code>[ \t]*/ig;return a.replace(c, " ")}};ukeGeeks.cpmParser=function(){}; ukeGeeks.cpmParser.prototype={runaway:30,columnCount:1,hasChords:!1,init:function(){},parse:function(a){var c=new ukeGeeks.data.song;a=this._stripHtml(a);a=this._domParse(a);a=this._parseInstr(a);a=this._parseSimpleInstr(a);a=this._markChordLines(a);c.body=this._export(a);1
'+c.body+"
");c.hasChords=this.hasChords;var b;b=this._getInfo(a, -this.blockTypeEnum.Title);0'+a[b].lines[0]+ -"\n";else if(a[b].type==this.blockTypeEnum.NewPage)c+='
\n';else if(a[b].type==this.blockTypeEnum.ChordText||a[b].type==this.blockTypeEnum.PlainText||a[b].type==this.blockTypeEnum.ChordOnlyText){if(!(1>a[b].lines[0].length)){var d=a[b].type==this.blockTypeEnum.PlainText?this.classNames.PrePlain:this.classNames.PreChords;a[b].type==this.blockTypeEnum.ChordOnlyText&&(d+=" "+this.classNames.NoLyrics);var e=a[b].type,f=0<=b-1?a[b-1].type:this.blockTypeEnum.Undefined, -g=b+1':"\n"),c=c+a[b].lines[0],c=c+(g!=e?"\n":"")}}else if(a[b].type==this.blockTypeEnum.ChorusBlock)c+='
\n',c+=this._export(a[b].lines),c+="
\n";else if(a[b].type==this.blockTypeEnum.TabBlock){var c=c+('
'),h;for(h in a[b].lines)c+=a[b].lines[h]+"\n";c+="
\n"}else a[b].type==this.blockTypeEnum.TextBlock?c+=this._export(a[b].lines): -a[b].type==this.blockTypeEnum.ColumnBreak&&(c+='
');return c},_echo:function(a){for(var c in a){console.log(">> "+c+". "+a[c].type+" node, "+a[c].lines.length+" lines");for(var b in a[c].lines)console.log(a[c].lines[b])}},_domParse:function(a){a=a.split("\n");var c=[],b=null,d,e;for(e in a)0ukeGeeks.toolsLite.trim(f.replace(b,"")).length,a[g].lines[h]={type:e?this.blockTypeEnum.ChordOnlyText:d?this.blockTypeEnum.ChordText:this.blockTypeEnum.PlainText,lines:[f]});return a},_getInfo:function(a,c){var b=[],d;for(d in a)if(a[d].type==c)b.push(a[d].lines[0]);else if(a[d].type==this.blockTypeEnum.TextBlock)for(var e in a[d].lines)a[d].lines[e].type==c&&b.push(a[d].lines[e].lines[0]);return b},_stripHtml:function(a){return a.replace(/<\/?pre>/img,"").replace(/\x3c!--(.|\n)*?--\x3e/gm, +"\n";else if(a[b].type==this.blockTypeEnum.NewPage)c+='
\n';else if(a[b].type==this.blockTypeEnum.ChordText||a[b].type==this.blockTypeEnum.PlainText||a[b].type==this.blockTypeEnum.ChordOnlyText){if(!(1>a[b].lines[0].length)){var f=a[b].type==this.blockTypeEnum.PlainText?this.classNames.PrePlain:this.classNames.PreChords;a[b].type==this.blockTypeEnum.ChordOnlyText&&(f+=" "+this.classNames.NoLyrics);var d=a[b].type,e=0<=b-1?a[b-1].type:this.blockTypeEnum.Undefined, +g=b+1':"\n"),c=c+a[b].lines[0],c=c+(g!=d?"\n":"")}}else if(a[b].type==this.blockTypeEnum.ChorusBlock)c+='
\n',c+=this._export(a[b].lines),c+="
\n";else if(a[b].type==this.blockTypeEnum.TabBlock){var c=c+('
'),l;for(l in a[b].lines)c+=a[b].lines[l]+"\n";c+="
\n"}else a[b].type==this.blockTypeEnum.TextBlock?c+=this._export(a[b].lines): +a[b].type==this.blockTypeEnum.ColumnBreak&&(c+='
');return c},_echo:function(a){for(var c in a){console.log(">> "+c+". "+a[c].type+" node, "+a[c].lines.length+" lines");for(var b in a[c].lines)console.log(a[c].lines[b])}},_domParse:function(a){a=a.split("\n");var c=[],b=null,f,d;for(d in a)0ukeGeeks.toolsLite.trim(e.replace(b,"")).length,a[g].lines[l]={type:d?this.blockTypeEnum.ChordOnlyText:f?this.blockTypeEnum.ChordText:this.blockTypeEnum.PlainText,lines:[e]});return a},_getInfo:function(a,c){var b=[],f;for(f in a)if(a[f].type==c)b.push(a[f].lines[0]);else if(a[f].type==this.blockTypeEnum.TextBlock)for(var d in a[f].lines)a[f].lines[d].type==c&&b.push(a[f].lines[d].lines[0]);return b},_stripHtml:function(a){return a.replace(/<\/?pre>/img,"").replace(/\x3c!--(.|\n)*?--\x3e/gm, "")}}; -ukeGeeks.chordPainter=function(){var a={},c=null,b=[],d=null;a.init=function(a){c=new ukeGeeks.chordBrush;c.init();d=a};var e=[],f=/^(n.?\/?c.?|tacet)$/i;a.show=function(a){d.diagrams.innerHTML="";b=[];e=[];for(var h=0;hb.length))for(var e=0;ef.width&&(f.width=a+2);f.right=f.left+f.width;return f},b=function(a){return"undefined"!==typeof a.clip?a.clip.width:a.style.pixelWidth?a.style.pixelWidth:a.offsetWidth};a.Fix=function(a){var b=a.getElementsByTagName("code"); -for(a=0;ah.right||g.righth.left&&g.lefth.left&&g.righth?1:h)+"px")}};return a}(); -ukeGeeks.scriptasaurus=function(){var a=[],c=function(b){var c=new ukeGeeks.cpmParser;c.init();c=c.parse(b.text.innerHTML);ukeGeeks.definitions.replace(c.defs);var e=new ukeGeeks.chordParser;e.init();b.text.innerHTML=e.parse(c.body);c.chords=e.getChords();e=new ukeGeeks.chordPainter;e.init(b);e.show(c.chords);ukeGeeks.settings.inlineDiagrams&&(ukeGeeks.toolsLite.addClass(b.wrap,"ugsInlineDiagrams"),e.showInline(c.chords));var f=new ukeGeeks.tabs;f.init();f.replace(b.text);a.push(e.getErrors());(e= -b.wrap)&&(c.hasChords?ukeGeeks.toolsLite.removeClass(e,"ugsNoChords"):ukeGeeks.toolsLite.addClass(e,"ugsNoChords"));ukeGeeks.settings.opts.autoFixOverlaps&&ukeGeeks.overlapFixer.Fix(b.text);return c};return{init:function(a){var c=ukeGeeks.definitions;ukeGeeks.settings.environment.isIe=a;c.addInstrument(c.sopranoUkuleleGcea);c.useInstrument(c.instrument.sopranoUke);ukeGeeks.settings.defaultInstrument!=c.instrument.sopranoUke&&c.useInstrument(ukeGeeks.settings.defaultInstrument)},run:function(){var b= -new ukeGeeks.data.htmlHandles(document.getElementById(ukeGeeks.settings.ids.container),document.getElementById(ukeGeeks.settings.ids.canvas),document.getElementById(ukeGeeks.settings.ids.songText));if(!(b&&b.diagrams&&b.text&&b.wrap))return null;a=[];b=c(b);var d=a[0];if(!(1>d.length)){for(var e="",f=0;fg.length||void 0===h||1>h.length?null:new ukeGeeks.data.htmlHandles(f,g[0],h[0]);null!==f&&a.push(c(f))}return a},setTuningOffset:function(a){ukeGeeks.definitions.useInstrument(a)}}}(); \ No newline at end of file +ukeGeeks.chordPainter=function(){var a={},c=null,b=[],f=null;a.init=function(a){c=new ukeGeeks.chordBrush;c.init();f=a};var d=[],e=/^(n.?\/?c.?|tacet)$/i;a.show=function(a){f.diagrams.innerHTML="";b=[];d=[];for(var l=0;lb.length))for(var d=0;dk.length)){if(h="G"==k[3][0])for(var n=k,q=0;4>q;q++)n[q]=n[q].substr(1);for(var n=k,q=/([0-9]+)/g,p=[],m=0;4>m;m++)p[m]=n[m].match(q);for(var n=p,q=k,p=/([0-9]{2})/g,m=/([0-9])/g,r=[],s=0;4>s;s++)r[s]=q[s].replace(p,"-*"),r[s]=r[s].replace(m,"*");q=r;p=0;m=void 0;r=/-+$/gi;for(s=0;sp&&(p=m.length);m="";for(k=0;kt;t++)m.push([]);for(t=0;4>t;t++)for(s=u=v=0;ss;s++)g.moveTo(m,r),g.lineTo(m+p,r),r+=a.lineSpacing;g.strokeStyle=a.lineColor;g.lineWidth=a.lineWidth;g.stroke();g.closePath();a:for(r in s=void 0,m={x:0,y:k},r=void 0,n){if(3n;n++)ukeGeeks.canvasTools.drawText(g,{x:1,y:k+(n+0.3)*a.lineSpacing},h[n],a.labelFont,a.lineColor,"left")}g=[]}}}}}}; +ukeGeeks.overlapFixer=function(){var a={},c=function(a){for(var c=a,e={top:0,left:0,right:0,width:0};c&&!isNaN(c.offsetLeft)&&!isNaN(c.offsetTop);)e.left+=c.offsetLeft-c.scrollLeft,e.top+=c.offsetTop-c.scrollTop,c=c.offsetParent;e.width=b(a);if(a=a.getElementsByTagName("em")[0])a=b(a),a>e.width&&(e.width=a+2);e.right=e.left+e.width;return e},b=function(a){return"undefined"!==typeof a.clip?a.clip.width:a.style.pixelWidth?a.style.pixelWidth:a.offsetWidth};a.Fix=function(a){var b=a.getElementsByTagName("code"); +for(a=0;al.right||g.rightl.left&&g.leftl.left&&g.rightl?1:l)+"px")}};return a}(); +ukeGeeks.scriptasaurus=function(){var a=[],c=function(b){var c=new ukeGeeks.cpmParser;c.init();c=c.parse(b.text.innerHTML);ukeGeeks.definitions.replace(c.defs);var d=new ukeGeeks.chordParser;d.init();b.text.innerHTML=d.parse(c.body);c.chords=d.getChords();d=new ukeGeeks.chordPainter;d.init(b);d.show(c.chords);ukeGeeks.settings.inlineDiagrams&&(ukeGeeks.toolsLite.addClass(b.wrap,"ugsInlineDiagrams"),d.showInline(c.chords));var e=new ukeGeeks.tabs;e.init();e.replace(b.text);a.push(d.getErrors());(d= +b.wrap)&&(c.hasChords?ukeGeeks.toolsLite.removeClass(d,"ugsNoChords"):ukeGeeks.toolsLite.addClass(d,"ugsNoChords"));ukeGeeks.settings.opts.autoFixOverlaps&&ukeGeeks.overlapFixer.Fix(b.text);return c};return{init:function(a){var c=ukeGeeks.definitions;ukeGeeks.settings.environment.isIe=a;c.addInstrument(c.sopranoUkuleleGcea);c.useInstrument(c.instrument.sopranoUke);ukeGeeks.settings.defaultInstrument!=c.instrument.sopranoUke&&c.useInstrument(ukeGeeks.settings.defaultInstrument)},run:function(){var b= +new ukeGeeks.data.htmlHandles(document.getElementById(ukeGeeks.settings.ids.container),document.getElementById(ukeGeeks.settings.ids.canvas),document.getElementById(ukeGeeks.settings.ids.songText));if(!(b&&b.diagrams&&b.text&&b.wrap))return null;a=[];b=c(b);var f=a[0];if(!(1>f.length)){for(var d="",e=0;eg.length||void 0===l||1>l.length?null:new ukeGeeks.data.htmlHandles(e,g[0],l[0]);null!==e&&a.push(c(e))}return a},setTuningOffset:function(a){ukeGeeks.definitions.useInstrument(a)}}}(); \ No newline at end of file