[
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 SimGus\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<img width=\"400\" src=\"https://lh3.googleusercontent.com/_oj_6Y4K4cjpguig23UpstgNdLh6qUvWfcS3LBE73U6p6f8FRr_QuqTIEWmGzq5MpRevAwzF=s1280-h800-e365-rw\"></img>\n\n# iBookmark\nChrome extension for manage bookmarks 一款简单好用的 Chrome 书签管理插件，项目工程非常简单，可供学习参考。\n\n下载地址：https://chrome.google.com/webstore/detail/ibookmark/fnfchnalfnjbjbfeccpophocngdgapad\n\nWiki文档: https://github.com/0326/iBookmark/wiki\n\n## 快速上手\n先clone项目启动watch：\n```shell\ngit clone git@github.com:0326/iBookmark.git\ncd iBookmark\n# install devDependencies\nnpm i \n# start watch\ngulp   \n```\n然后chrome://extensions/ => 加载已解压 扩展程序 => 加载iBookmark文件夹：\n\n注意插件ID信息，浏览器访问：\nchrome-extension://{{插件ID}}/popup/popup.html\n\n编码完成后把项目打包成zip即可上传应用市场。\n\n\n\n## 已完成功能\n- 所有书签分组展示\n- 在当前分组新增书签\n- 修改已有书签信息\n- 删除书签\n- 搜索书签功能\n- 统计书签使用频率，新增常用书签一栏\n- 支持 manifest.json V3\n\n## 待完成功能\n- 新增书签类别\n- 修改书签类别名称\n- 删除某个书签分类\n- 支持书签拖拽，以及移动到其他分类\n- 支持历史记录\n- 支持插件配置功能，可配置主题，配置是否隐藏某些分类下的书签\n\n## 协议\nMIT.\n\n## 更新日志\n0.0.4版本： 支持 manifest V3 协议\n0.0.2版本： 新增配置功能，是否在每个分类下展示添加网址链接按钮"
  },
  {
    "path": "_locales/en/messages.json",
    "content": "{\n  \"appName\": { \"message\": \"iBookmark\" },\n  \"appDesc\": { \"message\": \"the best bookmark manager in Chrome\" },\n  \"extErrTitle\": { \"message\": \"Title Required\" },\n  \"extErrUrl\": { \"message\": \"Url Format Error<br>Please Start With 'http://' or 'https://'\" },\n  \"extBtnCancel\": { \"message\": \"Cancel\" },\n  \"extBtnDelete\": { \"message\": \"Delete\" },\n  \"extBtnUpdate\": { \"message\": \"Update\" },\n  \"extBtnSubmit\": { \"message\": \"Submit\" },\n  \"extTitleSearchResult\": { \"message\": \"Search Result\" },\n  \"extTxtNewSite\": { \"message\": \"Add New Site\" },\n  \"extTitleNewest\": { \"message\": \"The Newest\" },\n  \"extTitleViews\": { \"message\": \"The Most Views\" }\n}"
  },
  {
    "path": "_locales/en_US/messages.json",
    "content": "{\n  \"appName\": { \"message\": \"iBookmark\" },\n  \"appDesc\": { \"message\": \"the best bookmark manager in Chrome\" },\n  \"extErrTitle\": { \"message\": \"Title Required\" },\n  \"extErrUrl\": { \"message\": \"Url Format Error<br>Please Start With 'http://' or 'https://'\" },\n  \"extBtnCancel\": { \"message\": \"Cancel\" },\n  \"extBtnDelete\": { \"message\": \"Delete\" },\n  \"extBtnUpdate\": { \"message\": \"Update\" },\n  \"extBtnSubmit\": { \"message\": \"Submit\" },\n  \"extTitleSearchResult\": { \"message\": \"Search Result\" },\n  \"extTxtNewSite\": { \"message\": \"Add New Site\" },\n  \"extTitleNewest\": { \"message\": \"The Newest\" },\n  \"extTitleViews\": { \"message\": \"The Most Views\" }\n}"
  },
  {
    "path": "_locales/ja/messages.json",
    "content": "{\n  \"appName\": { \"message\": \"iBookmark\" },\n  \"appDesc\": { \"message\": \"Chromeで最高のブックマークマネージャー\" },\n  \"extErrTitle\": { \"message\": \"タイトルを入力してください\" },\n  \"extErrUrl\": { \"message\": \"URL形式エラー<br>「http://」または「https://」で始めてください\" },\n  \"extBtnCancel\": { \"message\": \"キャンセル\" },\n  \"extBtnDelete\": { \"message\": \"削除\" },\n  \"extBtnUpdate\": { \"message\": \"更新\" },\n  \"extBtnSubmit\": { \"message\": \"送信\" },\n  \"extTitleSearchResult\": { \"message\": \"検索結果\" },\n  \"extTxtNewSite\": { \"message\": \"新しいサイトを追加\" },\n  \"extTitleNewest\": { \"message\": \"最新の追加\" },\n  \"extTitleViews\": { \"message\": \"最も閲覧された\" }\n}"
  },
  {
    "path": "_locales/ko/messages.json",
    "content": "{\n  \"appName\": { \"message\": \"iBookmark\" },\n  \"appDesc\": { \"message\": \"Chrome에서 최고의 북마크 관리자\" },\n  \"extErrTitle\": { \"message\": \"제목을 입력하세요\" },\n  \"extErrUrl\": { \"message\": \"URL 형식 오류<br>'http://' 또는 'https://'로 시작하세요\" },\n  \"extBtnCancel\": { \"message\": \"취소\" },\n  \"extBtnDelete\": { \"message\": \"삭제\" },\n  \"extBtnUpdate\": { \"message\": \"수정\" },\n  \"extBtnSubmit\": { \"message\": \"제출\" },\n  \"extTitleSearchResult\": { \"message\": \"검색 결과\" },\n  \"extTxtNewSite\": { \"message\": \"새 사이트 추가\" },\n  \"extTitleNewest\": { \"message\": \"최신 추가\" },\n  \"extTitleViews\": { \"message\": \"가장 많이 본\" }\n}"
  },
  {
    "path": "_locales/zh_CN/messages.json",
    "content": "{\n  \"appName\": {\n    \"message\": \"iBookmark 收藏夹\"\n  },\n  \"appDesc\": {\n    \"message\": \"做最好用的Chrome收藏夹\"\n  },\n  \"extErrTitle\": {\n    \"message\":\"请输入标题\"\n  },\n  \"extErrUrl\": {\n    \"message\":\"地址格式错误<br>请以http://或者https://开头\"\n  },\n  \"extBtnCancel\": {\n    \"message\":\"取消\"\n  },\n  \"extBtnDelete\": {\n    \"message\":\"删除\"\n  },\n  \"extBtnUpdate\": {\n    \"message\":\"修改\"\n  },\n  \"extBtnSubmit\": {\n    \"message\":\"提交\"\n  },\n  \"extTitleSearchResult\": {\n    \"message\":\"搜索结果\"\n  },\n  \"extTxtNewSite\": {\n    \"message\":\"添加新网址\"\n  },\n  \"extTitleNewest\": {\n    \"message\":\"最新添加\"\n  },\n  \"extTitleViews\": {\n    \"message\":\"最常访问\"\n  }\n}"
  },
  {
    "path": "_locales/zh_TW/messages.json",
    "content": "{\n  \"appName\": { \"message\": \"iBookmark 收藏夾\" },\n  \"appDesc\": { \"message\": \"做最好用的Chrome收藏夾\" },\n  \"extErrTitle\": { \"message\": \"請輸入標題\" },\n  \"extErrUrl\": { \"message\": \"地址格式錯誤<br>請以http://或https://開頭\" },\n  \"extBtnCancel\": { \"message\": \"取消\" },\n  \"extBtnDelete\": { \"message\": \"刪除\" },\n  \"extBtnUpdate\": { \"message\": \"修改\" },\n  \"extBtnSubmit\": { \"message\": \"提交\" },\n  \"extTitleSearchResult\": { \"message\": \"搜尋結果\" },\n  \"extTxtNewSite\": { \"message\": \"新增網址\" },\n  \"extTitleNewest\": { \"message\": \"最新新增\" },\n  \"extTitleViews\": { \"message\": \"最常訪問\" }\n}"
  },
  {
    "path": "foreground.js",
    "content": "// This script gets injected into any opened page\n// whose URL matches the pattern defined in the manifest\n// (see \"content_script\" key).\n// Several foreground scripts can be declared\n// and injected into the same or different pages.\n\nconsole.log(\"This prints to the console of the page (injected only if the page url matched)\")\n"
  },
  {
    "path": "manifest.json",
    "content": "{\n    \"manifest_version\": 3,\n    \"name\": \"__MSG_appName__\",\n    \"description\": \"__MSG_appDesc__\",\n    \"default_locale\": \"en\",\n    \"version\": \"0.0.4\",\n    \"icons\": {\n        \"16\": \"img/icon16.png\",\n        \"48\": \"img/icon48.png\",\n        \"128\": \"img/icon128.png\"\n    },\n    \"options_page\": \"settings/settings.html\",\n    \"action\": {\n        \"default_title\": \"iBookmark 收藏夹\",\n        \"default_popup\": \"popup/popup.html\"\n    },\n    \"permissions\": [\n        \"bookmarks\",\n        \"favicon\",\n        \"storage\"\n    ],\n    \"host_permissions\": [\n        \"*://*/*\"\n    ],\n    \"web_accessible_resources\": [\n    {\n      \"resources\": [\"_favicon/*\"],\n      \"matches\": [\"<all_urls>\"],\n      \"extension_ids\": [\"*\"]\n    }\n  ],\n    \"background\": {\n        \"service_worker\": \"service-worker.js\"\n    },\n    \"content_scripts\": [{\n        \"js\": [\"foreground.js\"],\n        \"matches\": [\"https://github.com/*\"]\n    }]\n}\n"
  },
  {
    "path": "popup/popup.css",
    "content": "html, body {\n\t width: 800px;\n\t height: 600px;\n\t margin: 0;\n\t padding: 0;\n\t font-family: STHeiti, '微软雅黑', Arial, sans-serif;\n}\n .clearfix:after {\n\t content: \".\";\n\t display: block;\n\t height: 0;\n\t clear: both;\n\t visibility: hidden;\n}\n .show {\n\t display: block !important;\n}\n .icon {\n\t display: block;\n\t position: absolute;\n\t width: 16px;\n\t height: 16px;\n\t background-repeat: no-repeat;\n}\n .icon-search {\n\t left: 2px;\n\t top: 7px;\n\t background-image: url('../img/icon-search16.png');\n}\n .icon-close {\n\t right: 2px;\n\t top: 7px;\n\t background-image: url('../img/icon-close16.png');\n}\n .fix-header {\n\t position: fixed;\n\t top: 0;\n\t width: 100%;\n\t background: rgba(255,255,255,0.9);\n\t box-shadow: 0 1px 4px #ccc;\n\t z-index: 100;\n}\n .fix-header ul {\n\t margin: 0;\n\t padding: 0;\n\t height: 30px;\n\t line-height: 30px;\n}\n .fix-header li {\n\t float: left;\n\t width: 120px;\n\t list-style: none;\n\t text-align: center;\n\t cursor: pointer;\n}\n .fix-header li:hover {\n\t background: #f2f7f2;\n}\n .fix-header .search-bar {\n\t width: 240px;\n\t margin: 0 5px;\n\t position: relative;\n}\n .fix-header #J_SearchBookmark {\n\t width: 100%;\n\t height: 26px;\n\t padding-left: 20px;\n\t outline: none;\n\t border: none;\n\t background: transparent;\n\t border-bottom: 1px solid #0d9572;\n}\n #J_BookmarkHot, #J_BookmarkSearchList {\n\t margin-top: 40px;\n}\n .bookmark-ctr {\n\t margin: 5px;\n}\n .bookmark-ctr h2 {\n\t position: relative;\n\t padding: 0 0 5px 10px;\n\t margin-bottom: 5px;\n\t height: 20px;\n\t font-size: 16px;\n\t line-height: 20px;\n\t color: #666;\n\t border-bottom: 1px dashed #999;\n}\n .bookmark-ctr h2::after {\n\t display: block;\n\t content: ' ';\n\t position: absolute;\n\t left: 0;\n\t top: 0;\n\t width: 5px;\n\t height: 20px;\n\t background: #0d9572;\n}\n .bookmark-ctr ul {\n\t padding: 0;\n}\n .bookmark-ctr li {\n\t position: relative;\n\t float: left;\n\t width: 170px;\n\t height: 24px;\n\t padding-left: 22px;\n\t margin: 0 5px 5px 0;\n\t font-size: 14px;\n\t line-height: 24px;\n\t cursor: pointer;\n\t text-overflow: ellipsis;\n\t white-space: nowrap;\n\t overflow: hidden;\n}\n .bookmark-ctr li:hover {\n\t background-color: #f2f7f2;\n\t text-decoration: underline;\n}\n .bookmark-ctr a, .bookmark-ctr a:active, .bookmark-ctr a:visited {\n\t text-decoration: none;\n\t color: #0d9572;\n\t outline: none;\n}\n .bookmark-ctr a:hover {\n\t opacity: .5;\n}\n .bookmark-ctr i {\n\t position: absolute;\n\t display: block;\n\t left: 4px;\n\t top: 4px;\n\t height: 16px;\n\t width: 16px;\n\t background-repeat: no-repeat;\n\t background-size: contain;\n}\n .add-bookmark-pop {\n\t display: none;\n\t position: fixed;\n\t left: 0;\n\t top: 0;\n\t width: 100%;\n\t height: 100%;\n\t background: rgba(0,0,0,0.5);\n\t z-index: 1000;\n}\n .add-bookmark-pop .wrapper {\n\t margin: 100px auto;\n\t width: 240px;\n}\n .add-bookmark-pop input, .add-bookmark-pop button {\n\t display: block;\n\t width: 100%;\n\t height: 30px;\n\t margin: 10px 0;\n\t padding: 0;\n\t line-height: 30px;\n}\n .add-bookmark-pop input[type=\"text\"] {\n\t padding: 0 2px;\n\t border: 1px solid #0d9572;\n\t outline: #0d9572;\n}\n .add-bookmark-pop input[type=\"button\"], .add-bookmark-pop button {\n\t border: 1px solid #fff;\n\t background: #0d9572;\n\t color: #fff;\n\t cursor: pointer;\n}\n .add-bookmark-pop input[type=\"button\"]:hover, .add-bookmark-pop button:hover {\n\t background: #f2f7f2;\n\t border-color: #0d9572;\n\t color: #0d9572;\n}\n .add-bookmark-pop .tips {\n\t margin: 10px;\n\t text-align: center;\n\t color: #FFFE00;\n\t line-height: 20px;\n}\n "
  },
  {
    "path": "popup/popup.html",
    "content": "<html>\n<head>\n  <meta charset=\"utf-8\">\n  <link rel=\"stylesheet\" href=\"popup.css\" charset=\"utf-8\">\n</head>\n\n<body>\n  <header class=\"fix-header\">\n    <ul class=\"clearfix\">\n      <li class=\"search-bar\">\n        <i class=\"icon icon-search\"></i>\n        <input type=\"text\" id=\"J_SearchBookmark\" placeholder=\"search...\"></input>\n        <i id=\"J_SearchClose\" class=\"icon icon-close\"></i>\n      </li>\n    </ul>\n  </header>\n\n  <div id=\"J_BookmarkSearchList\" class=\"bookmark-ctr\">\n    <!--搜索标签结果列表-->\n  </div>\n\n  <div id=\"J_BookmarkHot\" class=\"bookmark-ctr\">\n    <!--最常使用-->\n  </div>\n\n  <div id=\"J_BookmarkRecent\" class=\"bookmark-ctr\">\n    <!--最新添加-->\n  </div>\n\n  <div id=\"J_BookmarkCtr\" class=\"bookmark-ctr\">\n    <!--书签列表-->\n  </div>\n\n  <div id=\"J_AddBookmarkPop\" class=\"add-bookmark-pop\">\n    <div class=\"wrapper\">\n      <input type=\"text\" name=\"title\" value=\"\" placeholder=\"title\" autocomplete=\"off\">\n      <input type=\"text\" name=\"url\" value=\"\" placeholder=\"url link\" autocomplete=\"off\">\n      <input type=\"button\" name=\"name\" value=\"Add\" class=\"J_SubmitAddBookmark\">\n      <input type=\"button\" name=\"name\" value=\"Update\" class=\"J_UpdateAddBookmark\">\n      <input type=\"button\" name=\"name\" value=\"Delete\" class=\"J_DeleteAddBookmark\">\n      <button type=\"button\" name=\"button\" class=\"J_CancelAddBookmark\">Cancel</button>\n      <p class=\"tips\"></p>\n    </div>\n  </div>\n  <script src=\"/lib/zepto.min.js\"></script>\n  <script src=\"popup.js\"></script>\n</body>\n\n</html>"
  },
  {
    "path": "popup/popup.js",
    "content": "function faviconURL(u) {\n  const url = new URL(chrome.runtime.getURL(\"/_favicon/\"));\n  url.searchParams.set(\"pageUrl\", u);\n  url.searchParams.set(\"size\", \"32\");\n  return url.toString();\n}\n\nclass Bookmark {\n  constructor() {\n    let that = this\n\n    that.bookmarkDict = {}\n\n    that.initI18n()\n    that.registerHotBookmark()\n    that.registerSearchBar()\n\n    chrome.bookmarks.getRecent(8, function(list) {\n      let obj = {}\n      obj[that.i18n.txtTitleNewest] = list\n      that.renderBookmarks($('#J_BookmarkRecent'), obj)\n    })\n\n    // 获取书签数据\n    chrome.bookmarks.getTree(function(tree) {\n      // 获取用户配置\n      chrome.storage.sync.get('hasNewBookmarkBtn',(obj)=>{\n        let hasNew = obj.hasNewBookmarkBtn === false ? false : true\n        that.recursiveTree(tree[0], '')\n        that.renderBookmarks($('#J_BookmarkCtr'), that.bookmarkDict, hasNew)\n        that.bindEvent()\n      })\n    })\n  }\n\n  initI18n() {\n    let i18n = chrome.i18n\n    this.i18n = {\n      errTitle: i18n.getMessage('extErrTitle'),\n      errUrl: i18n.getMessage('extErrUrl'),\n      btnCancel: i18n.getMessage('extBtnCancel'),\n      btnDelete: i18n.getMessage('extBtnDelete'),\n      btnUpdate: i18n.getMessage('extBtnUpdate'),\n      btnSubmit: i18n.getMessage('extBtnSubmit'),\n      txtNewSite: i18n.getMessage('extTxtNewSite'),\n      txtsearchResult: i18n.getMessage('extTitleSearchResult'),\n      txtTitleNewest: i18n.getMessage('extTitleNewest'),\n      txtTitleSearchResult: i18n.getMessage('extTitleSearchResult'),\n      txtTitleViews: i18n.getMessage('extTitleViews')\n    }\n\n    $('.J_UpdateAddBookmark').val(this.i18n.btnUpdate)\n    $('.J_DeleteAddBookmark').val(this.i18n.btnDelete)\n    $('.J_SubmitAddBookmark').val(this.i18n.btnSubmit)\n    $('.J_CancelAddBookmark').text(this.i18n.btnCancel)\n  }\n\n  registerSearchBar() {\n    let that = this\n    let inputPause = false\n    let $searchBar = $('#J_SearchBookmark')\n    let $searchResultList = $('#J_BookmarkSearchList')\n    $searchBar.on('input', function(params) {\n      if (inputPause) {\n        return\n      }\n\n      inputPause = true\n\n      setTimeout(function(params) {\n        let val = $searchBar.val()\n        if (val) {\n          renderSearchBookmark(val)\n        } else {\n          $searchResultList.hide()\n        }\n        inputPause = false\n      }, 1000)\n    })\n\n    $('#J_SearchClose').on('click', function() {\n      $searchResultList.hide()\n    })\n\n    function renderSearchBookmark(val) {\n      chrome.bookmarks.search(val, function(list) {\n        let obj = {}\n        obj[that.i18n.txtTitleSearchResult] = list\n        that.renderBookmarks($searchResultList, obj)\n        $searchResultList.show()\n      })\n    }\n  }\n\n  // 实现最热书签排行榜\n  registerHotBookmark() {\n    let that = this\n    let CStorage = chrome.storage.local\n    $('.bookmark-ctr').on('click', 'li', function(e) {\n      //  e.preventDefault()\n      if (e.target.href) {\n        let bkid = e.currentTarget.dataset.id.toString()\n        CStorage.get(bkid, function(obj) {\n          let num = obj[bkid]\n          let saveObj = {}\n\n          saveObj[bkid] = 1\n          if (num) {\n            saveObj[bkid] = num + 1\n          }\n          CStorage.set(saveObj)\n        })\n      }\n    })\n\n    CStorage.get(null, function(obj) {\n      let objArr = []\n      let idList = []\n\n      // obj=>arr\n      for (let i in obj) {\n        if (/^\\d+$/.test(i)) {\n          objArr.push({\n            id: i,\n            num: obj[i]\n          })\n        }\n      }\n\n      // 过滤出点击num最大的前8个数据\n      objArr.sort(function(a, b) {\n          return b.num - a.num\n        })\n        .slice(0, 8)\n        .forEach(function(item) {\n          idList.push(item.id)\n        })\n\n      chrome.bookmarks.get(idList, function(list) {\n        let obj = {}\n        obj[that.i18n.txtTitleViews] = list\n        that.renderBookmarks($('#J_BookmarkHot'), obj)\n      })\n    })\n  }\n\n  // 遍历收藏夹，将叶子节点的父节点作为分类名归类\n  recursiveTree(dad, dadName, self) {\n    let that = this\n    if (dad && dad.children) {\n      if (dad.children.length) {\n        dad.children.forEach(function(son) {\n          let title = dadName\n          if (son.children) {\n            title = dadName ? dadName + '-' + son.title : son.title\n          }\n          that.recursiveTree(son, title)\n        })\n      } else {\n        that.recursiveTree(null, dadName, dad)\n      }\n\n    } else if (that.bookmarkDict[dadName]) {\n      that.bookmarkDict[dadName].push(dad)\n    } else if (dadName) {\n      that.bookmarkDict[dadName] = dad ? [dad] : self\n    }\n  }\n\n  // 渲染收藏夹列表\n  renderBookmarks($ctr, dict, hasNew) {\n    let tpl = ''\n    let txtNewSite = this.i18n.txtNewSite\n    for (let key in dict) {\n      tpl += '<section><h2>' + key + '</h2><ul class=\"clearfix\">'\n      if (dict[key].length) {\n        dict[key].forEach(function(item) {\n          tpl += '<li data-id=\"' + item.id + '\" data-parentId=\"' + item.parentId + '\" data-index=\"' + item.index + '\" data-title=\"' + item.title + '\" data-url=\"' + item.url + '\"' + '><i class=\"J_BookmarkEdit\" style=\"background-image:url(' + faviconURL(item.url) + ')\"></i><a target=\"_blank\" class=\"bm-item\" href=\"' + item.url + '\" alt=\"' + item.url + '\">' + item.title + '</a></li>'\n        })\n\n        if (hasNew) {\n          tpl += '<li class=\"J_BookmarkNew bookmark-new\" data-parentId=\"' + dict[key][0].parentId + '\" >' + txtNewSite + '</li></ul></section>'\n        } else {\n          tpl += '</ul></section>'\n        }\n\n      } else if (hasNew) {\n        // 该分类下无数据，那么在该分类下建立的页面的parentId就是该分类本身的id\n        tpl += '<li class=\"J_BookmarkNew bookmark-new\" data-parentId=\"' + dict[key].id + '\" >' + txtNewSite + '</li></ul></section>'\n      } else {\n        tpl += '</ul></section>'\n      }\n\n    }\n    $ctr.html(tpl)\n  }\n\n  // 注册所有用户事件\n  bindEvent() {\n    let that = this\n    let currentNewBookmarkParentId = 0\n    $('.J_BookmarkNew').on('click', function(e) {\n      let $target = $(e.target)\n      currentNewBookmarkParentId = $target.attr('data-parentId')\n\n      that.showAddBookmarkPop()\n    })\n\n    $('.J_BookmarkEdit').on('click', function(e) {\n      let $father = $(e.target).parent()\n      that.showAddBookmarkPop($father.attr('data-id'), $father.attr('data-title'), $father.attr('data-url'))\n    })\n\n    $('.J_SubmitAddBookmark').on('click', function(e) {\n      let title = $('#J_AddBookmarkPop').find('input[name=title]').val()\n      let url = $('#J_AddBookmarkPop').find('input[name=url]').val()\n      if (!title.length) {\n        $('#J_AddBookmarkPop').find('.tips').html(that.i18n.errTitle)\n        return\n      }\n      if (!/(http|https):\\/\\/.+/g.test(url)) {\n        $('#J_AddBookmarkPop').find('.tips').html(that.i18n.errUrl)\n        return\n      }\n\n      chrome.bookmarks.create({\n        parentId: currentNewBookmarkParentId,\n        title: title,\n        url: url\n      }, function(e) {\n        location.reload()\n      });\n    })\n\n    $('.J_DeleteAddBookmark').on('click', function(e) {\n      chrome.bookmarks.remove($('.J_DeleteAddBookmark').attr('data-id'), function(e) {\n        location.reload()\n      });\n    })\n\n    $('.J_UpdateAddBookmark').on('click', function(e) {\n      let title = $('#J_AddBookmarkPop').find('input[name=title]').val()\n      let url = $('#J_AddBookmarkPop').find('input[name=url]').val()\n      if (!title.length) {\n        $('#J_AddBookmarkPop').find('.tips').html(that.i18n.errTitle)\n        return\n      }\n      if (!/(http|https):\\/\\/.+/g.test(url)) {\n        $('#J_AddBookmarkPop').find('.tips').html(that.i18n.errUrl)\n        return\n      }\n\n      chrome.bookmarks.update($('.J_UpdateAddBookmark').attr('data-id'), {\n        title: title,\n        url: url\n      }, function(e) {\n        location.reload()\n      });\n    })\n\n    $('.J_CancelAddBookmark').on('click', function(e) {\n      $('#J_AddBookmarkPop').removeClass('show')\n    })\n  }\n\n  // 展示书签编辑框，根据参数来判断是更新还是新建或者删除\n  showAddBookmarkPop(id, title, url) {\n    $('#J_AddBookmarkPop').addClass('show')\n    $('#J_AddBookmarkPop').find('input[type=button]').hide()\n\n    if (id) {\n      $('.J_UpdateAddBookmark').attr('data-id', id).show()\n      $('.J_DeleteAddBookmark').attr('data-id', id).show()\n      $('#J_AddBookmarkPop').find('input[name=title]').val(title)\n      $('#J_AddBookmarkPop').find('input[name=url]').val(url)\n    } else {\n      $('.J_SubmitAddBookmark').show()\n      $('#J_AddBookmarkPop').find('input[name=title]').val('')\n      $('#J_AddBookmarkPop').find('input[name=url]').val('')\n    }\n  }\n}\n\nnew Bookmark()"
  },
  {
    "path": "service-worker-utils.js",
    "content": "// This file can be imported inside the service worker,\n// which means all of its functions and variables will be accessible\n// inside the service worker.\n// The importation is done in the file `service-worker.js`.\n\nconsole.log(\"External file is also loaded!\")\n"
  },
  {
    "path": "service-worker.js",
    "content": "// This is the service worker script, which executes in its own context\n// when the extension is installed or refreshed (or when you access its console).\n// It would correspond to the background script in chrome extensions v2.\n\nconsole.log(\"This prints to the console of the service worker (background script)\")\n\n// Importing and using functionality from external files is also possible.\nimportScripts('service-worker-utils.js')\n\n// If you want to import a file that is deeper in the file hierarchy of your\n// extension, simply do `importScripts('path/to/file.js')`.\n// The path should be relative to the file `manifest.json`.\n"
  },
  {
    "path": "settings/settings.css",
    "content": "body {\n    background-color: #222;\n    color: #eee;\n}\n\n.special-text {\n    color: red;\n}\n"
  },
  {
    "path": "settings/settings.html",
    "content": "<html>\n<head>\n<meta charset=\"utf-8\">\n  <title>iBookmark</title>\n</head>\n<style>\n  section {\n    width: 600px;\n    margin: 50px auto;\n    text-align: center;\n  }\n</style>\n\n<body>\n  <section>\n    <img src=\"/img/icon128.png\" alt=\"iBookmark\">\n    <h1>iBookmark 0.0.4</h1>\n    <p><a href=\"https://github.com/0326/iBookmark\">fork on GitHub:iBookmark</a></p>\n  </section>\n  <section>\n    <h1>功能设置</h1>\n    <form action=\"\">\n      <div>\n        <label for=\"i_BookmarkNew\">是否展示添加新网址链接</label>\n        <input type=\"checkbox\" name=\"bookmark-new\" id=\"i_BookmarkNew\" checked></input>\n      </div>\n    </form>\n  </section>\n  <script src=\"/lib/zepto.min.js\"></script>\n  <script src=\"settings.js\"></script>\n</body>\n\n</html>"
  },
  {
    "path": "settings/settings.js",
    "content": "\nconst $ = Zepto\n\nchrome.storage.sync.get('hasNewBookmarkBtn',(obj)=>{\n  let $opt = $('#i_BookmarkNew')[0]\n  obj.hasNewBookmarkBtn === false ? $opt.checked = false : '默认为true'\n})\n\nfunction registerEvent() {\n  $('#i_BookmarkNew').on('change', (e) => {\n    chrome.storage.sync.set({'hasNewBookmarkBtn': e.target.checked},() => {\n      // chrome.storage.sync.get('hasNewBookmarkBtn',(obj)=>{\n      //   console.log(obj)\n      // })\n    }) \n  })\n}\n\nregisterEvent()"
  }
]