diff --git a/TODO b/TODO
new file mode 100644
index 0000000..740ca9f
--- /dev/null
+++ b/TODO
@@ -0,0 +1,3 @@
+Config Page
+Improve screenshot result
+Add favicon support
diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json
new file mode 100644
index 0000000..12a7167
--- /dev/null
+++ b/src/_locales/en/messages.json
@@ -0,0 +1,52 @@
+{
+ "extensionName": {
+ "message": "Quick Dial",
+ "description": "Name of the extension."
+ },
+
+ "extensionDescription": {
+ "message": "Quick Dial, new tab page.",
+ "description": "Description of the extension."
+ },
+
+ "menuAddToQuickDial": {
+ "message": "Add to Quick Dial",
+ "description": "Text of add bookmark menu item."
+ },
+
+ "menuAddBookmark": {
+ "message": "Add Bookmark",
+ "description": "Text of add bookmark menu item."
+ },
+
+ "AddBookmarkPrompt": {
+ "message": "Enter the new bookmark url :",
+ "description": "Text of the add bookmark prompt."
+ },
+
+ "menuAddFolder": {
+ "message": "Add Folder",
+ "description": "Text of add folder menu item."
+ },
+
+ "AddFolderPrompt": {
+ "message": "Enter the new folder name :",
+ "description": "Text of the add folder prompt."
+ },
+
+ "menuRefreshItem": {
+ "message": "Refresh",
+ "description": "Text of refresh menu item."
+ },
+
+ "menuDeleteItem": {
+ "message": "Delete",
+ "description": "Text of delete menu item."
+ },
+
+ "deleteItemConfimation": {
+ "message": "Delete $1 ?",
+ "description": "Text of delete confirmation."
+ }
+
+}
diff --git a/src/_locales/fr/messages.json b/src/_locales/fr/messages.json
new file mode 100644
index 0000000..4e7e134
--- /dev/null
+++ b/src/_locales/fr/messages.json
@@ -0,0 +1,52 @@
+{
+ "extensionName": {
+ "message": "Quick Dial",
+ "description": "Name of the extension."
+ },
+
+ "extensionDescription": {
+ "message": "Quick Dial, page nouvel onglet.",
+ "description": "Description of the extension."
+ },
+
+ "menuAddToQuickDial": {
+ "message": "Ajouter à Quick Dial",
+ "description": "Text of add bookmark menu item."
+ },
+
+ "menuAddBookmark": {
+ "message": "Ajouter un marque-page",
+ "description": "Text of add bookmark menu item."
+ },
+
+ "AddBookmarkPrompt": {
+ "message": "Entrez l'url du nouveau marque-page :",
+ "description": "Text of the add bookmark prompt."
+ },
+
+ "menuAddFolder": {
+ "message": "Ajouter un dossier",
+ "description": "Text of add folder menu item."
+ },
+
+ "AddFolderPrompt": {
+ "message": "Entrez le nom du nouveau dossier :",
+ "description": "Text of the add folder prompt."
+ },
+
+ "menuRefreshItem": {
+ "message": "Actualiser",
+ "description": "Text of refresh menu item."
+ },
+
+ "menuDeleteItem": {
+ "message": "Supprimer",
+ "description": "Text of delete menu item."
+ },
+
+ "deleteItemConfimation": {
+ "message": "Supprimer $1 ?",
+ "description": "Text of delete confirmation."
+ }
+
+}
diff --git a/src/dial b/src/dial
new file mode 100644
index 0000000..92123f6
--- /dev/null
+++ b/src/dial
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/html/options.html b/src/html/options.html
new file mode 100644
index 0000000..8d1c8b6
--- /dev/null
+++ b/src/html/options.html
@@ -0,0 +1 @@
+
diff --git a/src/html/test.html b/src/html/test.html
new file mode 100644
index 0000000..6906290
--- /dev/null
+++ b/src/html/test.html
@@ -0,0 +1,9 @@
+
+
+ test
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/img/24.png b/src/img/24.png
new file mode 100644
index 0000000..6f9210f
Binary files /dev/null and b/src/img/24.png differ
diff --git a/src/img/32.png b/src/img/32.png
new file mode 100644
index 0000000..c497567
Binary files /dev/null and b/src/img/32.png differ
diff --git a/src/img/README.md b/src/img/README.md
new file mode 100644
index 0000000..dd8dc70
--- /dev/null
+++ b/src/img/README.md
@@ -0,0 +1,3 @@
+# About Image licence :
+These images provide from fast dial extention but it's only temporary.
+I would make my own to be free of all dependencies.
diff --git a/src/img/back.png b/src/img/back.png
new file mode 100644
index 0000000..c0095bf
Binary files /dev/null and b/src/img/back.png differ
diff --git a/src/img/folder.png b/src/img/folder.png
new file mode 100644
index 0000000..f83bbec
Binary files /dev/null and b/src/img/folder.png differ
diff --git a/src/img/throbber.gif b/src/img/throbber.gif
new file mode 100644
index 0000000..b8f5437
Binary files /dev/null and b/src/img/throbber.gif differ
diff --git a/src/js/background.js b/src/js/background.js
new file mode 100644
index 0000000..333de77
--- /dev/null
+++ b/src/js/background.js
@@ -0,0 +1,280 @@
+var core = {}; // Main app object in background.js
+var app = {}; // Shared app object with pages
+
+core._init = function(){ // Called from core.Settings.load()
+ core.Bookmarks.initRoot(function(){
+ core.GridNodes.sync(app.settings.grid.node, app.settings.grid.root); // Sync bookmarks with stored data
+ core.ContextMenus.initMenu();
+ core.Bookmarks.initListener();
+ })
+}
+
+core.Settings = {}; // Settings helper object
+core.Settings.load = function(){ // Load settings and call core.init
+ browser.storage.local.get({
+ background: '#3c4048',
+ grid: {
+ margin: 10,
+ rows: 4,
+ columns: 5,
+ cells: {
+ margin: 4,
+ ratioX: 4,
+ ratioY: 3,
+ borderColor: '#333333',
+ borderColorHover: '#a9a9a9',
+ borderRadius: 4,
+ title: true,
+ titleHeight: 18,
+ titleFontSize: 11,
+ titleFont: 'Arial, Verdana, Sans-serif',
+ titleColor: '#ffffff',
+ titleColorHover: '#33ccff',
+ backPanel: true,
+ backIcon: 'img/back.png',
+ folderIcon: 'img/folder.png',
+ loadingIcon: 'img/throbber.gif'
+ },
+ root: 'Quick Dial',
+ node: {}
+ }
+ }).then(function(obj){
+ app.settings = obj;
+ core._init();
+ browser.runtime.sendMessage({ command: 'appReady'}).then(function(){}, function(){});
+ },function(){});
+}
+core.Settings.save = function(){ // Save settings
+ browser.storage.local.set(app.settings);
+}
+core.Settings.load(); // Need to be loaded first and call core.init when ready
+
+core.ContextMenus = {} // ContextMenu helper Object
+core.ContextMenus.initMenu = function(){ // (Called from core._init) Init context menu in all pages
+ browser.contextMenus.create({ // Create Context menu
+ id: 'AddToQuickDial',
+ title: browser.i18n.getMessage("menuAddToQuickDial"),
+ contexts: ["all"],
+ documentUrlPatterns: [ 'http://*/*', 'https://*/*', 'file://*/*' ]
+ }, function(){});
+ browser.contextMenus.onClicked.addListener(function(info, tab) { // Context menu click event
+ if (info.menuItemId == "AddToQuickDial")
+ core.GridNodes.createBookmark(app.settings.grid.node, info.pageUrl, tab.title, function(){});
+ });
+}
+
+core.Bookmarks = {} // Bookmarks helper object
+core.Bookmarks.initListener = function(){ // (Called from core._init) (/!\ Need filter to root tree only) Init listener of bookmarks
+ function notifyBookmarksChanged(){ core.GridNodes.sync(app.settings.grid.node, app.settings.grid.root); }
+ browser.bookmarks.onCreated.addListener(notifyBookmarksChanged);
+ browser.bookmarks.onChanged.addListener(notifyBookmarksChanged);
+ browser.bookmarks.onMoved.addListener(notifyBookmarksChanged);
+ browser.bookmarks.onRemoved.addListener(notifyBookmarksChanged);
+}
+core.Bookmarks.initRoot = function(callback){ // (Called from core._init) Create the root folder if not exist
+ browser.bookmarks.getSubTree('menu________').then(function(bookmarkItems){
+ getChildItem = function(bookmarkItem, path, callback){
+ if(path.length == 0){
+ if(callback) callback(bookmarkItem);
+ return;
+ }
+ for(var child of bookmarkItem.children){
+ if((path + '/').startsWith(child.title + '/')){
+ getChildItem(child, path.substr(child.title.length + 1), callback);
+ return;
+ }
+ }
+ browser.bookmarks.create({
+ parentId: bookmarkItem.id,
+ title: path.substr(0, (path + '/').indexOf('/'))
+ }).then(callback);
+ }
+ getChildItem(bookmarkItems[0], app.settings.grid.root, callback);
+ }, function(){
+ console.log('Can not load bookmarks');
+ if(callback) callback(null);
+ });
+}
+core.Bookmarks.load = function(rootPath, callback){ // callback(bookmarkItem) Return BookmarkItem from rootPath
+ browser.bookmarks.getSubTree('menu________').then(function(bookmarkItems){
+ if(callback) callback(core.Bookmarks.getItem(bookmarkItems[0], rootPath + '/'))
+ }, function(){
+ console.log('Can not load bookmarks');
+ if(callback) callback(null);
+ });
+}
+core.Bookmarks.getItem = function(bookmarkItem, path){ // Return BookmarkItem from path from bookmarkItem as root
+ if(path.length == 0) return bookmarkItem;
+ for(var child of bookmarkItem.children)
+ if(path.startsWith(child.title + '/'))
+ return core.Bookmarks.getItem(child, path.substr(child.title.length + 1));
+ return null;
+}
+
+core.SiteInfos = {} // Siteinfos helper object
+core.SiteInfos.loadInfos = function(url, args, callback){ // args: { icon: false; screenshot: false }, callback( { url, title, (/!\ Not handled now)icon, screenshot } || error: {} )
+ function pageLoaded(){
+ var docTitle = iframe.contentWindow.document.title;
+ var docIcon = null;
+ var docScreenshot = null;
+ if(args && args.icon){
+ //
+ }
+ if(args && args.screenshot){
+ var canvas = document.createElement('canvas');
+ canvas.style.width = previewWidth.toString() + 'px';
+ canvas.style.height = previewHeight.toString() + 'px';
+ canvas.width = previewWidth / 2;
+ canvas.height = previewHeight / 2;
+ var ctx = canvas.getContext('2d');
+ ctx.clearRect(0, 0, previewWidth, previewHeight);
+ ctx.save();
+ ctx.scale(0.5, 0.5);
+ ctx.drawWindow(iframe.contentWindow, 0, 0, previewWidth, previewHeight, 'rgb(255, 255, 255)');
+ ctx.restore();
+ docScreenshot = canvas.toDataURL();
+ }
+
+ document.body.removeChild(iframe);
+ if(callback) callback({ url: url, title: docTitle, icon: docIcon, screenshot:docScreenshot });
+ }
+
+ var previewWidth = 1200; // Need to be linked to settings
+ var previewHeight = 710; // Need to be linked to settings
+ var iframe = document.createElement('iframe');
+ iframe.width = previewWidth
+ iframe.height = previewHeight
+ iframe.style.position = 'absolute';
+ iframe.style.visibility = 'hidden';
+ var xmlHttp = new XMLHttpRequest();
+ xmlHttp.timeout = 2000
+ xmlHttp.open('GET', url, true);
+ xmlHttp.onload = function(){
+ document.body.appendChild(iframe);
+ iframe.contentWindow.document.write(xmlHttp.responseText.replace('', ''));
+ //iframe.contentWindow.document.write(xmlHttp.responseText.replace('', ''));
+ setTimeout(function(){ pageLoaded(); }, 2000); // /!\ Caution function can be shortcuted and sendtimeout is not the best way
+ }
+ xmlHttp.onabort = function(){ if(callback) callback(); }
+ xmlHttp.onerror = function(){ if(callback) callback(); }
+ xmlHttp.ontimeout = function(){ if(callback) callback(); }
+ xmlHttp.send(null);
+}
+
+core.GridNodes = {}; // GridNodes helper object
+core.GridNodes.sync = function(gridNode, rootPath){ // Sync GridNodes with Bookmarks
+ core.Bookmarks.load(rootPath, function(bookmarkItem){
+ core.GridNodes.syncItem(gridNode, bookmarkItem);
+ browser.runtime.sendMessage({ command: 'gridNodesSynced'}).then(function(){}, function(){});
+ core.Settings.save();
+ });
+}
+core.GridNodes.syncItem = function(gridNode, bookmarkItem){ // Sync GridNode with BookmarkItem
+ gridNode.id = bookmarkItem.id;
+ gridNode.title = bookmarkItem.title; // /!\ Need check last update
+ if(bookmarkItem.url){
+ gridNode.type = 'bookmark';
+ gridNode.url = bookmarkItem.url; // /!\ Need check last update
+ } else if(bookmarkItem.children){
+ gridNode.type = 'folder';
+ var EmptyItems = [];
+ if(! gridNode.children) gridNode.children = [];
+ else {
+ for(var i=gridNode.children.length-1; i>=0; i--){
+ if(gridNode.children[i].type!='empty'){
+ var found = false;
+ for(var child of bookmarkItem.children){
+ if(child.id==gridNode.children[i].id){
+ found = true;
+ break;
+ }
+ }
+ if(! found){
+ if(i0){
+ childGridNode = EmptyItems[0];
+ EmptyItems.shift();
+ }else {
+ childGridNode = {};
+ gridNode.children.push(childGridNode)
+ }
+ }
+ core.GridNodes.syncItem(childGridNode, child);
+ }
+ EmptyItems.length = 0;
+ } else node.type = 'empty';
+}
+core.GridNodes.getChild = function(gridNode, id){ // Return child node by ID
+ for(var child of gridNode.children) if(child.id == id) return child;
+ return null;
+}
+core.GridNodes.getNode = function(gridNode, path){ // Return GridNode from RootGridNode path
+ if(path.length == 0 || path == '/') return gridNode;
+ for(var child of gridNode.children)
+ if(path.startsWith(child.title + '/'))
+ return core.GridNodes.getNode(child, path.substr(child.title.length + 1));
+ return null;
+}
+core.GridNodes.refreshNode = function(gridNode, callback){ // Refresh content of a GridNode
+ core.SiteInfos.loadInfos(gridNode.url, { screenshot: true }, function(infos){
+ if(infos){
+ gridNode.title = infos.title;
+ gridNode.image = infos.screenshot;
+ browser.bookmarks.update(gridNode.id, {
+ title: infos.title
+ }).then(function(bookmarkItem){}, function(){});
+ core.Settings.save();
+ }
+ if(callback) callback(infos);
+ });
+}
+core.GridNodes.createFolder = function(gridNode, name, callback){ // Create a new folder in a GridNode
+ browser.bookmarks.create({
+ parentId: gridNode.id,
+ title: name
+ }).then(callback);
+}
+core.GridNodes.createBookmark = function(gridNode, url, title, callback){ // Create a new Bookmark in a GridNode
+ browser.bookmarks.create({
+ parentId: gridNode.id,
+ title: title || url,
+ url: url
+ }).then(callback);
+}
+core.GridNodes.delete = function(id, callback){ // Delete a GridNode
+ browser.bookmarks.removeTree(id).then(callback);
+}
+core.GridNodes.setNodeIndex = function(gridNode, index, newIndex, callback){ // Set Child GridNodeIndex
+ while(newIndex>=gridNode.children.length){
+ gridNode.children.push({ type: 'empty' });
+ }
+ var node1 = gridNode.children[index];
+ var node2 = gridNode.children[newIndex];
+ gridNode.children[index] = node2;
+ gridNode.children[newIndex] = node1;
+ core.Settings.save();
+ if(callback) callback();
+ browser.runtime.sendMessage({ command: 'gridNodesSynced'}).then(function(){}, function(){});
+}
+
+// Public functions
+app.refreshNode = core.GridNodes.refreshNode;
+app.getNode = core.GridNodes.getNode;
+app.createFolder = core.GridNodes.createFolder;
+app.createBookmark = core.GridNodes.createBookmark;
+app.deleteNode = core.GridNodes.delete;
+app.setNodeIndex = core.GridNodes.setNodeIndex;
diff --git a/src/js/dial.js b/src/js/dial.js
new file mode 100644
index 0000000..a2a026d
--- /dev/null
+++ b/src/js/dial.js
@@ -0,0 +1,305 @@
+var app = {}
+var dial = {
+ styles: {},
+ page: 1,
+ maxpage: 1
+};
+
+browser.runtime.getBackgroundPage().then(function(page){ app = page.app; }, function(){});
+window.onload = function(){ if(app.settings) dial.initUI(); }
+window.onresize = function(){
+ if(app.settings) dial.updateGridLayout(dial.Grid, app.settings.grid, dial.styles.grid);
+}
+window.onwheel = function(ev){
+ if(app.settings){
+ if(ev.deltaY > 0){
+ if(dial.page < dial.maxpage){
+ dial.page += 1;
+ dial.populateGrid(dial.Grid, app.settings.grid, dial.Node);
+ }
+ } else if(ev.deltaY < 0){
+ if(dial.page > 1){
+ dial.page -= 1;
+ dial.populateGrid(dial.Grid, app.settings.grid, dial.Node);
+ }
+ }
+ }
+}
+browser.runtime.onMessage.addListener(function(request, sender, sendResponse){
+ switch(request.command){
+ case 'gridNodesSynced':
+ if(app.settings) dial.populateGrid(dial.Grid, app.settings.grid, dial.Node);
+ break;
+ case 'appReady':
+ browser.runtime.getBackgroundPage().then(function(page){ app = page.app; }, function(){});
+ dial.initUI();
+ break;
+ }
+});
+
+
+dial.initUI = function(){
+ dial.Head = document.getElementById('head');
+ dial.Body = document.getElementById('body');
+ dial.Body.setAttribute('contextmenu', 'page');
+ dial.Body.setAttribute('contextmenu', 'page');
+ dial.initStyles();
+ dial.initMenus();
+ dial.Grid = dial.initGrid('Grid', app.settings.grid, dial.Body);
+ var url = new URL(window.location);
+ dial.path = url.searchParams.get('path');
+ /*
+ if(url.searchParams.get('path')) dial.Node = app.getNode(app.settings.grid.node, dial.path + '/');
+ else dial.Node = app.getNode(app.settings.grid.node, '/');
+ */
+ if(url.searchParams.get('path')) {
+ dial.Node = app.getNode(app.settings.grid.node, dial.path + '/');
+ } else {
+ dial.Node = app.getNode(app.settings.grid.node, '/');
+ }
+ dial.populateGrid(dial.Grid, app.settings.grid, dial.Node);
+}
+
+dial.initStyles = function(){
+ dial.Style = document.createElement('style'), StyleSheet;
+ document.head.appendChild(dial.Style);
+ dial.styles.html = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('html { height: 100%; }')].style;
+ dial.styles.body = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('body { user-select: none; -moz-user-select: none; display: flex; width: 100%; height: 100%; margin: 0px; padding: 0px; background: ' + app.settings.background + '; }')].style;
+ dial.styles.grid = {};
+ dial.styles.grid.grid = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid { border-collapse: collapse; margin: auto auto; }')].style;
+ dial.styles.grid.cell = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td { margin: 0px; padding: 0px; }')].style;
+ dial.styles.grid.link = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a { display: block; outline: none; text-decoration: none; margin: ' + app.settings.grid.cells.margin + 'px; border: 1px solid ' + app.settings.grid.cells.borderColor + '; border-radius: ' + app.settings.grid.cells.borderRadius + 'px; }')].style;
+ dial.styles.grid.linkHover = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a:hover { border-color: ' + app.settings.grid.cells.borderColorHover + '; }')].style;
+ dial.styles.grid.linkPanel = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a>div:first-child { background-repeat: no-repeat; }')].style;
+ dial.styles.grid.linkTitle = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a>div:last-child { height: ' + app.settings.grid.cells.titleHeight + 'px; font-size: ' + app.settings.grid.cells.titleFontSize + 'pt; font-family: ' + app.settings.grid.cells.titleFont + 'pt; text-align: center; overflow: hidden; color: ' + app.settings.grid.cells.titleColor + '; border-top: 1px solid ' + app.settings.grid.cells.borderColor + '; }')].style;
+ dial.styles.grid.linkTitleHover = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a:hover>div:last-child { color: ' + app.settings.grid.cells.titleColorHover + '; border-top-color: ' + app.settings.grid.cells.borderColorHover + ' }')].style;
+ dial.styles.grid.linkEmpty = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a.Empty { display: none; }')].style;
+ dial.styles.grid.linkBack = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a.Back :first-child { background-image: url("' + app.settings.grid.cells.backIcon + '"); background-repeat: no-repeat; background-position: center center; }')].style;
+ dial.styles.grid.linkFolder = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a.Folder :first-child { background-image: url("' + app.settings.grid.cells.folderIcon + '"); background-repeat: no-repeat; background-size: 100% 100%; }')].style;
+ dial.styles.grid.linkBookmark = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a.Bookmark :first-child { background-repeat: no-repeat; background-size: 100% 100%; }')].style;
+ dial.styles.grid.linkBookmarkLoading = dial.Style.sheet.cssRules[dial.Style.sheet.insertRule('.Grid td>a.BookmarkLoading :first-child { background-image: url("' + app.settings.grid.cells.loadingIcon + '"); background-repeat: no-repeat; background-position: center center; }')].style;
+}
+
+dial.initMenus = function(){
+ dial.PageMenu = document.createElement('menu');
+ dial.PageMenu.type = 'context';
+ dial.PageMenu.id = 'page'
+ dial.PageMenuCreateBookmark = document.createElement('menuitem');
+ dial.PageMenuCreateBookmark.label = 'Add bookmark';
+ dial.PageMenuCreateBookmark.onclick = dial.createBookmark;
+ dial.PageMenuCreateFolder = document.createElement('menuitem');
+ dial.PageMenuCreateFolder.label = 'Add folder';
+ dial.PageMenuCreateFolder.onclick = dial.createFolder;
+ dial.PageMenu.appendChild(dial.PageMenuCreateBookmark);
+ dial.PageMenu.appendChild(dial.PageMenuCreateFolder);
+ dial.Body.appendChild(dial.PageMenu);
+
+ dial.ItemMenu = document.createElement('menu');
+ dial.ItemMenu.type = 'context';
+ dial.ItemMenu.id = 'item'
+ dial.ItemMenuCreateBookmark = document.createElement('menuitem');
+ dial.ItemMenuCreateBookmark.label = browser.i18n.getMessage("menuAddBookmark");
+ dial.ItemMenuCreateBookmark.onclick = dial.createBookmark;
+ dial.ItemMenuCreateFolder = document.createElement('menuitem');
+ dial.ItemMenuCreateFolder.label = browser.i18n.getMessage("menuAddFolder");
+ dial.ItemMenuCreateFolder.onclick = dial.createFolder;
+ dial.ItemMenuEdit = document.createElement('menuitem');
+ dial.ItemMenuEdit.label = 'Edit';
+ //dial.ItemMenuEdit.onclick = dial.test;
+ dial.ItemMenuRefresh = document.createElement('menuitem');
+ dial.ItemMenuRefresh.label = 'Refresh';
+ dial.ItemMenuRefresh.label = browser.i18n.getMessage("menuRefreshItem");
+ dial.ItemMenuRefresh.onclick = dial.refreshNode;
+ dial.ItemMenuDelete = document.createElement('menuitem');
+ dial.ItemMenuDelete.label = browser.i18n.getMessage("menuDeleteItem");
+ dial.ItemMenuDelete.onclick = dial.deleteNode;
+ dial.ItemMenu.appendChild(dial.ItemMenuCreateBookmark);
+ dial.ItemMenu.appendChild(dial.ItemMenuCreateFolder);
+ dial.ItemMenu.appendChild(document.createElement('hr'));
+ //dial.ItemMenu.appendChild(dial.ItemMenuEdit);
+ dial.ItemMenu.appendChild(dial.ItemMenuRefresh);
+ dial.ItemMenu.appendChild(dial.ItemMenuDelete);
+ dial.Body.appendChild(dial.ItemMenu);
+}
+
+dial.initGrid = function(name, settings, container){
+ var grid = document.createElement('table');
+ grid.className = name;
+ grid.getLink = function(index){
+ var num_columns = grid.rows[0].cells.length;
+ return grid.rows[Math.floor(index/num_columns)].cells[index % num_columns].childNodes[0];
+ }
+ for(var i=0; i dial.maxpage) dial.page = dial.maxpage;
+ if(dial.page > 1) iBase = (dial.page -1) * maxCells;
+ for(var i = iBase; i', ''));
+ }
+ xmlHttp.send(null);
+}
diff --git a/src/manifest.json b/src/manifest.json
new file mode 100644
index 0000000..fbdec02
--- /dev/null
+++ b/src/manifest.json
@@ -0,0 +1,42 @@
+{
+
+ "manifest_version": 2,
+ "name": "__MSG_extensionName__",
+ "version": "0.0.2",
+
+ "description": "__MSG_extensionDescription__",
+
+ "icons": {
+ "24": "img/24.png",
+ "32": "img/32.png"
+ },
+
+ "permissions": [
+ "storage",
+ "bookmarks",
+ "contextMenus",
+ "tabs",
+ ""
+ ],
+
+ "background": {
+ "scripts": ["js/background.js"]
+ },
+
+ "chrome_url_overrides" : {
+ "newtab": "dial"
+ },
+
+ "options_ui": {
+ "page": "options.html"
+ },
+
+ "applications": {
+ "gecko": {
+ "id": "mat@matmoul.com_quickdial_test_3",
+ "strict_min_version": "52.0"
+ }
+ },
+
+ "default_locale": "en"
+}