1'use strict'; 2/** 3*/ 4angular.module('swd.inspector-gadget', []); 5 6angular.module('swd.inspector-gadget') 7 .service('intPopover', function() { 8 this.bootstrap = function(elm, config) { 9 elm.popover(config); 10 return { 11 show: function() { 12 elm.popover('show'); 13 }, 14 hide: function() { 15 elm.popover('hide'); 16 } 17 }; 18 }; 19 20 }); 21 22 23angular.module('swd.inspector-gadget') 24 .directive('inspectorGadget', function($compile, $document, intPopover, $timeout) { 25 var doc = $document[0]; 26 27 var rootNode = function(elm) { 28 return angular.element(elm.parentsUntil().slice(-1)[0]); 29 }; 30 31 // some helpers 32 var tagHtml = function(childElm, tag) { 33 if (tag) { 34 var tagDiv = doc.createElement('div'); 35 tagDiv.setAttribute('data-inspector-gadget-tag', tag); 36 tagDiv.setAttribute('style', 'display: none'); 37 childElm.appendChild(tagDiv); 38 } 39 var childHtml = childElm.innerHTML; 40 return childHtml; 41 }; 42 43 var collectPopoverAttrArgs = function(attrs) { 44 var bootstrArgs = {}; 45 angular.forEach(attrs, function(attrValue, attrName) { 46 // only allow certain attributes 47 if (attrName === 'placement' || attrName === 'animation' || 48 attrName === 'delay' || attrName === 'container' || 49 attrName === 'viewport') { 50 bootstrArgs[attrName] = attrValue; 51 } 52 }); 53 return bootstrArgs; 54 }; 55 56 var getPopoverContainer = function(rootNode, popoverId) { 57 var elm = rootNode.find('div[data-inspector-gadget-tag="' + popoverId + '"]'); 58 var popover = elm.parent().parent(); 59 return popover; 60 }; 61 62 var uniqueDirective = 1; 63 64 var link = function(scope, element, attrs) { 65 var anchoredDiv = element.find('.popover-anchor'); 66 var root = rootNode(anchoredDiv); 67 68 var myPopoverId = scope._insp.popoverId; 69 var titleHtml = scope._insp.titleHtml; 70 var contentHtml = scope._insp.contentHtml; 71 72 var popConfig = collectPopoverAttrArgs(attrs); 73 var timeout = 500; 74 if (attrs.hasOwnProperty('timeout')) { 75 timeout = parseInt(attrs.timeout, 10); 76 } 77 78 var popControl = null; 79 80 var hidePromise = null; 81 82 popConfig.html = true; 83 popConfig.title = function() { 84 return titleHtml; 85 }; 86 popConfig.content = function() { 87 return contentHtml; 88 }; 89 popConfig.trigger = 'manual'; 90 91 var rendered; 92 93 var isPopOpen = function(root, myPopoverId) { 94 return getPopoverContainer(root, myPopoverId).length > 0; 95 }; 96 97 var hide = function() { 98 popControl.hide(); 99 }; 100 101 anchoredDiv.mouseenter(function() { 102 // trigger hover event, open popover, link btn to modal 103 $timeout.cancel(hidePromise); 104 if (!isPopOpen(root, myPopoverId)) { 105 rendered = false; 106 popControl.show(); 107 // TODO remaining problem -- this compiles 108 var popCont = getPopoverContainer(root, myPopoverId); 109 popCont.mouseenter(function() { 110 $timeout.cancel(hidePromise); 111 }); 112 popCont.mouseleave(function() { 113 $timeout.cancel(hidePromise); 114 hidePromise = $timeout(function() { 115 hide(); 116 }, timeout); 117 }); 118 119 $compile(popCont.contents())(scope); 120 scope.$apply(); 121 } 122 }); 123 anchoredDiv.on('shown.bs.popover', function() { 124 rendered = true; 125 }); 126 anchoredDiv.mouseleave(function() { 127 $timeout.cancel(hidePromise); 128 hidePromise = $timeout(function() { 129 hide(); 130 }, timeout); 131 }); 132 popControl = intPopover.bootstrap(anchoredDiv, popConfig); 133 134 }; 135 return { 136 restrict: 'E', 137 transclude: true, 138 //template: '<div ng-transclude></div>', 139 140 compile: function(elem, attrs, transclude) { 141 return function(scope, /*out*/lElem /*out lAttrs*/) { 142 var childScope = scope.$new(); 143 transclude(childScope, function(clone, innerScope) { 144 innerScope._insp = {}; 145 var div = angular.element('<div class="popover-anchor"></div>'); 146 angular.forEach(clone, function(c) { 147 if (c.nodeType !== 1 || (c.tagName !== 'INSPECTOR-TITLE' && c.tagName !== 'INSPECTOR-CONTENT')) { 148 div.append(c); 149 } 150 else if (c.nodeType === 1 && c.tagName === 'INSPECTOR-CONTENT') { 151 innerScope._insp.contentHtml = c.innerHTML; 152 } 153 else if (c.nodeType === 1 && c.tagName === 'INSPECTOR-TITLE') { 154 var myPopoverId = uniqueDirective++; 155 innerScope._insp.popoverId = myPopoverId; 156 innerScope._insp.titleHtml = tagHtml(c, myPopoverId); 157 } 158 }); 159 lElem.append(div); 160 }); 161 link(childScope, angular.element(lElem[0]), attrs); 162 }; 163 }, 164 }; 165 }); 166 167angular.module('swd.inspector-gadget') 168 .directive('inspectorContent', function() { 169 return { 170 require: '^inspectorGadget', 171 restrict: 'E', 172 terminal: true, // prevent compilation of my content, for later compilation 173 priority: 1000 174 }; 175 }); 176 177 178angular.module('swd.inspector-gadget') 179 .directive('inspectorTitle', function() { 180 return { 181 require: '^inspectorGadget', 182 restrict: 'E', 183 terminal: true, // prevent compilation of my content, for later compilation 184 priority: 1000 185 }; 186 }); 187 188
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.