[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('console-filters', function (Y, NAME) { 9 10 /** 11 * <p>Provides Plugin.ConsoleFilters plugin class.</p> 12 * 13 * <p>This plugin adds the ability to control which Console entries display by filtering on category and source. Two groups of checkboxes are added to the Console footer, one for categories and the other for sources. Only those messages that match a checked category or source are displayed.</p> 14 * 15 * @module console-filters 16 * @namespace Plugin 17 * @class ConsoleFilters 18 */ 19 20 // Some common strings and functions 21 var getCN = Y.ClassNameManager.getClassName, 22 CONSOLE = 'console', 23 FILTERS = 'filters', 24 FILTER = 'filter', 25 CATEGORY = 'category', 26 SOURCE = 'source', 27 CATEGORY_DOT = 'category.', 28 SOURCE_DOT = 'source.', 29 30 HOST = 'host', 31 CHECKED = 'checked', 32 DEF_VISIBILITY = 'defaultVisibility', 33 34 DOT = '.', 35 EMPTY = '', 36 37 C_BODY = DOT + Y.Console.CHROME_CLASSES.console_bd_class, 38 C_FOOT = DOT + Y.Console.CHROME_CLASSES.console_ft_class, 39 40 SEL_CHECK = 'input[type=checkbox].', 41 42 isString = Y.Lang.isString; 43 44 function ConsoleFilters() { 45 ConsoleFilters.superclass.constructor.apply(this,arguments); 46 } 47 48 Y.namespace('Plugin').ConsoleFilters = Y.extend(ConsoleFilters, Y.Plugin.Base, 49 50 // Y.Plugin.ConsoleFilters prototype 51 { 52 /** 53 * Collection of all log messages passed through since the plugin's 54 * instantiation. This holds all messages regardless of filter status. 55 * Used as a single source of truth for repopulating the Console body when 56 * filters are changed. 57 * 58 * @property _entries 59 * @type Array 60 * @protected 61 */ 62 _entries : null, 63 64 /** 65 * Maximum number of entries to store in the message cache. 66 * 67 * @property _cacheLimit 68 * @type {Number} 69 * @default Infinity 70 * @protected 71 */ 72 _cacheLimit : Number.POSITIVE_INFINITY, 73 74 /** 75 * The container node created to house the category filters. 76 * 77 * @property _categories 78 * @type Node 79 * @protected 80 */ 81 _categories : null, 82 83 /** 84 * The container node created to house the source filters. 85 * 86 * @property _sources 87 * @type Node 88 * @protected 89 */ 90 _sources : null, 91 92 /** 93 * Initialize entries collection and attach listeners to host events and 94 * methods. 95 * 96 * @method initializer 97 * @protected 98 */ 99 initializer : function () { 100 this._entries = []; 101 102 this.get(HOST).on("entry", this._onEntry, this); 103 104 this.doAfter("renderUI", this.renderUI); 105 this.doAfter("syncUI", this.syncUI); 106 this.doAfter("bindUI", this.bindUI); 107 108 this.doAfter("clearConsole", this._afterClearConsole); 109 110 if (this.get(HOST).get('rendered')) { 111 this.renderUI(); 112 this.syncUI(); 113 this.bindUI(); 114 } 115 116 this.after("cacheLimitChange", this._afterCacheLimitChange); 117 }, 118 119 /** 120 * Removes the plugin UI and unwires events. 121 * 122 * @method destructor 123 * @protected 124 */ 125 destructor : function () { 126 //TODO: grab last {consoleLimit} entries and update the console with 127 //them (no filtering) 128 this._entries = []; 129 130 if (this._categories) { 131 this._categories.remove(); 132 } 133 if (this._sources) { 134 this._sources.remove(); 135 } 136 }, 137 138 /** 139 * Adds the category and source filter sections to the Console footer. 140 * 141 * @method renderUI 142 * @protected 143 */ 144 renderUI : function () { 145 var foot = this.get(HOST).get('contentBox').one(C_FOOT), 146 html; 147 148 if (foot) { 149 html = Y.Lang.sub( 150 ConsoleFilters.CATEGORIES_TEMPLATE, 151 ConsoleFilters.CHROME_CLASSES); 152 153 this._categories = foot.appendChild(Y.Node.create(html)); 154 155 html = Y.Lang.sub( 156 ConsoleFilters.SOURCES_TEMPLATE, 157 ConsoleFilters.CHROME_CLASSES); 158 159 this._sources = foot.appendChild(Y.Node.create(html)); 160 } 161 }, 162 163 /** 164 * Binds to checkbox click events and internal attribute change events to 165 * maintain the UI state. 166 * 167 * @method bindUI 168 * @protected 169 */ 170 bindUI : function () { 171 this._categories.on('click', Y.bind(this._onCategoryCheckboxClick, this)); 172 173 this._sources.on('click', Y.bind(this._onSourceCheckboxClick, this)); 174 175 this.after('categoryChange',this._afterCategoryChange); 176 this.after('sourceChange', this._afterSourceChange); 177 }, 178 179 /** 180 * Updates the UI to be in accordance with the current state of the plugin. 181 * 182 * @method syncUI 183 */ 184 syncUI : function () { 185 Y.each(this.get(CATEGORY), function (v, k) { 186 this._uiSetCheckbox(CATEGORY, k, v); 187 }, this); 188 189 Y.each(this.get(SOURCE), function (v, k) { 190 this._uiSetCheckbox(SOURCE, k, v); 191 }, this); 192 193 this.refreshConsole(); 194 }, 195 196 /** 197 * Ensures a filter is set up for any new categories or sources and 198 * collects the messages in _entries. If the message is stamped with a 199 * category or source that is currently being filtered out, the message 200 * will not pass to the Console's print buffer. 201 * 202 * @method _onEntry 203 * @param e {Event} the custom event object 204 * @protected 205 */ 206 _onEntry : function (e) { 207 this._entries.push(e.message); 208 209 var cat = CATEGORY_DOT + e.message.category, 210 src = SOURCE_DOT + e.message.source, 211 cat_filter = this.get(cat), 212 src_filter = this.get(src), 213 overLimit = this._entries.length - this._cacheLimit, 214 visible; 215 216 if (overLimit > 0) { 217 this._entries.splice(0, overLimit); 218 } 219 220 if (cat_filter === undefined) { 221 visible = this.get(DEF_VISIBILITY); 222 this.set(cat, visible); 223 cat_filter = visible; 224 } 225 226 if (src_filter === undefined) { 227 visible = this.get(DEF_VISIBILITY); 228 this.set(src, visible); 229 src_filter = visible; 230 } 231 232 if (!cat_filter || !src_filter) { 233 e.preventDefault(); 234 } 235 }, 236 237 /** 238 * Flushes the cached entries after a call to the Console's clearConsole(). 239 * 240 * @method _afterClearConsole 241 * @protected 242 */ 243 _afterClearConsole : function () { 244 this._entries = []; 245 }, 246 247 /** 248 * Triggers the Console to update if a known category filter 249 * changes value (e.g. visible => hidden). Updates the appropriate 250 * checkbox's checked state if necessary. 251 * 252 * @method _afterCategoryChange 253 * @param e {Event} the attribute change event object 254 * @protected 255 */ 256 _afterCategoryChange : function (e) { 257 var cat = e.subAttrName.replace(/category\./, EMPTY), 258 before = e.prevVal, 259 after = e.newVal; 260 261 // Don't update the console for new categories 262 if (!cat || before[cat] !== undefined) { 263 this.refreshConsole(); 264 265 this._filterBuffer(); 266 } 267 268 if (cat && !e.fromUI) { 269 this._uiSetCheckbox(CATEGORY, cat, after[cat]); 270 } 271 }, 272 273 /** 274 * Triggers the Console to update if a known source filter 275 * changes value (e.g. visible => hidden). Updates the appropriate 276 * checkbox's checked state if necessary. 277 * 278 * @method _afterSourceChange 279 * @param e {Event} the attribute change event object 280 * @protected 281 */ 282 _afterSourceChange : function (e) { 283 var src = e.subAttrName.replace(/source\./, EMPTY), 284 before = e.prevVal, 285 after = e.newVal; 286 287 // Don't update the console for new sources 288 if (!src || before[src] !== undefined) { 289 this.refreshConsole(); 290 291 this._filterBuffer(); 292 } 293 294 if (src && !e.fromUI) { 295 this._uiSetCheckbox(SOURCE, src, after[src]); 296 } 297 }, 298 299 /** 300 * Flushes the Console's print buffer of any entries that have a category 301 * or source that is currently being excluded. 302 * 303 * @method _filterBuffer 304 * @protected 305 */ 306 _filterBuffer : function () { 307 var cats = this.get(CATEGORY), 308 srcs = this.get(SOURCE), 309 buffer = this.get(HOST).buffer, 310 start = null, 311 i; 312 313 for (i = buffer.length - 1; i >= 0; --i) { 314 if (!cats[buffer[i].category] || !srcs[buffer[i].source]) { 315 start = start || i; 316 } else if (start) { 317 buffer.splice(i,(start - i)); 318 start = null; 319 } 320 } 321 if (start) { 322 buffer.splice(0,start + 1); 323 } 324 }, 325 326 /** 327 * Trims the cache of entries to the appropriate new length. 328 * 329 * @method _afterCacheLimitChange 330 * @param e {Event} the attribute change event object 331 * @protected 332 */ 333 _afterCacheLimitChange : function (e) { 334 if (isFinite(e.newVal)) { 335 var delta = this._entries.length - e.newVal; 336 337 if (delta > 0) { 338 this._entries.splice(0,delta); 339 } 340 } 341 }, 342 343 /** 344 * Repopulates the Console with entries appropriate to the current filter 345 * settings. 346 * 347 * @method refreshConsole 348 */ 349 refreshConsole : function () { 350 var entries = this._entries, 351 host = this.get(HOST), 352 body = host.get('contentBox').one(C_BODY), 353 remaining = host.get('consoleLimit'), 354 cats = this.get(CATEGORY), 355 srcs = this.get(SOURCE), 356 buffer = [], 357 i,e; 358 359 if (body) { 360 host._cancelPrintLoop(); 361 362 // Evaluate all entries from latest to oldest 363 for (i = entries.length - 1; i >= 0 && remaining >= 0; --i) { 364 e = entries[i]; 365 if (cats[e.category] && srcs[e.source]) { 366 buffer.unshift(e); 367 --remaining; 368 } 369 } 370 371 body.setHTML(EMPTY); 372 host.buffer = buffer; 373 host.printBuffer(); 374 } 375 }, 376 377 /** 378 * Updates the checked property of a filter checkbox of the specified type. 379 * If no checkbox is found for the input params, one is created. 380 * 381 * @method _uiSetCheckbox 382 * @param type {String} 'category' or 'source' 383 * @param item {String} the name of the filter (e.g. 'info', 'event') 384 * @param checked {Boolean} value to set the checkbox's checked property 385 * @protected 386 */ 387 _uiSetCheckbox : function (type, item, checked) { 388 if (type && item) { 389 var container = type === CATEGORY ? 390 this._categories : 391 this._sources, 392 sel = SEL_CHECK + getCN(CONSOLE,FILTER,item), 393 checkbox = container.one(sel), 394 host; 395 396 if (!checkbox) { 397 host = this.get(HOST); 398 399 this._createCheckbox(container, item); 400 401 checkbox = container.one(sel); 402 403 host._uiSetHeight(host.get('height')); 404 } 405 406 checkbox.set(CHECKED, checked); 407 } 408 }, 409 410 /** 411 * Passes checkbox clicks on to the category attribute. 412 * 413 * @method _onCategoryCheckboxClick 414 * @param e {Event} the DOM event 415 * @protected 416 */ 417 _onCategoryCheckboxClick : function (e) { 418 var t = e.target, cat; 419 420 if (t.hasClass(ConsoleFilters.CHROME_CLASSES.filter)) { 421 cat = t.get('value'); 422 if (cat && cat in this.get(CATEGORY)) { 423 this.set(CATEGORY_DOT + cat, t.get(CHECKED), { fromUI: true }); 424 } 425 } 426 }, 427 428 /** 429 * Passes checkbox clicks on to the source attribute. 430 * 431 * @method _onSourceCheckboxClick 432 * @param e {Event} the DOM event 433 * @protected 434 */ 435 _onSourceCheckboxClick : function (e) { 436 var t = e.target, src; 437 438 if (t.hasClass(ConsoleFilters.CHROME_CLASSES.filter)) { 439 src = t.get('value'); 440 if (src && src in this.get(SOURCE)) { 441 this.set(SOURCE_DOT + src, t.get(CHECKED), { fromUI: true }); 442 } 443 } 444 }, 445 446 /** 447 * Hides any number of categories from the UI. Convenience method for 448 * myConsole.filter.set('category.foo', false); set('category.bar', false); 449 * and so on. 450 * 451 * @method hideCategory 452 * @param cat* {String} 1..n categories to filter out of the UI 453 */ 454 hideCategory : function (cat, multiple) { 455 if (isString(multiple)) { 456 Y.Array.each(arguments, this.hideCategory, this); 457 } else { 458 this.set(CATEGORY_DOT + cat, false); 459 } 460 }, 461 462 /** 463 * Shows any number of categories in the UI. Convenience method for 464 * myConsole.filter.set('category.foo', true); set('category.bar', true); 465 * and so on. 466 * 467 * @method showCategory 468 * @param cat* {String} 1..n categories to allow to display in the UI 469 */ 470 showCategory : function (cat, multiple) { 471 if (isString(multiple)) { 472 Y.Array.each(arguments, this.showCategory, this); 473 } else { 474 this.set(CATEGORY_DOT + cat, true); 475 } 476 }, 477 478 /** 479 * Hides any number of sources from the UI. Convenience method for 480 * myConsole.filter.set('source.foo', false); set('source.bar', false); 481 * and so on. 482 * 483 * @method hideSource 484 * @param src* {String} 1..n sources to filter out of the UI 485 */ 486 hideSource : function (src, multiple) { 487 if (isString(multiple)) { 488 Y.Array.each(arguments, this.hideSource, this); 489 } else { 490 this.set(SOURCE_DOT + src, false); 491 } 492 }, 493 494 /** 495 * Shows any number of sources in the UI. Convenience method for 496 * myConsole.filter.set('source.foo', true); set('source.bar', true); 497 * and so on. 498 * 499 * @method showSource 500 * @param src* {String} 1..n sources to allow to display in the UI 501 */ 502 showSource : function (src, multiple) { 503 if (isString(multiple)) { 504 Y.Array.each(arguments, this.showSource, this); 505 } else { 506 this.set(SOURCE_DOT + src, true); 507 } 508 }, 509 510 /** 511 * Creates a checkbox and label from the ConsoleFilters.FILTER_TEMPLATE for 512 * the provided type and name. The checkbox and label are appended to the 513 * container node passes as the first arg. 514 * 515 * @method _createCheckbox 516 * @param container {Node} the parentNode of the new checkbox and label 517 * @param name {String} the identifier of the filter 518 * @protected 519 */ 520 _createCheckbox : function (container, name) { 521 var info = Y.merge(ConsoleFilters.CHROME_CLASSES, { 522 filter_name : name, 523 filter_class : getCN(CONSOLE, FILTER, name) 524 }), 525 node = Y.Node.create( 526 Y.Lang.sub(ConsoleFilters.FILTER_TEMPLATE, info)); 527 528 container.appendChild(node); 529 }, 530 531 /** 532 * Validates category updates are objects and the subattribute is not too 533 * deep. 534 * 535 * @method _validateCategory 536 * @param cat {String} the new category:visibility map 537 * @param v {String} the subattribute path updated 538 * @return Boolean 539 * @protected 540 */ 541 _validateCategory : function (cat, v) { 542 return Y.Lang.isObject(v,true) && cat.split(/\./).length < 3; 543 }, 544 545 /** 546 * Validates source updates are objects and the subattribute is not too 547 * deep. 548 * 549 * @method _validateSource 550 * @param cat {String} the new source:visibility map 551 * @param v {String} the subattribute path updated 552 * @return Boolean 553 * @protected 554 */ 555 _validateSource : function (src, v) { 556 return Y.Lang.isObject(v,true) && src.split(/\./).length < 3; 557 }, 558 559 /** 560 * Setter method for cacheLimit attribute. Basically a validator to ensure 561 * numeric input. 562 * 563 * @method _setCacheLimit 564 * @param v {Number} Maximum number of entries 565 * @return {Number} 566 * @protected 567 */ 568 _setCacheLimit: function (v) { 569 if (Y.Lang.isNumber(v)) { 570 this._cacheLimit = v; 571 return v; 572 } else { 573 return Y.Attribute.INVALID_VALUE; 574 } 575 } 576 }, 577 578 // Y.Plugin.ConsoleFilters static properties 579 { 580 /** 581 * Plugin name. 582 * 583 * @property NAME 584 * @type String 585 * @static 586 * @default 'consoleFilters' 587 */ 588 NAME : 'consoleFilters', 589 590 /** 591 * The namespace hung off the host object that this plugin will inhabit. 592 * 593 * @property NS 594 * @type String 595 * @static 596 * @default 'filter' 597 */ 598 NS : FILTER, 599 600 /** 601 * Markup template used to create the container for the category filters. 602 * 603 * @property CATEGORIES_TEMPLATE 604 * @type String 605 * @static 606 */ 607 CATEGORIES_TEMPLATE : 608 '<div class="{categories}"></div>', 609 610 /** 611 * Markup template used to create the container for the source filters. 612 * 613 * @property SOURCES_TEMPLATE 614 * @type String 615 * @static 616 */ 617 SOURCES_TEMPLATE : 618 '<div class="{sources}"></div>', 619 620 /** 621 * Markup template used to create the category and source filter checkboxes. 622 * 623 * @property FILTER_TEMPLATE 624 * @type String 625 * @static 626 */ 627 FILTER_TEMPLATE : 628 // IE8 and FF3 don't permit breaking _between_ nowrap elements. IE8 629 // doesn't understand (non spec) wbr tag, nor does it create text nodes 630 // for spaces in innerHTML strings. The thin-space entity suffices to 631 // create a breakable point. 632 '<label class="{filter_label}">'+ 633 '<input type="checkbox" value="{filter_name}" '+ 634 'class="{filter} {filter_class}"> {filter_name}'+ 635 '</label> ', 636 637 /** 638 * Classnames used by the templates when creating nodes. 639 * 640 * @property CHROME_CLASSES 641 * @type Object 642 * @static 643 * @protected 644 */ 645 CHROME_CLASSES : { 646 categories : getCN(CONSOLE,FILTERS,'categories'), 647 sources : getCN(CONSOLE,FILTERS,'sources'), 648 category : getCN(CONSOLE,FILTER,CATEGORY), 649 source : getCN(CONSOLE,FILTER,SOURCE), 650 filter : getCN(CONSOLE,FILTER), 651 filter_label : getCN(CONSOLE,FILTER,'label') 652 }, 653 654 ATTRS : { 655 /** 656 * Default visibility applied to new categories and sources. 657 * 658 * @attribute defaultVisibility 659 * @type {Boolean} 660 * @default true 661 */ 662 defaultVisibility : { 663 value : true, 664 validator : Y.Lang.isBoolean 665 }, 666 667 /** 668 * <p>Map of entry categories to their visibility status. Update a 669 * particular category's visibility by setting the subattribute to true 670 * (visible) or false (hidden).</p> 671 * 672 * <p>For example, yconsole.filter.set('category.info', false) to hide 673 * log entries with the category/logLevel of 'info'.</p> 674 * 675 * <p>Similarly, yconsole.filter.get('category.warn') will return a 676 * boolean indicating whether that category is currently being included 677 * in the UI.</p> 678 * 679 * <p>Unlike the YUI instance configuration's logInclude and logExclude 680 * properties, filtered entries are only hidden from the UI, but 681 * can be made visible again.</p> 682 * 683 * @attribute category 684 * @type Object 685 */ 686 category : { 687 value : {}, 688 validator : function (v,k) { 689 return this._validateCategory(k,v); 690 } 691 }, 692 693 /** 694 * <p>Map of entry sources to their visibility status. Update a 695 * particular sources's visibility by setting the subattribute to true 696 * (visible) or false (hidden).</p> 697 * 698 * <p>For example, yconsole.filter.set('sources.slider', false) to hide 699 * log entries originating from Y.Slider.</p> 700 * 701 * @attribute source 702 * @type Object 703 */ 704 source : { 705 value : {}, 706 validator : function (v,k) { 707 return this._validateSource(k,v); 708 } 709 }, 710 711 /** 712 * Maximum number of entries to store in the message cache. Use this to 713 * limit the memory footprint in environments with heavy log usage. 714 * By default, there is no limit (Number.POSITIVE_INFINITY). 715 * 716 * @attribute cacheLimit 717 * @type {Number} 718 * @default Number.POSITIVE_INFINITY 719 */ 720 cacheLimit : { 721 value : Number.POSITIVE_INFINITY, 722 setter : function (v) { 723 return this._setCacheLimit(v); 724 } 725 } 726 } 727 }); 728 729 730 }, '3.17.2', {"requires": ["plugin", "console"], "skinnable": true});
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |