1// shinyjs 2.1.0 by Dean Attali 2// Perform common JavaScript operations in Shiny apps using plain R code 3 4shinyjs = function() { 5 6 // -------------------------------- 7 // ------ Private variables ------- 8 9 // store the event handlers for the onevent function when it's called on 10 // elements that do not exist yet in the document 11 var _oneventData = {}; 12 13 // some functions need to work with dynamically generated elements, so they 14 // can add themselves to this list and will be called whenever the DOM is mutated 15 var _mutationSubscribers = []; 16 17 // --------------------------------------- 18 // ------ General helper functions ------- 19 20 // get an element by id using JQuery (escape chars that have special 21 // selector meaning) 22 var _jqid = function(id) { 23 return $("#" + id.replace( /(:|\.|\[|\]|,|\s)/g, "\\$1" )); 24 }; 25 26 // listen to DOM changes and whenever there are new nodes added, let all 27 // the mutation subscribers know about the new elements 28 var _initMutations = function() { 29 var canObserveMutation = 'MutationObserver' in window; 30 if (canObserveMutation) { 31 var mutationCallback = function(mutations) { 32 mutations.forEach(function(mutation) { 33 $.each(mutation.addedNodes, function(idx, node) { 34 $.each(_mutationSubscribers, function(idx, fxn) { 35 // call the subscriber on each new node 36 fxn(node); 37 }); 38 }); 39 }); 40 }; 41 var observer = new MutationObserver(mutationCallback); 42 observer.observe(document.body, { childList : true, subtree : true }); 43 } 44 }; 45 46 // if the given HTML tag is a shiny input, return the input container. 47 // otherwise, return the original tag 48 var _getContainer = function(els) { 49 return $.map(els, function(el) { 50 el = $(el); 51 if (el.hasClass("shiny-bound-input")) { 52 var inputContainer = el.closest(".shiny-input-container"); 53 if (inputContainer.length > 0) { 54 el = inputContainer; 55 } 56 } 57 return el; 58 }); 59 }; 60 61 // given a function parameters with several different ways to get DOM 62 // elements, retrieve the correct ones 63 var _getElements = function(params) { 64 var $els = null; 65 if (params.elements !== null && typeof params.elements !== "undefined") { 66 $els = params.elements; 67 } else if (params.id !== null && typeof params.id !== "undefined") { 68 $els = _jqid(params.id); 69 } else if (params.selector !== null && typeof params.selector !== "undefined") { 70 $els = $(params.selector); 71 } 72 if ($els === null || $els === undefined || $els.length == 0) { 73 shinyjs.debugMessage("shinyjs: Could not find DOM element using these parameters:"); 74 shinyjs.debugMessage(params); 75 $els = null; 76 } 77 return $els; 78 }; 79 80 // ----------------------------------- 81 // ------ Helpers for `toggle` ------- 82 83 // is an element currently hidden? 84 var _isHidden = function(el) { 85 return el.css("display") === "none"; 86 }; 87 88 // ---------------------------------------- 89 // ------ Helpers for `toggleState` ------- 90 91 // is an element currently disabled? 92 var _isDisabled = function(el) { 93 return el.prop('disabled') === true; 94 }; 95 96 // ------------------------------------- 97 // ------ Helpers for `disabled` ------- 98 99 // disable all the elements that were initialized as disabled 100 var _initDisabled = function() { 101 // disable elements on page load 102 _initDisabledHelper($(".shinyjs-disabled")); 103 104 // disable new elements being added to the document 105 _mutationSubscribers.push(function(node) { 106 _initDisabledHelper($(node).find(".shinyjs-disabled")); 107 if ($(node).is(".shinyjs-disabled")) { 108 _initDisabledHelper($(node)); 109 } 110 }); 111 }; 112 113 var _initDisabledHelper = function(els) { 114 if (els.length == 0) return; 115 116 // use a tiny delay because some input elements (sliders, selectize) need 117 // to first be initialized, and I don't know how to tell when they're ready 118 setTimeout(function() { 119 // disable elements 120 shinyjs.disable({ elements : els }); 121 }, 10); 122 }; 123 124 // ---------------------------------------- 125 // ------ Helpers for `show`/`hide` ------- 126 127 var _showHide = function(method, params) { 128 var defaultParams = { 129 id : null, 130 anim : false, 131 animType : "slide", 132 time : 0.5, 133 selector : null, 134 elements : null 135 }; 136 params = shinyjs.getParams(params, defaultParams); 137 138 var $els = _getElements(params); 139 if ($els === null) return; 140 141 // for input elements, hide the whole container, not just the input 142 $els = _getContainer($els); 143 144 // if an element was hidden on page load, remove that flag 145 $.map($els, function(el) { 146 if ($(el).hasClass("shinyjs-hide")) { 147 $(el).removeClass("shinyjs-hide"); 148 $(el).hide(); 149 } 150 });
151 152 if (!params.anim) { 153 $.map($els, function(el) { 154 (method == "show") ? 155 $(el).show() : 156 $(el).hide(); 157 }); 158 } else { 159 if (params.animType == "fade") { 160 $.map($els, function(el) { 161 (method == "show") ? 162 $(el).fadeIn(params.time * 1000) : 163 $(el).fadeOut(params.time * 1000); 164 }); 165 } else { 166 $.map($els, function(el) { 167 (method == "show") ? 168 $(el).slideDown(params.time * 1000) : 169 $(el).slideUp(params.time * 1000); 170 }); 171 } 172 } 173 174 // If an element was initially hidden when app started, tell shiny that 175 // it's now visible so that it can properly render dynamic elements 176 $.map($els, function(el) { 177 $(el).trigger(method == "show" ? "shown" : "hidden"); 178 }); 179 }; 180 181 // --------------------------------------------------- 182 // ------ Helpers for `addClass`/`removeClass` ------- 183 184 var _addRemoveClass = function(method, params) { 185 var defaultParams = { 186 id : null, 187 class : null, 188 selector : null, 189 elements : null 190 }; 191 params = shinyjs.getParams(params, defaultParams); 192 193 var $els = _getElements(params); 194 if ($els === null) return; 195 196 (method == "add") ? 197 $els.addClass(params.class) : 198 $els.removeClass(params.class); 199 }; 200 201 // --------------------------------------------------- 202 // ------ Helpers for `enable`/`disable` ------------- 203 204 var _enableDisable = function(method, params) { 205 var defaultParams = { 206 id : null, 207 selector : null, 208 elements : null 209 }; 210 params = shinyjs.getParams(params, defaultParams); 211 212 var $els = _getElements(params); 213 if ($els === null) return; 214 215 // make sure we take special care of elements that need to be specifically 216 // enabled with special javascript 217 var toadd = $els.find(".selectized, .js-range-slider"); 218 $els = $($els.toArray().concat(toadd.toArray())); 219 220 $.map($els, function(el) { 221 var $el = $(el); 222 223 // selectize and slider inputs need special javascript 224 if ($el.hasClass("selectized")) { 225 (method == "enable") ? 226 $el.selectize()[0].selectize.enable() : 227 $el.selectize()[0].selectize.disable(); 228 } else if ($el.hasClass("js-range-slider")) { 229 $el.data("ionRangeSlider").update({ disable : (method == "disable") }); 230 } 231 // for colour inputs, we want to enable/disable all input fields 232 else if ($el.hasClass("shiny-colour-input")) { 233 $el = $(_getContainer($el)[0]); 234 } 235 236 // enable/disable the container as well as all individual inputs inside 237 // (this is needed for grouped inputs such as radio and checkbox groups) 238 var toadd = $el.find("input, button, textarea, select, a[download]"); 239 $el = $($el.toArray().concat(toadd.toArray())); 240 $el.attr('disabled', (method == "disable")); 241 $el.prop('disabled', (method == "disable")); 242 method == "disable" ? $el.addClass("disabled") : $el.removeClass("disabled"); 243 }); 244 }; 245 246 // ---------------------------------- 247 // ------ Helpers for `reset` ------- 248 249 // find all shiny input elements and set them up to allow them to be reset 250 var _initResettables = function() { 251 // grab all the shiny input containers that exist when the app loads 252 _initResettablesHelper($(".shiny-input-container")); 253 254 // observer new elements added to the document so that dynamically generated 255 // elements can also be resettable 256 _mutationSubscribers.push(function(node) { 257 _initResettablesHelper($(node).find(".shiny-input-container")); 258 if ($(node).is(".shiny-input-container")) { 259 _initResettablesHelper($(node)); 260 } 261 }); 262 }; 263 264 // helper function to get the initial date from a bootstrap date element 265 // if there is no initial date, return the current date 266 var _getInputDate = function(el) { 267 if (el[0].hasAttribute('data-initial-date')) { 268 if (el.attr('data-initial-date') === "") { 269 return 'NA'; 270 } else { 271 return el.attr('data-initial-date'); 272 } 273 } 274 var today = new Date(); 275 var yyyy = today.getFullYear().toString(); 276 var mm = (today.getMonth() + 1).toString(); 277 var dd = today.getDate().toString(); 278 return yyyy + '-' + (mm[1]?mm:"0"+mm[0]) + '-' + (dd[1]?dd:"0"+dd[0]); 279 }; 280 281 // go through every Shiny input and based on what kind of input it is, 282 // add some information to the HTML tag so that we can know how to 283 // update it back to its original value 284 var _initResettablesHelper = function(els) { 285 for (var j = 0; j < els.length; j++) { 286 var inputContainer = $(els[j]); 287 var input = inputContainer; 288 var foundInput = true; 289 var inputType = null, 290 inputValue = null, 291 inputId = null; 292 293 // dateInput 294 if (input.hasClass("shiny-date-input")) { 295 input = input.children("input"); 296 inputType = "Date"; 297 inputValue = _getInputDate(input); 298 inputId = inputContainer.attr('id'); 299 } 300 // dateRangeInput 301 else if (input.hasClass("shiny-date-range-input")) { 302 inputType = "DateRange"; 303 inputValue = _getInputDate($(input.find("input")[0])) + "," + 304 _getInputDate($(input.find("input")[1])); 305 } 306 // checkboxGroupInput
307 else if (input.hasClass("shiny-input-checkboxgroup")) { 308 inputType = "CheckboxGroup"; 309 var selected = []; 310 var selectedEls = input.find("input[type='checkbox']:checked"); 311 selectedEls.each(function() { 312 selected.push($(this).val()); 313 }); 314 inputValue = JSON.stringify(selected); 315 } 316 // radioButtons 317 else if (input.hasClass("shiny-input-radiogroup")) { 318 inputType = "RadioButtons"; 319 inputValue = input.find("input[type='radio']:checked").val(); 320 } 321 // sliderInput 322 else if (input.children(".js-range-slider").length > 0) { 323 input = input.children(".js-range-slider"); 324 inputType = "Slider"; 325 if (typeof input.attr('data-from') !== "undefined") { 326 inputValue = input.attr('data-from'); 327 } 328 if (typeof input.attr('data-to') !== "undefined") { 329 inputValue = inputValue + "," + input.attr('data-to'); 330 } 331 } 332 // selectInput / selectizeInput 333 else if (input.find("select").length > 0) { 334 input = input.find("select"); 335 inputType = "Select"; 336 inputValue = input.val(); 337 if (inputValue === null) { 338 inputValue = ""; 339 } 340 inputValue = JSON.stringify(inputValue); 341 } 342 // colourInput 343 else if (input.children("input.shiny-colour-input").length > 0) { 344 input = input.children("input.shiny-colour-input"); 345 inputType = "Colour"; 346 inputValue = input.attr('data-init-value'); 347 } 348 // numericInput 349 else if (input.children("input[type='number']").length > 0) { 350 input = input.children("input[type='number']"); 351 inputType = "Numeric"; 352 } 353 // textInput 354 else if (input.children("input[type='text']").length > 0) { 355 input = input.children("input[type='text']"); 356 inputType = "Text"; 357 } 358 // checkboxInput 359 else if (input.find("input[type='checkbox']").length > 0) { 360 input = input.find("input[type='checkbox']"); 361 inputType = "Checkbox"; 362 inputValue = input.prop('checked'); 363 } 364 // passwordInput 365 else if (input.children("input[type='password']").length > 0) { 366 input = input.children("input[type='password']"); 367 inputType = "Password"; 368 } 369 // textAreaInput 370 else if (input.children("textarea").length > 0) { 371 input = input.children("textarea"); 372 inputType = "TextArea"; 373 } 374 else if (input.find("input[type='file']").length > 0) { 375 input = input.find("input[type='file']"); 376 inputType = "File" 377 } 378 // if none of the above, no supported Shiny input was found 379 else { 380 foundInput = false; 381 } 382 383 // if we found a Shiny input, set all the info on it 384 if (foundInput) { 385 if (inputId === null) { 386 inputId = input.attr('id'); 387 } 388 if (inputValue === null) { 389 inputValue = input.val(); 390 } 391 input.attr('data-shinyjs-resettable-id', inputId). 392 attr('data-shinyjs-resettable-type', inputType). 393 attr('data-shinyjs-resettable-value', inputValue). 394 addClass('shinyjs-resettable'); 395 } 396 } 397 }; 398 399 // ------------------------------------ 400 // ------ Helpers for `onevent` ------- 401 402 // ensure that the onevent function works for dynamic elements 403 var _initOnevent = function() { 404 // for every new node in the DOM, check if there is an ID that was registered 405 // with `onevent` for a dynamic element that corresponds to a node that was 406 // just created. If so, find out what events were registered to it and the 407 // shiny event handlers for it, and attach them 408 _mutationSubscribers.push(function(node) { 409 // check the top node 410 var $node = $(node); 411 var id = $node.attr("id"); 412 _eventsAttachById(id); 413 // check all descendants 414 $node.find("*").each(function() { 415 var id = $(this).attr("id"); 416 _eventsAttachById(id); 417 }); 418 });
419 }; 420 421 // Attach all events registered for a given id (if any) 422 var _eventsAttachById = function(id) { 423 var elementData = _oneventData[id]; 424 if (elementData !== null) { 425 $.each(elementData, function(event, eventDatas) { 426 $.each(eventDatas, function(idx, eventData) { 427 _oneventAttach({ 428 event : event, 429 id : id, 430 shinyInputId : eventData.shinyInputId, 431 add : true, 432 customProps : eventData.customProps 433 }); 434 }); 435 }); 436 } 437 }; 438 439 // attach an event listener to a DOM element that will trigger a call to Shiny 440 var _oneventAttach = function(params) { 441 var el = _jqid(params.id); 442 443 // for shiny inputs, perform the action when the event happens in any 444 // section of the input widget 445 el = $(_getContainer(el)[0]); 446 447 var shinyInputId = params.shinyInputId; 448 var attrName = "data-shinyjs-" + params.event; 449 450 // if this is the first event handler of this event type we attach to this 451 // element, initialize the data attribute and add the event handler 452 var first = !(el[0].hasAttribute(attrName)); 453 if (first) { 454 el.attr(attrName, JSON.stringify(Object())); 455 456 el[params.event](function(event) { 457 // Store a subset of the event properties (many are non-serializeable) 458 var props = ['altKey', 'button', 'buttons', 'clientX', 'clientY', 459 'ctrlKey', 'pageX', 'pageY', 'screenX', 'screenY', 'shiftKey', 460 'which', 'charCode', 'key', 'keyCode', 'offsetX', 'offsetY']; 461 props = props.concat(params.customProps); 462 var eventSimple = {}; 463 $.each(props, function(idx, prop) { 464 if (prop in event) { 465 eventSimple[prop] = event[prop]; 466 } 467 }); 468 eventSimple.shinyjsRandom = Math.random(); 469 470 var oldValues = JSON.parse(el.attr(attrName)); 471 var newValues = Object(); 472 $.each(oldValues, function(key, value) { 473 var newValue = value + 1; 474 newValues[key] = newValue; 475 Shiny.onInputChange(key, eventSimple); 476 }); 477 478 el.attr(attrName, JSON.stringify(newValues)); 479 }); 480 } 481 482 // if we want this action to overwrite existing ones, unbind event handler 483 if (params.add) { 484 var attrValue = JSON.parse(el.attr(attrName)); 485 } else { 486 var attrValue = {}; 487 } 488 attrValue[shinyInputId] = 0; 489 el.attr(attrName, JSON.stringify(attrValue)); 490 }; 491 492 return { 493 494 // by default, debug mode is off. If shinyjs is initialized with debug mode, 495 // then debugging messages will be printed to the console 496 debug : false, 497 498 // write a message to the console for debugging purposes if debug mode is on 499 debugMessage : function(text) { 500 if (shinyjs.debug) { 501 console.info(text); 502 } 503 }, 504 505 // Given a set of user-provided parameters and some default parameters, 506 // return a dictionary of key-value parameter pairs. 507 // The user parameters can either be an (unnamed) array, in which case 508 // we assume the order of the parameters, or it can be a dictionary with 509 // key-value parameter pairs. 510 getParams : function (params, defaultParams) { 511 var finalParams = defaultParams; 512 if (typeof params == "string") { 513 params = Array(params); 514 } 515 if (params instanceof Array) { 516 for (var i = 0; i < params.length; i++) { 517 finalParams[Object.keys(finalParams)[i]] = params[i]; 518 } 519 } else { 520 $.extend(finalParams, params); 521 } 522 523 return finalParams; 524 }, 525 526 // this function gets called once (automatically) to initialize shinyjs 527 initShinyjs : function() { 528 _initMutations(); 529 _initResettables(); 530 _initDisabled(); 531 _initOnevent(); 532 shinyjs.init(); 533 }, 534 535 // the init function should not be implemented here, it is a placeholder 536 // so that users can define their own `shinyjs.init` function (using extendShinyjs) 537 // that will be run when the page is initialized 538 init : function() {}, 539 540 // ----------------------------------------------------------------- 541 // ------ All functions below are exported shinyjs function -------- 542 // The documentation for function foo is available in R via ?shinyjs::foo 543 544 show : function (params) { 545 _showHide("show", params); 546 }, 547 548 hide : function (params) { 549 _showHide("hide", params); 550 }, 551 552 toggle : function (params) { 553 var defaultParams = { 554 id : null, 555 anim : false, 556 animType : "slide", 557 time : 0.5, 558 selector : null, 559 condition : null 560 }; 561 params = shinyjs.getParams(params, defaultParams); 562 563 // if there is no condition, then hide/show each element based on whether 564 // it is currently shown or hidden 565 if (params.condition === null) { 566 var $els = _getElements(params); 567 if ($els === null) return; 568 569 // for input elements, toggle the whole container, not just the input 570 $els = _getContainer($els); 571 572 $.map($els, function(el) { 573 params.elements = $(el); 574 _isHidden($(el)) ? shinyjs.show(params) : shinyjs.hide(params); 575 }); 576 } 577 else if (params.condition) { 578 shinyjs.show(params); 579 } else { 580 shinyjs.hide(params); 581 } 582 }, 583 584 addClass : function (params) { 585 _addRemoveClass("add", params); 586 }, 587 588 removeClass : function (params) { 589 _addRemoveClass("remove", params); 590 }, 591 592 toggleClass : function (params) { 593 var defaultParams = { 594 id : null, 595 class : null, 596 condition : null, 597 selector : null 598 }; 599 params = shinyjs.getParams(params, defaultParams); 600 601 // it there is no condition, add/remove class based on current state 602 if (params.condition === null) { 603 var $els = _getElements(params); 604 if ($els === null) return; 605 606 $.map($els, function(el) { 607 params.elements = $(el); 608 $(el).hasClass(params.class) ? shinyjs.removeClass(params) : shinyjs.addClass(params); 609 }); 610 } 611 else if (params.condition) { 612 shinyjs.addClass(params); 613 } else { 614 shinyjs.removeClass(params); 615 } 616 }, 617 618 enable : function (params) { 619 _enableDisable("enable", params); 620 }, 621 622 disable : function (params) { 623 _enableDisable("disable", params); 624 }, 625 626 toggleState : function (params) { 627 var defaultParams = { 628 id : null, 629 condition : null, 630 selector : null 631 }; 632 params = shinyjs.getParams(params, defaultParams); 633 634 // it there is no condition, enable/disable based on current state 635 if (params.condition === null) { 636 var $els = _getElements(params); 637 if ($els === null) return; 638 639 $.map($els, function(el) { 640 params.elements = $(el); 641 _isDisabled($(el)) ? shinyjs.enable(params) : shinyjs.disable(params); 642 }); 643 } 644 else if (params.condition) { 645 shinyjs.enable(params); 646 } else { 647 shinyjs.disable(params); 648 } 649 }, 650 651 html : function (params) { 652 var defaultParams = { 653 id : null, 654 html : null, 655 add : false, 656 selector : null 657 }; 658 params = shinyjs.getParams(params, defaultParams); 659 660 var $els = _getElements(params); 661 if ($els === null) return; 662 663 $.each($els, function(idx, node) { 664 if (params.add) { 665 node.innerHTML += params.html; 666 } else { 667 node.innerHTML = params.html; 668 } 669 }); 670 }, 671 672 alert : function (params) { 673 var defaultParams = { 674 text : null 675 } 676 params = shinyjs.getParams(params, defaultParams); 677 678 if (typeof params.text == "object") { 679 alert(JSON.stringify(params.text, null, 4)); 680 } else { 681 alert(params.text); 682 } 683 684 }, 685 686 logjs : function (params) { 687 var defaultParams = { 688 text : null 689 } 690 params = shinyjs.getParams(params, defaultParams); 691 692 console.log(params.text); 693 }, 694 695 runjs : function (params) { 696 var defaultParams = { 697 code : null 698 } 699 params = shinyjs.getParams(params, defaultParams); 700 701 eval(params.code); 702 }, 703 704 // onevent function is more complicated than the rest of the shinyjs functions 705 // we attach an event handler (onclick/onkeydown/onmouseup/etc) to an element 706 // and when it happens we call Shiny 707 onevent : function (params) { 708 var defaultParams = { 709 event : null, 710 id : null, 711 shinyInputId : null, 712 add : false, 713 customProps : [] 714 } 715 params = shinyjs.getParams(params, defaultParams); 716 717 var el = _jqid(params.id); 718 719 // if element does not exist in the document, save the information so that 720 // if the element is created dynamically later, we can add the handlers 721 if (el.length == 0) { 722 if (!(params.id in _oneventData)) { 723 _oneventData[params.id] = {}; 724 } 725 var elementData = _oneventData[params.id]; 726 if (!(params.event in elementData) || !params.add) { 727 elementData[params.event] = []; 728 } 729 elementData[params.event].push({ 730 "shinyInputId" : params.shinyInputId, 731 "customProps" : params.customProps 732 }); 733 } 734 // if the element does exist, add the event handler 735 else { 736 _oneventAttach(params); 737 } 738 }, 739 740 removeEvent : function (params) { 741 var defaultParams = { 742 event : null, 743 id : null 744 } 745 params = shinyjs.getParams(params, defaultParams); 746 747 var el = _jqid(params.id); 748 749 var eventInstance = params.event; 750 var eventType = eventInstance.replace(/(.*)-/,""); 751 var removeAll = (eventInstance == eventType); 752 753 // If the element is not yet in the document, remove it from the onevent queue 754 if (el.length == 0) { 755 if (params.id in _oneventData) { 756 var elementData = _oneventData[params.id]; 757 if (removeAll) { 758 delete elementData[eventType]; 759 } else { 760 if (eventType in elementData) { 761 var eventDatas = elementData[eventType]; 762 var newEvents = eventDatas.filter(function(data) { 763 return data.shinyInputId != eventInstance; 764 }); 765 if (newEvents.length == 0) { 766 delete elementData[eventType]; 767 } else { 768 elementData[eventType] = newEvents; 769 } 770 } 771 } 772 } 773 } else { 774 var attrName = "data-shinyjs-" + eventType; 775 if (el[0].hasAttribute(attrName)) { 776 if (removeAll) { 777 var attrValue = {}; 778 } else { 779 var attrValue = JSON.parse(el.attr(attrName)); 780 delete attrValue[eventInstance] 781 } 782 el.attr(attrName, JSON.stringify(attrValue)); 783 } 784 } 785 }, 786 787 // the reset function is also complicated because we need R to tell us 788 // what input element or form to reset, then the javascript needs to 789 // figure out the correct type and initial value for each input and pass 790 // that info back to R so that R can call the correct shiny::updateFooInput() 791 reset : function(params) { 792 var defaultParams = { 793 id : null, 794 shinyInputId : null 795 } 796 params = shinyjs.getParams(params, defaultParams); 797 798 if (params.id === "") { 799 var el = $("body"); 800 } else { 801 var el = _jqid(params.id); 802 } 803 804 // find all the resettable input elements 805 var resettables; 806 if (el.hasClass("shinyjs-resettable")) { 807 resettables = el; 808 } else { 809 resettables = el.find(".shinyjs-resettable"); 810 } 811 812 // go through each input and record its id, type, and initial value 813 var messages = Object(); 814 for (var i = 0; i < resettables.length; i++) { 815 var resettable = $(resettables[i]); 816 var type = resettable.attr('data-shinyjs-resettable-type'); 817 var value = resettable.attr('data-shinyjs-resettable-value'); 818 var id = resettable.attr('data-shinyjs-resettable-id'); 819 if (id !== undefined) { 820 // file inputs need to be reset manually since shiny doesn't have an 821 // update function for them 822 if (type == "File") { 823 _jqid(id).val(''); 824 _jqid(id + "_progress").css("visibility", "hidden"); 825 _jqid(id + "_progress").find(".progress-bar").css("width", "0"); 826 _jqid(id).closest(".input-group").find("input[type='text']").val(''); 827 } else { 828 messages[id] = { 'type' : type, 'value' : value }; 829 } 830 } 831 } 832 833 // send a message back to R with the info for each input element 834 Shiny.onInputChange(params.shinyInputId, messages); 835 }, 836 837 // run an R function after an asynchronous delay 838 delay : function(params) { 839 var defaultParams = { 840 ms : null, 841 shinyInputId : null 842 } 843 params = shinyjs.getParams(params, defaultParams); 844 845 // send a message back to R when the delay is up 846 setTimeout(function() { 847 Shiny.onInputChange(params.shinyInputId, params.ms); 848 }, params.ms); 849 }, 850 851 // click on a button 852 click : function(params) { 853 var defaultParams = { 854 id : null 855 }; 856 params = shinyjs.getParams(params, defaultParams); 857 858 var $el = _getElements(params); 859 if ($el === null) return; 860 $el[0].click(); 861 }, 862 863 // refresh the page 864 refresh : function(params) { 865 var defaultParams = { 866 id : null 867 }; 868 params = shinyjs.getParams(params, defaultParams); 869 870 window.location.reload(false); 871 } 872 }; 873}(); 874 875// Initialize shinyjs on the JS side 876$(function() { shinyjs.initShinyjs(); }); 877 878// ShinySenderQueue code taken from Joe Cheng 879// https://github.com/rstudio/shiny/issues/1476 880function ShinySenderQueue() { 881 this.readyToSend = true; 882 this.queue = []; 883 this.timer = null; 884} 885ShinySenderQueue.prototype.send = function(name, value) { 886 var self = this; 887 function go() { 888 self.timer = null; 889 if (self.queue.length) { 890 var msg = self.queue.shift(); 891 if (typeof Shiny === 'object' && typeof Shiny.compareVersion === 'function' && 892 Shiny.compareVersion(Shiny.version, '>=', '1.1.0')) { 893 Shiny.setInputValue(msg.name, msg.value, {priority: "event"}); 894 } else { 895 Shiny.onInputChange(msg.name, msg.value); 896 } 897 self.timer = setTimeout(go, 0); 898 } else { 899 self.readyToSend = true; 900 } 901 } 902 if (this.readyToSend) { 903 this.readyToSend = false; 904 if (typeof Shiny === 'object' && typeof Shiny.compareVersion === 'function' && 905 Shiny.compareVersion(Shiny.version, '>=', '1.1.0')) { 906 Shiny.setInputValue(name, value, {priority: "event"}); 907 } else { 908 Shiny.onInputChange(name, value); 909 } 910 this.timer = setTimeout(go, 0); 911 } else { 912 this.queue.push({name: name, value: value}); 913 if (!this.timer) { 914 this.timer = setTimeout(go, 0); 915 } 916 } 917};
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.