├── LICENSE
├── README.md
├── _locales
├── en
│ └── messages.json
├── en_US
│ └── messages.json
├── ja
│ └── messages.json
├── ko
│ └── messages.json
├── zh_CN
│ └── messages.json
└── zh_TW
│ └── messages.json
├── foreground.js
├── img
├── icon-close16.png
├── icon-search16.png
├── icon128.png
├── icon16.png
├── icon19.png
├── icon38.png
└── icon48.png
├── lib
└── zepto.min.js
├── manifest.json
├── popup
├── popup.css
├── popup.html
└── popup.js
├── service-worker-utils.js
├── service-worker.js
└── settings
├── settings.css
├── settings.html
└── settings.js
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 SimGus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # iBookmark
4 | Chrome extension for manage bookmarks 一款简单好用的 Chrome 书签管理插件,项目工程非常简单,可供学习参考。
5 |
6 | 下载地址:https://chrome.google.com/webstore/detail/ibookmark/fnfchnalfnjbjbfeccpophocngdgapad
7 |
8 | Wiki文档: https://github.com/0326/iBookmark/wiki
9 |
10 | ## 快速上手
11 | 先clone项目启动watch:
12 | ```shell
13 | git clone git@github.com:0326/iBookmark.git
14 | cd iBookmark
15 | # install devDependencies
16 | npm i
17 | # start watch
18 | gulp
19 | ```
20 | 然后chrome://extensions/ => 加载已解压 扩展程序 => 加载iBookmark文件夹:
21 |
22 | 注意插件ID信息,浏览器访问:
23 | chrome-extension://{{插件ID}}/popup/popup.html
24 |
25 | 编码完成后把项目打包成zip即可上传应用市场。
26 |
27 |
28 |
29 | ## 已完成功能
30 | - 所有书签分组展示
31 | - 在当前分组新增书签
32 | - 修改已有书签信息
33 | - 删除书签
34 | - 搜索书签功能
35 | - 统计书签使用频率,新增常用书签一栏
36 | - 支持 manifest.json V3
37 |
38 | ## 待完成功能
39 | - 新增书签类别
40 | - 修改书签类别名称
41 | - 删除某个书签分类
42 | - 支持书签拖拽,以及移动到其他分类
43 | - 支持历史记录
44 | - 支持插件配置功能,可配置主题,配置是否隐藏某些分类下的书签
45 |
46 | ## 协议
47 | MIT.
48 |
49 | ## 更新日志
50 | 0.0.4版本: 支持 manifest V3 协议
51 | 0.0.2版本: 新增配置功能,是否在每个分类下展示添加网址链接按钮
--------------------------------------------------------------------------------
/_locales/en/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "appName": { "message": "iBookmark" },
3 | "appDesc": { "message": "the best bookmark manager in Chrome" },
4 | "extErrTitle": { "message": "Title Required" },
5 | "extErrUrl": { "message": "Url Format Error
Please Start With 'http://' or 'https://'" },
6 | "extBtnCancel": { "message": "Cancel" },
7 | "extBtnDelete": { "message": "Delete" },
8 | "extBtnUpdate": { "message": "Update" },
9 | "extBtnSubmit": { "message": "Submit" },
10 | "extTitleSearchResult": { "message": "Search Result" },
11 | "extTxtNewSite": { "message": "Add New Site" },
12 | "extTitleNewest": { "message": "The Newest" },
13 | "extTitleViews": { "message": "The Most Views" }
14 | }
--------------------------------------------------------------------------------
/_locales/en_US/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "appName": { "message": "iBookmark" },
3 | "appDesc": { "message": "the best bookmark manager in Chrome" },
4 | "extErrTitle": { "message": "Title Required" },
5 | "extErrUrl": { "message": "Url Format Error
Please Start With 'http://' or 'https://'" },
6 | "extBtnCancel": { "message": "Cancel" },
7 | "extBtnDelete": { "message": "Delete" },
8 | "extBtnUpdate": { "message": "Update" },
9 | "extBtnSubmit": { "message": "Submit" },
10 | "extTitleSearchResult": { "message": "Search Result" },
11 | "extTxtNewSite": { "message": "Add New Site" },
12 | "extTitleNewest": { "message": "The Newest" },
13 | "extTitleViews": { "message": "The Most Views" }
14 | }
--------------------------------------------------------------------------------
/_locales/ja/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "appName": { "message": "iBookmark" },
3 | "appDesc": { "message": "Chromeで最高のブックマークマネージャー" },
4 | "extErrTitle": { "message": "タイトルを入力してください" },
5 | "extErrUrl": { "message": "URL形式エラー
「http://」または「https://」で始めてください" },
6 | "extBtnCancel": { "message": "キャンセル" },
7 | "extBtnDelete": { "message": "削除" },
8 | "extBtnUpdate": { "message": "更新" },
9 | "extBtnSubmit": { "message": "送信" },
10 | "extTitleSearchResult": { "message": "検索結果" },
11 | "extTxtNewSite": { "message": "新しいサイトを追加" },
12 | "extTitleNewest": { "message": "最新の追加" },
13 | "extTitleViews": { "message": "最も閲覧された" }
14 | }
--------------------------------------------------------------------------------
/_locales/ko/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "appName": { "message": "iBookmark" },
3 | "appDesc": { "message": "Chrome에서 최고의 북마크 관리자" },
4 | "extErrTitle": { "message": "제목을 입력하세요" },
5 | "extErrUrl": { "message": "URL 형식 오류
'http://' 또는 'https://'로 시작하세요" },
6 | "extBtnCancel": { "message": "취소" },
7 | "extBtnDelete": { "message": "삭제" },
8 | "extBtnUpdate": { "message": "수정" },
9 | "extBtnSubmit": { "message": "제출" },
10 | "extTitleSearchResult": { "message": "검색 결과" },
11 | "extTxtNewSite": { "message": "새 사이트 추가" },
12 | "extTitleNewest": { "message": "최신 추가" },
13 | "extTitleViews": { "message": "가장 많이 본" }
14 | }
--------------------------------------------------------------------------------
/_locales/zh_CN/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "appName": {
3 | "message": "iBookmark 收藏夹"
4 | },
5 | "appDesc": {
6 | "message": "做最好用的Chrome收藏夹"
7 | },
8 | "extErrTitle": {
9 | "message":"请输入标题"
10 | },
11 | "extErrUrl": {
12 | "message":"地址格式错误
请以http://或者https://开头"
13 | },
14 | "extBtnCancel": {
15 | "message":"取消"
16 | },
17 | "extBtnDelete": {
18 | "message":"删除"
19 | },
20 | "extBtnUpdate": {
21 | "message":"修改"
22 | },
23 | "extBtnSubmit": {
24 | "message":"提交"
25 | },
26 | "extTitleSearchResult": {
27 | "message":"搜索结果"
28 | },
29 | "extTxtNewSite": {
30 | "message":"添加新网址"
31 | },
32 | "extTitleNewest": {
33 | "message":"最新添加"
34 | },
35 | "extTitleViews": {
36 | "message":"最常访问"
37 | }
38 | }
--------------------------------------------------------------------------------
/_locales/zh_TW/messages.json:
--------------------------------------------------------------------------------
1 | {
2 | "appName": { "message": "iBookmark 收藏夾" },
3 | "appDesc": { "message": "做最好用的Chrome收藏夾" },
4 | "extErrTitle": { "message": "請輸入標題" },
5 | "extErrUrl": { "message": "地址格式錯誤
請以http://或https://開頭" },
6 | "extBtnCancel": { "message": "取消" },
7 | "extBtnDelete": { "message": "刪除" },
8 | "extBtnUpdate": { "message": "修改" },
9 | "extBtnSubmit": { "message": "提交" },
10 | "extTitleSearchResult": { "message": "搜尋結果" },
11 | "extTxtNewSite": { "message": "新增網址" },
12 | "extTitleNewest": { "message": "最新新增" },
13 | "extTitleViews": { "message": "最常訪問" }
14 | }
--------------------------------------------------------------------------------
/foreground.js:
--------------------------------------------------------------------------------
1 | // This script gets injected into any opened page
2 | // whose URL matches the pattern defined in the manifest
3 | // (see "content_script" key).
4 | // Several foreground scripts can be declared
5 | // and injected into the same or different pages.
6 |
7 | console.log("This prints to the console of the page (injected only if the page url matched)")
8 |
--------------------------------------------------------------------------------
/img/icon-close16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0326/iBookmark/f8334ce1636aabce17104f8b3cbb42e02cee4517/img/icon-close16.png
--------------------------------------------------------------------------------
/img/icon-search16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0326/iBookmark/f8334ce1636aabce17104f8b3cbb42e02cee4517/img/icon-search16.png
--------------------------------------------------------------------------------
/img/icon128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0326/iBookmark/f8334ce1636aabce17104f8b3cbb42e02cee4517/img/icon128.png
--------------------------------------------------------------------------------
/img/icon16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0326/iBookmark/f8334ce1636aabce17104f8b3cbb42e02cee4517/img/icon16.png
--------------------------------------------------------------------------------
/img/icon19.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0326/iBookmark/f8334ce1636aabce17104f8b3cbb42e02cee4517/img/icon19.png
--------------------------------------------------------------------------------
/img/icon38.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0326/iBookmark/f8334ce1636aabce17104f8b3cbb42e02cee4517/img/icon38.png
--------------------------------------------------------------------------------
/img/icon48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/0326/iBookmark/f8334ce1636aabce17104f8b3cbb42e02cee4517/img/icon48.png
--------------------------------------------------------------------------------
/lib/zepto.min.js:
--------------------------------------------------------------------------------
1 | /* Zepto v1.0rc1 - polyfill zepto event detect fx ajax form touch - zeptojs.com/license */
2 | (function(a){String.prototype.trim===a&&(String.prototype.trim=function(){return this.replace(/^\s+/,"").replace(/\s+$/,"")}),Array.prototype.reduce===a&&(Array.prototype.reduce=function(b){if(this===void 0||this===null)throw new TypeError;var c=Object(this),d=c.length>>>0,e=0,f;if(typeof b!="function")throw new TypeError;if(d==0&&arguments.length==1)throw new TypeError;if(arguments.length>=2)f=arguments[1];else do{if(e in c){f=c[e++];break}if(++e>=d)throw new TypeError}while(!0);while(e0?[].concat.apply([],a):a}function H(a){return a.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function I(a){return a in i?i[a]:i[a]=new RegExp("(^|\\s)"+a+"(\\s|$)")}function J(a,b){return typeof b=="number"&&!k[H(a)]?b+"px":b}function K(a){var b,c;return h[a]||(b=g.createElement(a),g.body.appendChild(b),c=j(b,"").getPropertyValue("display"),b.parentNode.removeChild(b),c=="none"&&(c="block"),h[a]=c),h[a]}function L(b,d){return d===a?c(b):c(b).filter(d)}function M(a,b,c,d){return A(b)?b.call(a,c,d):b}function N(a,b,d){var e=a%2?b:b.parentNode;e?e.insertBefore(d,a?a==1?e.firstChild:a==2?b:null:b.nextSibling):c(d).remove()}function O(a,b){b(a);for(var c in a.childNodes)O(a.childNodes[c],b)}var a,b,c,d,e=[],f=e.slice,g=window.document,h={},i={},j=g.defaultView.getComputedStyle,k={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},l=/^\s*<(\w+|!)[^>]*>/,m=[1,3,8,9,11],n=["after","prepend","before","append"],o=g.createElement("table"),p=g.createElement("tr"),q={tr:g.createElement("tbody"),tbody:o,thead:o,tfoot:o,td:p,th:p,"*":g.createElement("div")},r=/complete|loaded|interactive/,s=/^\.([\w-]+)$/,t=/^#([\w-]+)$/,u=/^[\w-]+$/,v={}.toString,w={},x,y,z=g.createElement("div");return w.matches=function(a,b){if(!a||a.nodeType!==1)return!1;var c=a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.matchesSelector;if(c)return c.call(a,b);var d,e=a.parentNode,f=!e;return f&&(e=z).appendChild(a),d=~w.qsa(e,b).indexOf(a),f&&z.removeChild(a),d},x=function(a){return a.replace(/-+(.)?/g,function(a,b){return b?b.toUpperCase():""})},y=function(a){return a.filter(function(b,c){return a.indexOf(b)==c})},w.fragment=function(b,d){d===a&&(d=l.test(b)&&RegExp.$1),d in q||(d="*");var e=q[d];return e.innerHTML=""+b,c.each(f.call(e.childNodes),function(){e.removeChild(this)})},w.Z=function(a,b){return a=a||[],a.__proto__=arguments.callee.prototype,a.selector=b||"",a},w.isZ=function(a){return a instanceof w.Z},w.init=function(b,d){if(!b)return w.Z();if(A(b))return c(g).ready(b);if(w.isZ(b))return b;var e;if(D(b))e=F(b);else if(C(b))e=[c.extend({},b)],b=null;else if(m.indexOf(b.nodeType)>=0||b===window)e=[b],b=null;else if(l.test(b))e=w.fragment(b.trim(),RegExp.$1),b=null;else{if(d!==a)return c(d).find(b);e=w.qsa(g,b)}return w.Z(e,b)},c=function(a,b){return w.init(a,b)},c.extend=function(c){return f.call(arguments,1).forEach(function(d){for(b in d)d[b]!==a&&(c[b]=d[b])}),c},w.qsa=function(a,b){var c;return a===g&&t.test(b)?(c=a.getElementById(RegExp.$1))?[c]:e:a.nodeType!==1&&a.nodeType!==9?e:f.call(s.test(b)?a.getElementsByClassName(RegExp.$1):u.test(b)?a.getElementsByTagName(b):a.querySelectorAll(b))},c.isFunction=A,c.isObject=B,c.isArray=D,c.isPlainObject=C,c.inArray=function(a,b,c){return e.indexOf.call(b,a,c)},c.trim=function(a){return a.trim()},c.uuid=0,c.map=function(a,b){var c,d=[],e,f;if(E(a))for(e=0;e0&&w.matches(this[0],a)},not:function(b){var d=[];if(A(b)&&b.call!==a)this.each(function(a){b.call(this,a)||d.push(this)});else{var e=typeof b=="string"?this.filter(b):E(b)&&A(b.item)?f.call(b):c(b);this.forEach(function(a){e.indexOf(a)<0&&d.push(a)})}return c(d)},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){var a=this[0];return a&&!B(a)?a:c(a)},last:function(){var a=this[this.length-1];return a&&!B(a)?a:c(a)},find:function(a){var b;return this.length==1?b=w.qsa(this[0],a):b=this.map(function(){return w.qsa(this,a)}),c(b)},closest:function(a,b){var d=this[0];while(d&&!w.matches(d,a))d=d!==b&&d!==g&&d.parentNode;return c(d)},parents:function(a){var b=[],d=this;while(d.length>0)d=c.map(d,function(a){if((a=a.parentNode)&&a!==g&&b.indexOf(a)<0)return b.push(a),a});return L(b,a)},parent:function(a){return L(y(this.pluck("parentNode")),a)},children:function(a){return L(this.map(function(){return f.call(this.children)}),a)},siblings:function(a){return L(this.map(function(a,b){return f.call(b.parentNode.children).filter(function(a){return a!==b})}),a)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(a){return this.map(function(){return this[a]})},show:function(){return this.each(function(){this.style.display=="none"&&(this.style.display=null),j(this,"").getPropertyValue("display")=="none"&&(this.style.display=K(this.nodeName))})},replaceWith:function(a){return this.before(a).remove()},wrap:function(a){return this.each(function(){c(this).wrapAll(c(a)[0].cloneNode(!1))})},wrapAll:function(a){return this[0]&&(c(this[0]).before(a=c(a)),a.append(this)),this},unwrap:function(){return this.parent().each(function(){c(this).replaceWith(c(this).children())}),this},clone:function(){return c(this.map(function(){return this.cloneNode(!0)}))},hide:function(){return this.css("display","none")},toggle:function(b){return(b===a?this.css("display")=="none":b)?this.show():this.hide()},prev:function(){return c(this.pluck("previousElementSibling"))},next:function(){return c(this.pluck("nextElementSibling"))},html:function(b){return b===a?this.length>0?this[0].innerHTML:null:this.each(function(a){var d=this.innerHTML;c(this).empty().append(M(this,b,a,d))})},text:function(b){return b===a?this.length>0?this[0].textContent:null:this.each(function(){this.textContent=b})},attr:function(c,d){var e;return typeof c=="string"&&d===a?this.length==0||this[0].nodeType!==1?a:c=="value"&&this[0].nodeName=="INPUT"?this.val():!(e=this[0].getAttribute(c))&&c in this[0]?this[0][c]:e:this.each(function(a){if(this.nodeType!==1)return;if(B(c))for(b in c)this.setAttribute(b,c[b]);else this.setAttribute(c,M(this,d,a,this.getAttribute(c)))})},removeAttr:function(a){return this.each(function(){this.nodeType===1&&this.removeAttribute(a)})},prop:function(b,c){return c===a?this[0]?this[0][b]:a:this.each(function(a){this[b]=M(this,c,a,this[b])})},data:function(b,c){var d=this.attr("data-"+H(b),c);return d!==null?d:a},val:function(b){return b===a?this.length>0?this[0].value:a:this.each(function(a){this.value=M(this,b,a,this.value)})},offset:function(){if(this.length==0)return null;var a=this[0].getBoundingClientRect();return{left:a.left+window.pageXOffset,top:a.top+window.pageYOffset,width:a.width,height:a.height}},css:function(c,d){if(d===a&&typeof c=="string")return this.length==0?a:this[0].style[x(c)]||j(this[0],"").getPropertyValue(c);var e="";for(b in c)typeof c[b]=="string"&&c[b]==""?this.each(function(){this.style.removeProperty(H(b))}):e+=H(b)+":"+J(b,c[b])+";";return typeof c=="string"&&(d==""?this.each(function(){this.style.removeProperty(H(c))}):e=H(c)+":"+J(c,d)),this.each(function(){this.style.cssText+=";"+e})},index:function(a){return a?this.indexOf(c(a)[0]):this.parent().children().indexOf(this[0])},hasClass:function(a){return this.length<1?!1:I(a).test(this[0].className)},addClass:function(a){return this.each(function(b){d=[];var e=this.className,f=M(this,a,b,e);f.split(/\s+/g).forEach(function(a){c(this).hasClass(a)||d.push(a)},this),d.length&&(this.className+=(e?" ":"")+d.join(" "))})},removeClass:function(b){return this.each(function(c){if(b===a)return this.className="";d=this.className,M(this,b,c,d).split(/\s+/g).forEach(function(a){d=d.replace(I(a)," ")}),this.className=d.trim()})},toggleClass:function(b,d){return this.each(function(e){var f=M(this,b,e,this.className);(d===a?!c(this).hasClass(f):d)?c(this).addClass(f):c(this).removeClass(f)})}},["width","height"].forEach(function(b){c.fn[b]=function(d){var e,f=b.replace(/./,function(a){return a[0].toUpperCase()});return d===a?this[0]==window?window["inner"+f]:this[0]==g?g.documentElement["offset"+f]:(e=this.offset())&&e[b]:this.each(function(a){var e=c(this);e.css(b,M(this,d,a,e[b]()))})}}),n.forEach(function(a,b){c.fn[a]=function(){var a=c.map(arguments,function(a){return B(a)?a:w.fragment(a)});if(a.length<1)return this;var d=this.length,e=d>1,f=b<2;return this.each(function(c,g){for(var h=0;h0&&this.bind(o,n),setTimeout(function(){m.css(i),e<=0&&setTimeout(function(){m.each(function(){n.call(this)})},0)},0),this},i=null}(Zepto),function($){function triggerAndReturn(a,b,c){var d=$.Event(b);return $(a).trigger(d,c),!d.defaultPrevented}function triggerGlobal(a,b,c,d){if(a.global)return triggerAndReturn(b||document,c,d)}function ajaxStart(a){a.global&&$.active++===0&&triggerGlobal(a,null,"ajaxStart")}function ajaxStop(a){a.global&&!--$.active&&triggerGlobal(a,null,"ajaxStop")}function ajaxBeforeSend(a,b){var c=b.context;if(b.beforeSend.call(c,a,b)===!1||triggerGlobal(b,c,"ajaxBeforeSend",[a,b])===!1)return!1;triggerGlobal(b,c,"ajaxSend",[a,b])}function ajaxSuccess(a,b,c){var d=c.context,e="success";c.success.call(d,a,e,b),triggerGlobal(c,d,"ajaxSuccess",[b,c,a]),ajaxComplete(e,b,c)}function ajaxError(a,b,c,d){var e=d.context;d.error.call(e,c,b,a),triggerGlobal(d,e,"ajaxError",[c,d,a]),ajaxComplete(b,c,d)}function ajaxComplete(a,b,c){var d=c.context;c.complete.call(d,b,a),triggerGlobal(c,d,"ajaxComplete",[b,c]),ajaxStop(c)}function empty(){}function mimeToDataType(a){return a&&(a==htmlType?"html":a==jsonType?"json":scriptTypeRE.test(a)?"script":xmlTypeRE.test(a)&&"xml")||"text"}function appendQuery(a,b){return(a+"&"+b).replace(/[&?]{1,2}/,"?")}function serializeData(a){isObject(a.data)&&(a.data=$.param(a.data)),a.data&&(!a.type||a.type.toUpperCase()=="GET")&&(a.url=appendQuery(a.url,a.data))}function serialize(a,b,c,d){var e=$.isArray(b);$.each(b,function(b,f){d&&(b=c?d:d+"["+(e?"":b)+"]"),!d&&e?a.add(f.name,f.value):(c?$.isArray(f):isObject(f))?serialize(a,f,c,b):a.add(b,f)})}var jsonpID=0,isObject=$.isObject,document=window.document,key,name,rscript=/
46 |
47 |