diff --git a/js/extra/rainbow-display-stats.js b/js/extra/rainbow-display-stats.js new file mode 100644 index 00000000..a9d5070f --- /dev/null +++ b/js/extra/rainbow-display-stats.js @@ -0,0 +1,139 @@ +$(function() { + + 'use strict'; + + var labels = { + show: 'show usage counts', + hide: 'hide usage counts' + }; + + /** + * Rainbow.displayStats(); + * + * Adds a new element before
 tag and displays usage counts.
+     *
+     * @param tag {String} optional - any element container of 
 tag (applies to all 
 tags if no param given)
+     * @param fullList {Boolean} optional - if true will expand the list of usages
+     */
+    Rainbow.displayStatsOn = function(tag,fullList){
+
+        Rainbow.statsOn = tag || 'body';
+        Rainbow.statsFull = fullList;
+
+        getElementLink();
+
+    };
+
+    /********************
+     * PRIVATE METHODS
+     ********************/
+
+    function getElementLink(){
+        var $link = $('').attr('href','#').text(labels.show);
+
+        $link.on('click',createOrToggleList);
+
+        $(Rainbow.statsOn).find('pre').before($link);
+    }
+
+    function getElementStats($target){
+        var classes = getClasses($target.next()),
+            $stats = $('
').attr('class','rainbow-stats'), + $class = $('').attr('class','rainbow-stats-class'), + $count = $('').attr('class','rainbow-stats-count'); + + for(var c in classes){ + if(classes.hasOwnProperty(c)){ + $stats.append( + $('
') + .append($count.clone().text(classes[c].count)) + .append($class.clone().text(classes[c].name) + .on('click',doHighlight) + ) + ); + } + } + + $target.after($stats); + + return $stats; + } + + function getClasses($el){ + + var classes = {}; + + if(!$el || !$el.is || !$el.is('pre')) { + return null; + } + + $el.find('span').each(function(i,e){ + + var clsStr = $(e).attr('class'); + + classes[clsStr] || (classes[clsStr]=0); + classes[clsStr]++; + + if(Rainbow.statsFull === true){ + var clsArr = clsStr.split(' '); + for(var c in clsArr){ + if(clsArr.hasOwnProperty(c)){ + classes[clsArr[c]] || (classes[clsArr[c]]=0); + classes[clsArr[c]]++; + } + } + } + + }); + + var classesArray = []; + for(var cl in classes){ + if(classes.hasOwnProperty(cl)){ + classesArray.push({name:cl,count:classes[cl]}); + } + } + + return classesArray.sort(function(a,b){return a.name > b.name;}); + + } + + /******************** + * EVENT HANDLERS + ********************/ + + function createOrToggleList(e){ + e.preventDefault(); + + var $t = $(e.currentTarget), + $stats = $t.next('.rainbow-stats'); + + var action = $stats.length===0 ? 'create' : $stats.css('display')==='none' ? 'show' : 'hide'; + + switch(action){ + case 'create': + $t.text(labels.hide); + getElementStats($t); + break; + case 'show': + $t.text(labels.hide); + $stats.show(); + break; + case 'hide': + $t.text(labels.show); + $stats.hide(); + break; + } + } + + function doHighlight(e){ + var $t = $(e.currentTarget), + cl = $t.text().split(' '); + + $('.rainbow-stats-class').removeClass('rainbow-stats-selected'); + $t.addClass('rainbow-stats-selected'); + + cl.unshift(''); + Rainbow.doHighlight && Rainbow.doHighlight($t.closest('.rainbow-stats').next(),cl.join('.')); + } + +}); diff --git a/js/extra/rainbow-extensions.css b/js/extra/rainbow-extensions.css new file mode 100644 index 00000000..20a0cb83 --- /dev/null +++ b/js/extra/rainbow-extensions.css @@ -0,0 +1,49 @@ +/** + * TOGGLE HIGHLIGHT + * + * rainbow-toggle-highlight.js + */ +pre .highlighted { + background-color: rgba(255, 255, 0, 0.2); + box-shadow: 0 0 2px 2px #ffff00; +} + +/** + * TOGGLE INFO + * + * rainbow-toggle-info.js + */ +#rainbowOverlay { + background: #002b36; + border-radius: 4px; + bottom: 0; + color: #839496; + left: 0; + margin: 8px; + padding: 8px 16px; + position: fixed; +} + +#rainbowOverlay strong { + color: #acb8b9; +} + +/** + * DISPLAY STATS + * + * rainbow-display-stats.js + */ +.rainbow-stats-class { + cursor: pointer; +} + +.rainbow-stats-count { + display: inline-block; + margin: 0 8px 0 0; + text-align: right; + width: 30px; +} + +.rainbow-stats-selected { + font-weight: bold; +} diff --git a/js/extra/rainbow-toggle-highlight.js b/js/extra/rainbow-toggle-highlight.js new file mode 100644 index 00000000..e40b3aa8 --- /dev/null +++ b/js/extra/rainbow-toggle-highlight.js @@ -0,0 +1,117 @@ +$(function() { + + 'use strict'; + + /** + * Rainbow.toggleHighlightOn(tag:String, toggle:Boolean); + * + * Toggle click event for highlight every Rainbow generated span tags. + * + * @param tag {String} any ancestor tag of the
 modified by Rainbow
+     * @param toggle {Boolean} optional
+     * @returns {Boolean} returns false if no tags were found
+     */
+    Rainbow.toggleHighlightOn = function(tag, toggle){
+
+        if($(tag).length===0) {
+            return false;
+        }
+
+        typeof(toggle)!=='boolean' && (toggle = !$(tag).data('Rainbow.toggleHighlightState'));
+
+        if(!!toggle){
+            $(tag).on('click', 'pre', highlightClasses);
+        }else{
+            $(tag).off('click', 'pre', highlightClasses);
+        }
+
+        $(tag).data('Rainbow.toggleHighlightState', !toggle);
+
+        return true;
+    };
+
+    /**
+     * Rainbow.doHighlight($parent:jQuery, selector:String);
+     *
+     * Publicly exposed method for a single highlight.
+     *
+     * @param $parent {jQuery} the element that contains the 
 tag
+     * @param selector {String} the selector to be highlighted
+     */
+    Rainbow.doHighlight = function($parent,selector){
+        removeHighlight($parent);
+        addHighlight($parent,selector);
+    };
+
+    /**
+     * Rainbow.setHighlightClass(className:String);
+     *
+     * Call this method in order to customize the className for highlighted elements
+     *
+     * @param className {String} className for highlighted tags
+     */
+    Rainbow.setHighlightClass = function(className){
+        if(typeof(className)==='string') {
+            Rainbow.toggleHighlightClass = className;
+        }
+    };
+
+    // sets default className
+    Rainbow.setHighlightClass('highlighted');
+
+    /********************
+     * PRIVATE METHODS
+     ********************/
+
+    function highlightClasses(e){
+        e.stopPropagation();
+
+        if(!Rainbow.toggleHighlightClass || typeof(Rainbow.toggleHighlightClass)!=='string' || Rainbow.toggleHighlightClass.length===0){
+            return;
+        }
+
+        var $e = $(e.target),
+            $pre = $e.is('pre') ? $e : $e.closest('pre');
+
+        if(!$e.is('span')) {
+            removeHighlight($pre);
+            return;
+        }
+
+        if($e.parents('.' + Rainbow.toggleHighlightClass).length){
+            $e = $e.parents('.' + Rainbow.toggleHighlightClass).parents('span');
+        }else if($e.hasClass(Rainbow.toggleHighlightClass)){
+            $e = $e.parents('span');
+        }
+
+        removeHighlight($pre);
+
+        if($e.length){
+            var cl = $e.attr('class').split(' '),
+                classes = [''];
+
+            for(var c in cl){
+                if(cl.hasOwnProperty(c)){
+                    classes.push(cl[c]);
+                }
+            }
+
+            addHighlight($pre,classes.join('.'));
+
+            console.log('highlight on: ',classes.join('.'));
+        }else {
+            console.log('highlight off');
+        }
+
+        Rainbow.refreshOverlay && Rainbow.refreshOverlay();
+    }
+
+    function addHighlight($parent,selector){
+        $parent.find(selector).addClass(Rainbow.toggleHighlightClass);
+    }
+
+    function removeHighlight($parent){
+        $parent.find('.'+Rainbow.toggleHighlightClass).removeClass(Rainbow.toggleHighlightClass);
+    }
+
+});
diff --git a/js/extra/rainbow-toggle-info.js b/js/extra/rainbow-toggle-info.js
new file mode 100644
index 00000000..49f9432f
--- /dev/null
+++ b/js/extra/rainbow-toggle-info.js
@@ -0,0 +1,138 @@
+$(function() {
+
+    'use strict';
+
+    /**
+     * Rainbow.toggleInfoOn(tag:String, toggle:Boolean);
+     *
+     * Toggle mouseover/out events for display classes info on every Rainbow generated span tags.
+     *
+     * @param tag {String} any ancestor tag of the 
 modified by Rainbow
+     * @param toggle {Boolean} optional
+     * @param keepOverlay {Boolean} optional - whether to keep the overlay on mouseOut or not
+     * @returns {boolean} returns false if no tags were found
+     */
+    Rainbow.toggleInfoOn = function(tag, toggle, keepOverlay) {
+
+        if($(tag).length===0) {
+            return false;
+        }
+
+        typeof(toggle)!=='boolean' && (toggle = !$(tag).data('Rainbow.overlayInfoState'));
+
+        if(!!toggle){
+            $(tag).on('mouseover', 'pre span', showOverlay);
+            keepOverlay || $(tag).on('mouseout', 'pre span', hideOverlay);
+        }else{
+            $(tag).off('mouseover', 'pre span', showOverlay);
+            $(tag).off('mouseout', 'pre span', hideOverlay);
+        }
+
+        $(tag).data('Rainbow.overlayInfoState', !toggle);
+
+        return true;
+    };
+
+    /**
+     * Rainbow.setOverlayContent(classes:Array);
+     *
+     * Override this method in order to customize the overlay content
+     *
+     * @param classes {Array} list of classes to be displayed as info
+     */
+    Rainbow.setOverlayContent = function(classes){
+        return ['

',classes.join(',^ ').split(',').join('

'),'

'].join(''); + }; + + /** + * Rainbow.setOverlayContainer($dom:jQuery); + * + * Call this method in order to customize the overlay main element + * + * @param $dom {jQuery} a jquery object that will be used as overlay info + * @param ID {String} optional + */ + Rainbow.setOverlayContainer = function($dom, ID){ + ID || (ID='rainbowOverlay'); + + if(typeof($dom)==='object' && typeof(ID)==='string'){ + $dom.attr('id',ID); + Rainbow.$overlayInfoContainer = $dom; + } + }; + + // sets default className + Rainbow.setOverlayContainer($('
'), 'rainbowOverlay'); + + /** + * Rainbow.refreshOverlay(); + * + * Publicly exposed method to let the overlay refresh upon new highlights. + */ + Rainbow.refreshOverlay = function(){ + showOverlay({target:Rainbow.$overlayedEl}); + }; + + /******************** + * PRIVATE METHODS + ********************/ + + function hideOverlay(){ + Rainbow.$overlayInfoContainer && Rainbow.$overlayInfoContainer.remove(); + } + + function showOverlay(e){ + e.stopPropagation && e.stopPropagation(); + + hideOverlay(); + + var $e = $(e.target), + classes = getClasses($e); + + Rainbow.$overlayedEl = $e; + + if(classes){ + var html = Rainbow.setOverlayContent(classes), + $overlay = Rainbow.$overlayInfoContainer; + + $overlay && $overlay.html(html).appendTo('body'); + } + } + + function getClasses($e){ + + var classes, $p; + + if($e.is('span')){ + classes = [getRainbowClasses($e)]; + + $p = $e.parent(); + while($p.is('span')){ + classes.push(getRainbowClasses($p)); + $p = $p.parent(); + } + + return classes; + } + + return null; + } + + // removes the class defined in Rainbow.toggleHighlightClass from the returning classes string + function getRainbowClasses($el){ + var classes = $el.attr('class'); + + if(~classes.indexOf(Rainbow.toggleHighlightClass)){ + var classes_arr = classes.split(' '), + idx = classes_arr.indexOf(Rainbow.toggleHighlightClass); + + if(idx>-1){ + classes_arr.splice(idx,1); + classes = ''+classes_arr.join(' ')+''; + } + } + + return classes; + } + +});