防止删除Tumblr仪表板上的DOM元素

时间:2015-02-05 07:30:35

标签: javascript google-chrome-extension tumblr

注意:这是my previous one的后续问题。

我决定通过#posts元素中的扩展程序将帖子显示在信息中心上。现在我的问题是 Tumblr自动删除帖子'滚动内容

以下是移除前正常帖子的示例

<li class="post_container" data-pageable="post_110141415125">
    <div class="post post_full ..." [...]>
        <!-- ... -->
    </div>
</li>

同样的帖子,删除后的内容:

<li class="post_container" data-pageable="post_110141415125" style="border-radius: 3px; height: 207px; width: 540px; background-color: rgb(255, 255, 255);">
</li>

由于我的扩展程序将帖子重新定位为 pinterest-like 布局,删除帖子&#39;内容会弄乱整个布局。是否可以阻止Tumblr仪表板删除每个.post中的DOM元素?

修改

我在内容脚本中添加了removeChild方法的注入代码:

function addScript(){
    var script = document.createElement('script');  
    script.id = 'newRemoveChildScript'; ///just to find is faster in the code
    script.src = chrome.extension.getURL("injectedCode.js");
    $($('script')[0]).before(script); ///Script is indeed present, I checked that
}

window.onload = addScript;

接下来我做的是用第二个版本创建injectedCode.js文件,如下所示:

(function (obj, method) {
    function isPost(el) {
        return (/^post_\d+$/.test(el.id) && ~el.className.indexOf('post'));
    }
    obj[method] = (function (obj_method) {
        return function (child) {
            if (isPost(child)) return child;
            return obj_method.apply(this, arguments);
        }
    }(obj[method]));
}(Element.prototype, 'removeChild'));

当我加载Tumblr-Dashboard时,我可以确认head-element中存在Script-element。该文件也正确链接,因为&#39; removeChild&#39;函数被调用一次。似乎在那里删除了一个脚本元素。

从那时起,该函数再也没有被调用过,我可以看到那些空的&#39;再次发帖。

1 个答案:

答案 0 :(得分:13)

劫持Tumblr仪表板行为

免责声明 :完全合法的事情发生在这里,不要惊慌!

你要问的是不是很容易要做的事情,但实际上你可以阻止Tumblr在他们离开视口时滚动时隐藏帖子。更准确地说,一个高级程序员实际上可以操纵任何Tumblr方法使其表现得像他想要的那样,但是,现在,让我们专注于你的问题。

为什么Tumblr会在滚动时删除帖子?

Tumblr删除帖子&#39;使页面更轻的内容,让您继续浏览,而不会因为大量的元素而遇到任何延迟和/或难以滚动。想象一下直接向下滚动一小时:你的破折号会有数千个帖子,你的浏览器可能会因每次滚动时必须移动的东西过多而冻结。

Tumblr如何实现这一目标?

我没有检查和理解Tumblr代码的每一行,因为它全部打包/缩小,并且实际上不可能理解任何方法的单行(除非你在Tumblr,在这种情况下恭喜),但是,基本上,我放了一些DOM breakpoints并且我已经检查了当他们离开视口时删除帖子的代码部分。

简而言之,这就是它的作用:

  1. Tumblr创造了一些自定义和狡猾的&#34;滚动&#34;这些帖子的活动。每当帖子超出视口的距离时,这些事件都会触发

  2. 现在Tumblr会将一些侦听器附加到这些自定义事件上,并且使用li.post_container元素上的 DOM断点,您将能够看到这些侦听器驻留在dashboard.js JavaScript文件中。

    dashboard.js

    更确切地说,删除帖子的代码的确切部分&#39;内容如下:

    function j(t,v) { try{ t.removeChild(v) } catch(u){} }
    

    其中tli.post_containerv是其子级:div#post_[id]

    这部分代码有什么作用?没有什么特别之处:它确实从其父div#post_[id] 中删除li.post_container元素。

  3. 现在Tumblr必须设置已删除帖子的容器的样式,以便保持#posts元素的高度,该元素包含所有帖子,否则删除帖子的内容会使页面向下滚动H像素,其中H是已移除的帖子的高度。

    此更改发生在另一个脚本index.js内,我甚至没有仔细查看它,因为它只是无法阅读:

    index.js

    顺便说一下,这个脚本并不重要,因为我们可以使用简单的CSS来防止样式更改

  4. 现在帖子的内容已被删除&#34;,它看起来像这样:

    removed post

    *为了清楚起见:我添加了文字和墓碑,你实际上并没有看到它们lol

  5. 所以,最后,当一个帖子离开视口时,会发生以下变化:

    <li class="post_container" [...]>
        <div id="post_[id]" class="post post_full ..." [...]>
            <!-- post body... -->
        </div>
    </li>
    

    到此:

    <li class="post_container" [...] style="border-radius: 3px; height: Hpx; width: Wpx; background-color: rgb(255, 255, 255);">
    </li>
    

    阻止Tumblr代码删除帖子(确实有些小黑客)

    现在我们知道Tumblr在滚动仪表板时的行为,我们可以阻止它删除帖子并将它们设置为,看起来像带有圆形边框的空白色死区。

    首先是

    风格

    在关心防止移除柱子之前,我们应该将它们设计成不具有固定高度和宽度的样式,覆盖Tumblr离开视口时应用于它们的样式。

    我们可以在页面中注入一些简单的CSS,制定规则!important以防止内联样式覆盖它们。这是我们添加的CSS:

    li.post_container {
        height: auto !important;
        width: 540px !important;
        /* 540px is the default width
         * change it to any amount that applies to your layout 
         */
    }
    

    或者,使用JavaScript,我们可以:

    var s = document.createElement('style');
    s.textContent = 'li.post_container{height:auto!important;width:540px!important;}';
    document.head.appendChild(s);
    

    防止移除后:轻松(愚蠢)

    如果我们不想浪费时间考虑一个好的解决方案,我们可以实现最简单的解决方案,并且,在几行代码中我们可以:

    1. 复制removeChild的{​​{1}}方法,并将其称为Element.prototype

    2. 将原来的替换为&#34;过滤&#34;拨打电话,决定删除除帖子以外的任何内容。

    3. 这是解决问题的简单而愚蠢的代码:

      _removeChild

      没有注释的代码长度:5行

      您可以检查多个条件:例如,您可以检查帖子是否包含类Element.prototype._removeChild = Element.prototype.removeChild Element.prototype.removeChild = function(child) { // Check if the element is a post (e.g. the id looks like "post_123456...") if (/^post_\d+$/.test(child.id)) { // If so, stop here by returning the post // This will make Tumblr believe the post has been removed return child; } // Otherwise the element isn't a post, so we can remove it return Element.prototype._removeChild.apply(this, arguments); } post,或者post_full是否有类parentElement,等等......它取决于你。

      防止移除后:聪明(更难)的方式

      完成此操作的更优雅,更狡猾的方法是&#34;编辑&#34;原始的post_container方法,使用了一些闭包和更复杂的逻辑。这就是我们要做的事情:

      1. 创建一个闭包,我们重新定义Element.prototype.removeChild方法,添加&#34;过滤器&#34;它的帖子。

      2. 在此闭包中,我们将定义我们可以调用Element.prototype.removeChild的自定义过滤器函数,以过滤要删除的元素

        < / LI>
      3. 使用第二个闭包,我们将isPost()方法重新定义为:

        1. 使用之前创建的过滤器功能Element.prototype.removeChild检查要移除的元素

        2. 如果要删除的元素是帖子,则停止此处,不要将其删除。

        3. 否则继续并使用isPost()方法调用原始Element.prototype.removeChild方法。

      4. 这可能看起来很难,但代码并不难理解,我通过评论来实现它以使其更易于理解,这里是:

        .apply

        没有注释的代码长度:11行

        在页面中注入脚本

        由于内容脚本在隐藏的,不同的(function (obj, method) { // This is all wrapped inside a closure // to make the new removeChild method remember the isPost function // and maintain all the work invisible to the rest of the code in the page function isPost(el) { // Check if the element is a post // This will return true if el is a post, otherwise false return (/^post_\d+$/.test(el.id) && ~el.className.indexOf('post')); } // Edit the Element.prototype.removeChild assigning to it our own function obj[method] = (function (obj_method) { return function (child) { // This is the function that will be assigned to removeChild // It is wrapped in a closure to make the check before removing the element // Check if the element that is going to be removed is a post if (isPost(child)) return child; // If so, stop here by returning the post // This will make Tumblr believe the post has been removed // Otherwise continue and remove it return obj_method.apply(this, arguments); } }(obj[method])); }(Element.prototype, 'removeChild')); 对象中工作,因此内容脚本代码无法与页面代码交互,您可以使用。我必须从您的内容脚本直接在页面中注入代码。为此,您需要创建一个window元素并将其插入页面的<script>。您可以将要注入的代码存储在新脚本中(让我们将其称为<head>)并使用injectedCode.js获取要在chrome.runtime.getURL src中使用的绝对URL。

        重要:您需要将<script>文件添加到injectedCode.js中的"web_accessible_resources" field,以便可以从Tumblr访问该文件,就像这样:

        manifest.json

        然后,您可以创建一个"web_accessible_resources": ["/injectedCode.js"] 设置<script> .src,如下所示:

        injectedCode.js

        最终注释

        这些只是实现目标的两种方法:防止Tumblr在滚动时隐藏帖子。显然还有很多其他方法可以做到这一点,例如使用MutationObserver来检查子树修改,删除所有帖子并使用新的个人事件和方法创建一个新容器来模拟Tumblr,插入Tumblr代码并直接编辑它(几乎不可能,也不太合法),等等。

        我还想强调一下这样一个事实:这只是一个问题的答案我不负责错误地使用这些操作会损害您的分机用户