<commit_before>// The function below is executed in the context of the inspected page.
var page_getProperties = function() {
  try {
    function addModelProperties(key, model, useLongName) {
      for (var property in model.__observers__) {
        var observer = model.__observers__[property];
        var propertyName = observer.propertyName;
        var currentValue = observer.getValue ? observer.getValue() : observer.currentValue;
        var getType = {};
        var isFunction = (property && getType.toString.call(property) === '[object Function]');
        if (!isFunction && propertyName !== undefined) {
          props.push({
            'name': useLongName ? key + "." + propertyName : propertyName,
            'value': currentValue
          });
        }
      }
    }

    var data = window.jQuery && $0 ? jQuery.data($0) : {};
    var selectedNode = $0;
    var aureliaNode = selectedNode;

    // go up the structure until an element affected by aurelia is found
    while (aureliaNode !== null && aureliaNode !== undefined && aureliaNode.au === undefined) {
      aureliaNode = aureliaNode.parentNode;
    }

    if (!aureliaNode) {
      return false;
    }

    var props = [];

    Object.keys(aureliaNode.au).forEach(function(key) {
      var model = aureliaNode.au[key].model || aureliaNode.au[key].viewModel; // compatibility with aurelia 0.17 and 0.18
      if (model && key !== 'controller') {
        var useLongName = aureliaNode.au['controller'] === undefined || $0 !== aureliaNode;
        addModelProperties(key, model, useLongName);
      }
    });

    if (props.length !== 0) {
      var copy = {__proto__: null};

      props.forEach(function (prop) {
        copy[prop.name] = prop.value;
      });

      return copy;
    }

    return null;
  } catch (e) {
    console.log('Aurelia Properties plug-in error:', e);
  }
};

chrome.devtools.panels.elements.createSidebarPane(
  "Aurelia",
  function(sidebar) {
    function updateElementProperties() {
      sidebar.setExpression("(" + page_getProperties.toString() + ")()");
    }

    updateElementProperties();

    chrome.devtools.panels.elements.onSelectionChanged.addListener(updateElementProperties);
  }
);<commit_msg>feat(context-debugger): display binding context for any node<commit_after>

// The function below is executed in the context of the inspected page.
var page_getProperties = function() {
  try {
    function debugObject(obj) {
      var noProto = Object.create(null);
      
      Object.keys(obj || {}).forEach(function(x) {
        if (x.startsWith('_')) {
          return;
        }

        noProto[x] = obj[x];
      });

      return noProto;
    }

    function controllerDebugObject(controller) {
      let controllerDebugger = debugObject({
        Controller: controller,
        'View-Model': controller.viewModel
      });

      if (controller.view) {
        controllerDebugger.View = controller.view;
      }

      return controllerDebugger;
    }

    function _getRepeaterContext(node) {
      var current = node.nextSibling;

      while(current) {
        if (current.nodeType === 8 && current.viewSlot) {
          var children = current.viewSlot.children;

          for (var i = 0, ii = children.length; i < ii; ++i) {
            var view = children[i];
            var currentChild = view.firstChild
            var lastChild = view.lastChild;
            var nextChild;

            while (currentChild) {
              nextChild = currentChild.nextSibling;
              
              if (currentChild === node) {
                return view.bindingContext;
              }

              if (currentChild === lastChild) {
                break;
              }

              currentChild = nextChild;
            }
          }
        }

        current = current.nextSibling;
      }

      return null;
    }

    function _getBindingContext(node) {
      if (!node) {
        return null;
      }

      if (node.aurelia) {
        return node.aurelia.root.viewModel;
      } else if (node.au) {
        var au = node.au;

        if (au.controller) { //custom element
          var controller = au.controller;
          var tagName = node.tagName ? node.tagName.toLowerCase() : null;
          var repeaterContext;

          if (tagName === 'router-view') {
            return controller.viewModel.view.controller.viewModel;
          } else if (tagName === 'compose') {
            return controller.viewModel.currentViewModel;
          } else if (controller['with']) {
            return controller['with'].viewModel.value;
          } else if (repeaterContext = _getRepeaterContext(node)) {
            return repeaterContext;
          } else {

          }
        }
      }

      return _getBindingContext(node.parentNode);
    }

    function getBindingContext(node) {
      var repeaterContext;

      if (repeaterContext = _getRepeaterContext(node)) {
        return repeaterContext;
      }

      return _getBindingContext(node.parentNode);
    }

    var selectedNode = $0;
    var inspector = debugObject();

    if (selectedNode.au) {
      var au = selectedNode.au;

      if (au.controller) {
        inspector['Custom Element'] = controllerDebugObject(au.controller);
      }

      var tagName = selectedNode.tagName ? selectedNode.tagName.toLowerCase() : null;
      var customAttributes = Object.keys(au).filter(function(key) {
        return key !== 'controller' && key !== tagName;
      });

      if (customAttributes.length) {
        var customAttributesDebug = inspector['Custom Attributes'] = debugObject();
        customAttributes.forEach(function(x) { customAttributesDebug[x] = controllerDebugObject(au[x]); });
      }
    }

    inspector['Binding Context'] = getBindingContext(selectedNode);

    return inspector;
  } catch (e) {
    console.log('Aurelia Properties plug-in error:', e);
  }
};

chrome.devtools.panels.elements.createSidebarPane(
  "Aurelia",
  function(sidebar) {
    function updateElementProperties() {
      sidebar.setExpression("(" + page_getProperties.toString() + ")()");
    }

    updateElementProperties();

    chrome.devtools.panels.elements.onSelectionChanged.addListener(updateElementProperties);
  }
);
{'fraction_non_alphanumeric': 0.11845065895210544, 'fraction_numerical': 0.0022500803600128574, 'mean_word_length': 2.3421052631578947, 'pattern_counts': {'":': 0, '<': 4, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6246669', 'n_tokens_mistral': 1766, 'n_tokens_neox': 1719, 'n_words': 380}