Moving a child object into root before it's original parent inside a json array

Viewed 234

I have the following JSON array

{"type":"doc","version":1,"content":[{"type":"paragraph","content":[{"type":"image","attrs":{"src":"cid:avatar_de332fbebe0906c451c8859294d1553d"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~malhajj?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4"}}]},{"type":"text","text":" Mohamad AL HAJJ "},{"type":"text","text":"mentioned","marks":[{"type":"strong"}]},{"type":"text","text":" you on a page"}]},{"type":"paragraph","content":[{"type":"text","text":" ","marks":[{"type":"textColor","attrs":{"color":"#ffffff"}}]},{"type":"text","text":" "},{"type":"image","attrs":{"src":"cid:mention-icon","alt":"mention icon","title":"mention icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]},{"type":"text","text":" "},{"type":"text","text":"Bassem 1-1 2022-07-28","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]}]},{"type":"paragraph","content":[{"type":"text","text":"···"}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]}]}]},{"type":"paragraph","content":[{"type":"text","text":"Release 3.0.7 is ready"}]},{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[]}]}]},{"type":"paragraph","content":[{"type":"hardBreak"},{"type":"text","text":" Research about supporting React in windows app"}]},{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]},{"type":"paragraph","content":[{"type":"hardBreak"},{"type":"text","text":" "},{"type":"hardBreak"},{"type":"text","text":" Test server changes done by Ahmad"}]},{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]},{"type":"paragraph","content":[{"type":"hardBreak"}]},{"type":"paragraph","content":[{"type":"image","attrs":{"src":"cid:com.atlassian.confluence.plugins.confluence-email-resources_view-page-email-adg-footer-item_icon","alt":"View page Icon","title":"View page Icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]},{"type":"text","text":" "},{"type":"text","text":"View page","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]},{"type":"text","text":" • "},{"type":"image","attrs":{"src":"cid:com.atlassian.confluence.plugins.confluence-email-resources_add-comment-to-content-email-adg-footer-item_icon","alt":"Add comment Icon","title":"Add comment Icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?showComments=true&showCommentArea=true&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=comment#addcomment"}}]},{"type":"text","text":" "},{"type":"text","text":"Add comment","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?showComments=true&showCommentArea=true&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=comment#addcomment"}}]},{"type":"text","text":" • "},{"type":"image","attrs":{"src":"cid:com.atlassian.confluence.plugins.confluence-like_view-email-adg-content-item_icon","alt":"Like Icon","title":"Like Icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/plugins/likes/like.action?contentId=26543947&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=like&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4c3JmOjMwYmFmMWJhN2NjZGRkZDMwMTdmY2ExMzAwN2UwMGM0IiwicXNoIjoiODEwNWNmMmVlZjcwMGQ1MjVmYjUyODkzMjFmYTMzZGQyNDNmNDNmM2M2MWY1YmU5NzU3YjhjMWVmZmIxZTk1MSIsImlzcyI6ImNvbmZsdWVuY2Vfbm90aWZpY2F0aW9uc0JFOFUtTDNMWi1USzFPLVBGM00iLCJleHAiOjE2NTk3NzM1NTYsImlhdCI6MTY1OTE2ODc1Nn0.R4yPR6SKdUg5mc8fwgdGUa7BeWOdN_2LXDZbAKC5A-o"}}]},{"type":"text","text":" "},{"type":"text","text":"Like","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/plugins/likes/like.action?contentId=26543947&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=like&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4c3JmOjMwYmFmMWJhN2NjZGRkZDMwMTdmY2ExMzAwN2UwMGM0IiwicXNoIjoiODEwNWNmMmVlZjcwMGQ1MjVmYjUyODkzMjFmYTMzZGQyNDNmNDNmM2M2MWY1YmU5NzU3YjhjMWVmZmIxZTk1MSIsImlzcyI6ImNvbmZsdWVuY2Vfbm90aWZpY2F0aW9uc0JFOFUtTDNMWi1USzFPLVBGM00iLCJleHAiOjE2NTk3NzM1NTYsImlhdCI6MTY1OTE2ODc1Nn0.R4yPR6SKdUg5mc8fwgdGUa7BeWOdN_2LXDZbAKC5A-o"}}]},{"type":"text","text":" "},{"type":"text","text":" ","marks":[{"type":"textColor","attrs":{"color":"#ffffff"}}]}]},{"type":"paragraph","content":[{"type":"text","text":"Manage notifications","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/users/editmyemailsettings.action?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=manage"}}]},{"type":"text","text":" "},{"type":"image","attrs":{"src":"cid:footer-desktop-logo","alt":"Confluence logo big","title":"Confluence logo big"}},{"type":"text","text":" This message was sent by Atlassian Confluence 7.18.1"},{"type":"hardBreak"},{"type":"image","attrs":{"src":"cid:footer-mobile-logo","alt":"","title":""}}]}]}

what I am trying to do is creating a recursive function that locate all the elements with type image and try to move it from inside it's parent and push it as a root element but I am not able to push it right after or before it's original parent.

This is what I did

static recur = (arr, AttachmentsArr, madfdoc, htmlbody) => {
    if (arr && arr.length > 0) {
        arr.forEach(item => {
            try {
                switch (item.type) {
                    case "image":
                        this.handleImages(arr, madfdoc, item, htmlbody, AttachmentsArr)
                        break;
                    case "paragraph":
                        this.handleParaphs(item, htmlbody, AttachmentsArr)
                        break;
                    default:
                        break;
                }
                if (item.content) {
                    this.recur(item.content, AttachmentsArr, madfdoc, htmlbody);
                }
            }
            catch (ex) {
                console.log(ex)
            }
        });
    }

};

static handleImages(arr, madfdoc, item, htmlbody, AttachmentsArr) {
    var imghtmlobj = htmlbody.querySelector(`img[src*='${item.attrs.src}']`);
    let src = item.attrs.src.replace("cid:", "");
    // find the image bloburl to change it                        
    let fnd = AttachmentsArr && AttachmentsArr.length ? AttachmentsArr.find(obj => {
        return obj.ContentId ? obj.ContentId === src : undefined;
    }) : undefined
    var imgw = undefined;
    var imgh = undefined;
    if (imghtmlobj) {
        let img = new Image();
        img.onload = function () {
            imgw = this.width;
            imgh = this.height;
            delete item["attrs"]
            delete item["marks"]
            item.type = "mediaSingle";
            item.content = [];
            item.content.push({
                type: "media",
                attrs: {
                    type: "external",
                    url: fnd ? fnd.preview : src,
                    width: imgw,
                    height: imgh
                }
            })
            const indexOfObject = arr.findIndex(object => {
                return object.type === "mediaSingle";
            });
            **arr.splice(indexOfObject, 1); // here is where i am deleting it from inside it's parent and push it to the root inside `madfdoc` 
            madfdoc.content.push(item);**
        }
        img.src = fnd ? fnd.preview : src;
    }
}

The expected Json would be something like this

{
 "type": "doc",
 "version": 1,
  "content": [
  {
      "type": "image",
      "attrs": {
        "src": "cid:avatar_de332fbebe0906c451c8859294d1553d"
      },
      "marks": [
        {
          "type": "link",
          "attrs": {
            "href": "https://wiki.infosysta.com/display/~malhajj?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4"
          }
        }
      ]
    },
{
  "type": "paragraph",
  "content": [
    
    {
      "type": "text",
      "text": " test"
    },
    {
      "type": "text",
      "text": "mentioned",
      "marks": [
        {
          "type": "strong"
        }
      ]
    },
    {
      "type": "text",
      "text": " you on a page"
    }
  ]
}

 ]

}

2 Answers

If I understood your requirement correctly, this should do it:

class ImagePopper {
  #data;
  #collector = [];

  constructor(data) {
    if (typeof data === "object") {
      this.#data = structuredClone(data);
      this.parseObject(this.#data, []);
      this.#collector.reverse().forEach(({ entry, path }) => {
        this.#data[path[0]].splice(path[1], 0, entry);
      });
    }

    return this.#data || data;
  }

  parseArray = (arr, path) => {
    _.set(
      this.#data,
      path,
      arr.reduce((acc, entry, index) => {
        if (typeof entry === "object") {
          this.parseObject(entry, [...path, index]);
        }
        if (entry?.type === "image") {
          this.#collector.push({ entry, path });
        } else {
          acc.push(entry);
        }

        return acc;
      }, [])
    );
  };

  parseObject = (obj, path) =>
    Object.entries(obj).forEach(
      ([key, value]) =>
        Array.isArray(value) && this.parseArray(value, [...path, key])
    );
}

const json = {"type":"doc","version":1,"content":[{"type":"paragraph","content":[{"type":"image","attrs":{"src":"cid:avatar_de332fbebe0906c451c8859294d1553d"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~malhajj?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4"}}]},{"type":"text","text":" Mohamad AL HAJJ "},{"type":"text","text":"mentioned","marks":[{"type":"strong"}]},{"type":"text","text":" you on a page"}]},{"type":"paragraph","content":[{"type":"text","text":" ","marks":[{"type":"textColor","attrs":{"color":"#ffffff"}}]},{"type":"text","text":" "},{"type":"image","attrs":{"src":"cid:mention-icon","alt":"mention icon","title":"mention icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]},{"type":"text","text":" "},{"type":"text","text":"Bassem 1-1 2022-07-28","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]}]},{"type":"paragraph","content":[{"type":"text","text":"···"}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]}]}]},{"type":"paragraph","content":[{"type":"text","text":"Release 3.0.7 is ready"}]},{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[]}]}]},{"type":"paragraph","content":[{"type":"hardBreak"},{"type":"text","text":" Research about supporting React in windows app"}]},{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]},{"type":"paragraph","content":[{"type":"hardBreak"},{"type":"text","text":" "},{"type":"hardBreak"},{"type":"text","text":" Test server changes done by Ahmad"}]},{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]},{"type":"paragraph","content":[{"type":"hardBreak"}]},{"type":"paragraph","content":[{"type":"image","attrs":{"src":"cid:com.atlassian.confluence.plugins.confluence-email-resources_view-page-email-adg-footer-item_icon","alt":"View page Icon","title":"View page Icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]},{"type":"text","text":" "},{"type":"text","text":"View page","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]},{"type":"text","text":" • "},{"type":"image","attrs":{"src":"cid:com.atlassian.confluence.plugins.confluence-email-resources_add-comment-to-content-email-adg-footer-item_icon","alt":"Add comment Icon","title":"Add comment Icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?showComments=true&showCommentArea=true&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=comment#addcomment"}}]},{"type":"text","text":" "},{"type":"text","text":"Add comment","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?showComments=true&showCommentArea=true&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=comment#addcomment"}}]},{"type":"text","text":" • "},{"type":"image","attrs":{"src":"cid:com.atlassian.confluence.plugins.confluence-like_view-email-adg-content-item_icon","alt":"Like Icon","title":"Like Icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/plugins/likes/like.action?contentId=26543947&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=like&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4c3JmOjMwYmFmMWJhN2NjZGRkZDMwMTdmY2ExMzAwN2UwMGM0IiwicXNoIjoiODEwNWNmMmVlZjcwMGQ1MjVmYjUyODkzMjFmYTMzZGQyNDNmNDNmM2M2MWY1YmU5NzU3YjhjMWVmZmIxZTk1MSIsImlzcyI6ImNvbmZsdWVuY2Vfbm90aWZpY2F0aW9uc0JFOFUtTDNMWi1USzFPLVBGM00iLCJleHAiOjE2NTk3NzM1NTYsImlhdCI6MTY1OTE2ODc1Nn0.R4yPR6SKdUg5mc8fwgdGUa7BeWOdN_2LXDZbAKC5A-o"}}]},{"type":"text","text":" "},{"type":"text","text":"Like","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/plugins/likes/like.action?contentId=26543947&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=like&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4c3JmOjMwYmFmMWJhN2NjZGRkZDMwMTdmY2ExMzAwN2UwMGM0IiwicXNoIjoiODEwNWNmMmVlZjcwMGQ1MjVmYjUyODkzMjFmYTMzZGQyNDNmNDNmM2M2MWY1YmU5NzU3YjhjMWVmZmIxZTk1MSIsImlzcyI6ImNvbmZsdWVuY2Vfbm90aWZpY2F0aW9uc0JFOFUtTDNMWi1USzFPLVBGM00iLCJleHAiOjE2NTk3NzM1NTYsImlhdCI6MTY1OTE2ODc1Nn0.R4yPR6SKdUg5mc8fwgdGUa7BeWOdN_2LXDZbAKC5A-o"}}]},{"type":"text","text":" "},{"type":"text","text":" ","marks":[{"type":"textColor","attrs":{"color":"#ffffff"}}]}]},{"type":"paragraph","content":[{"type":"text","text":"Manage notifications","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/users/editmyemailsettings.action?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=manage"}}]},{"type":"text","text":" "},{"type":"image","attrs":{"src":"cid:footer-desktop-logo","alt":"Confluence logo big","title":"Confluence logo big"}},{"type":"text","text":" This message was sent by Atlassian Confluence 7.18.1"},{"type":"hardBreak"},{"type":"image","attrs":{"src":"cid:footer-mobile-logo","alt":"","title":""}}]}]}

const result = new ImagePopper(json);

// console.log({ before: json, after: result });

before.innerHTML = JSON.stringify(json, null, 2)
after.innerHTML = JSON.stringify(result, null, 2)
@media (min-width: 800px) {
  .side-by-side {
    display: flex;
  }
  .side-by-side > div {
    width: 50%;
  }
  .scroller {
    overflow: auto;
    height: calc(100vh - 84px);
  }
}
pre {
  padding: .5rem;
  background-color: #f5f5f5;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>

<div class="side-by-side">
  <div>
    <h2>Before</h2>
    <div class="scroller">
      <pre id="before"></pre>
    </div>
  </div>
  <div>
    <h2>After</h2>
    <div class="scroller">
      <pre id="after"></pre>
    </div>
  </div>
</div>

I'm traversing the data recursively and collect all images, storing their current path. At each level, I'm deleting the images from their parent (by omission). I used lodash's set for this (it allows passing the path as array, which was quite handy here). 1, 2

Then I'm injecting each image at top level before its root parent, in reverse order. This way I don't need to always inflate the splice index by the number of previously processed images.

Decided to wrap it as a class to keep it from interacting with the outer scope, for cleanness, readability and reusability.

That's about it.


Notes:

1 - If you don't want to use lodash's set, consider using this implementation.
2 - in your project, you shouldn't import all of lodash, as I'm doing here. Only import set:

import { set } from 'lodash-es'
// replace `_.set(` in the class with just `set(`

Focussing on your description, I would build a new json object and add the properties in the order I want them to appear.

Assuming your json data is in the data variable, the following would recursively parse the root content, remove any images it finds and later insert them after the root content element it found them in.

const data = `{"type":"doc","version":1,"content":[{"type":"paragraph","content":[{"type":"image","attrs":{"src":"cid:avatar_de332fbebe0906c451c8859294d1553d"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~malhajj?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4"}}]},{"type":"text","text":" Mohamad AL HAJJ "},{"type":"text","text":"mentioned","marks":[{"type":"strong"}]},{"type":"text","text":" you on a page"}]},{"type":"paragraph","content":[{"type":"text","text":" ","marks":[{"type":"textColor","attrs":{"color":"#ffffff"}}]},{"type":"text","text":" "},{"type":"image","attrs":{"src":"cid:mention-icon","alt":"mention icon","title":"mention icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]},{"type":"text","text":" "},{"type":"text","text":"Bassem 1-1 2022-07-28","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]}]},{"type":"paragraph","content":[{"type":"text","text":"···"}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]}]}]},{"type":"paragraph","content":[{"type":"text","text":"Release 3.0.7 is ready"}]},{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[]}]}]},{"type":"paragraph","content":[{"type":"hardBreak"},{"type":"text","text":" Research about supporting React in windows app"}]},{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]},{"type":"paragraph","content":[{"type":"hardBreak"},{"type":"text","text":" "},{"type":"hardBreak"},{"type":"text","text":" Test server changes done by Ahmad"}]},{"type":"paragraph","content":[{"type":"text","text":"@"},{"type":"text","text":"Bassem Alameddine","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/~balameddine"}}]},{"type":"text","text":" "}]},{"type":"paragraph","content":[{"type":"hardBreak"}]},{"type":"paragraph","content":[{"type":"image","attrs":{"src":"cid:com.atlassian.confluence.plugins.confluence-email-resources_view-page-email-adg-footer-item_icon","alt":"View page Icon","title":"View page Icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]},{"type":"text","text":" "},{"type":"text","text":"View page","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=view"}}]},{"type":"text","text":" • "},{"type":"image","attrs":{"src":"cid:com.atlassian.confluence.plugins.confluence-email-resources_add-comment-to-content-email-adg-footer-item_icon","alt":"Add comment Icon","title":"Add comment Icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?showComments=true&showCommentArea=true&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=comment#addcomment"}}]},{"type":"text","text":" "},{"type":"text","text":"Add comment","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/display/MDT/Bassem+1-1+2022-07-28?showComments=true&showCommentArea=true&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=comment#addcomment"}}]},{"type":"text","text":" • "},{"type":"image","attrs":{"src":"cid:com.atlassian.confluence.plugins.confluence-like_view-email-adg-content-item_icon","alt":"Like Icon","title":"Like Icon"},"marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/plugins/likes/like.action?contentId=26543947&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=like&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4c3JmOjMwYmFmMWJhN2NjZGRkZDMwMTdmY2ExMzAwN2UwMGM0IiwicXNoIjoiODEwNWNmMmVlZjcwMGQ1MjVmYjUyODkzMjFmYTMzZGQyNDNmNDNmM2M2MWY1YmU5NzU3YjhjMWVmZmIxZTk1MSIsImlzcyI6ImNvbmZsdWVuY2Vfbm90aWZpY2F0aW9uc0JFOFUtTDNMWi1USzFPLVBGM00iLCJleHAiOjE2NTk3NzM1NTYsImlhdCI6MTY1OTE2ODc1Nn0.R4yPR6SKdUg5mc8fwgdGUa7BeWOdN_2LXDZbAKC5A-o"}}]},{"type":"text","text":" "},{"type":"text","text":"Like","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/plugins/likes/like.action?contentId=26543947&src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=like&jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4c3JmOjMwYmFmMWJhN2NjZGRkZDMwMTdmY2ExMzAwN2UwMGM0IiwicXNoIjoiODEwNWNmMmVlZjcwMGQ1MjVmYjUyODkzMjFmYTMzZGQyNDNmNDNmM2M2MWY1YmU5NzU3YjhjMWVmZmIxZTk1MSIsImlzcyI6ImNvbmZsdWVuY2Vfbm90aWZpY2F0aW9uc0JFOFUtTDNMWi1USzFPLVBGM00iLCJleHAiOjE2NTk3NzM1NTYsImlhdCI6MTY1OTE2ODc1Nn0.R4yPR6SKdUg5mc8fwgdGUa7BeWOdN_2LXDZbAKC5A-o"}}]},{"type":"text","text":" "},{"type":"text","text":" ","marks":[{"type":"textColor","attrs":{"color":"#ffffff"}}]}]},{"type":"paragraph","content":[{"type":"text","text":"Manage notifications","marks":[{"type":"link","attrs":{"href":"https://wiki.infosysta.com/users/editmyemailsettings.action?src=mail&src.mail.product=confluence-server&src.mail.timestamp=1659168756680&src.mail.notification=com.atlassian.confluence.plugins.confluence-mentions-plugin%3Amention-created-notification&src.mail.recipient=30baf1ba7ccdddd3017fca13007e00c4&src.mail.action=manage"}}]},{"type":"text","text":" "},{"type":"image","attrs":{"src":"cid:footer-desktop-logo","alt":"Confluence logo big","title":"Confluence logo big"}},{"type":"text","text":" This message was sent by Atlassian Confluence 7.18.1"},{"type":"hardBreak"},{"type":"image","attrs":{"src":"cid:footer-mobile-logo","alt":"","title":""}}]}]}`;
const findAndRemoveImagesRecursive = (element) => {
    let images = [];
    if (Array.isArray(element.content)) {
        element.content.forEach((c, i) => {
            if (c.type === 'image') {
                images.push({
                    ...c
                })
                delete element.content[i];
            }
            else {
                images = images.concat(findAndRemoveImagesRecursive(c));
            }
        })
        element.content = element.content.filter(x=>x);
    }
    return images;
}

const newJson = {...data, content: []};


data.content.forEach(e => {
    const images = findAndRemoveImagesRecursive(e);
    newJson.content = newJson.content.concat(images);
    newJson.content.push(e);
});
Related