experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

migrate to webextension, change to bookmark title for config

+208 -2837
+37 -4
README.md
··· 1 - This is the appvisor add-on. It contains: 1 + # Peek 2 + 3 + Quickly peek at your favorite web pages without breaking your flow. 4 + 5 + Peek lets you choose 10 web pages to open with a keyboard shortcut, without opening a new tab, and able to close with the `escape` key. 6 + 7 + I use this for: 8 + 9 + * Translating text 10 + * See my Github notifications 11 + * Calendar schedule 12 + * Check email periodically instead of having it open all the time 13 + * Stock or cryptocurrency prices 14 + * Slack instances I don't want loaded all the time 15 + * Check the weather 16 + 17 + ## Usage 18 + 19 + * Create up to 10 bookmarks with "peek#" plus the number 0-9 in the title. Eg "My favorite website peek#1". 20 + 21 + * Use the keyboard shortcut `control+shift` plus the number you put in the bookmark title to peek at that URL. 2 22 3 - * A program (lib/main.js). 4 - * A few tests. 5 - * Some meager documentation. 23 + * A new minimal window will open with your chosen URL loaded. 24 + 25 + * Hit the `escape` key to close the window. 26 + 27 + (If no bookmark is configured for an index, Peek will just load about:home.) 28 + 29 + ## TODO 30 + 31 + * ESC doesn't work sometimes 32 + 33 + * test on windows/linux 34 + 35 + * fix window to have a maximum size 36 + 37 + * add feature to long-press links to peek (in pb mode?) 38 +
+36
background.js
··· 1 + browser.commands.onCommand.addListener(function(command) { 2 + if (command.indexOf('toggle-peek') != -1) { 3 + onCommand(command); 4 + } 5 + }); 6 + 7 + async function getURLForCommand(number) { 8 + let bookmarks = await browser.bookmarks.search('peek#' + number); 9 + return bookmarks.length ? bookmarks[0].url : 'about:home'; 10 + } 11 + 12 + async function onCommand(command) { 13 + const height = window.screen.height * 0.75; 14 + const width = window.screen.width * 0.75; 15 + const number = command.split('-')[2]; 16 + const url = await getURLForCommand(number); 17 + let win = await browser.windows.create({ 18 + url: url, 19 + type: 'popup', 20 + allowScriptsToClose: true, 21 + height: height, 22 + width: width, 23 + top: window.screen.height - height / 2, 24 + left: window.screen.width - width / 2 25 + }); 26 + 27 + browser.tabs.onUpdated.addListener((tabId, changeInfo) => { 28 + if (tabId == win.tabs[0].id && 29 + changeInfo.status && 30 + changeInfo.status == 'complete') { 31 + browser.tabs.executeScript(win.tabs[0].id, { 32 + file: '/content-script.js' 33 + }); 34 + } 35 + }); 36 + }
+12
content-script.js
··· 1 + document.onkeydown = function(evt) { 2 + evt = evt || window.event; 3 + var isEscape = false; 4 + if ("key" in evt) { 5 + isEscape = (evt.key == "Escape" || evt.key == "Esc"); 6 + } else { 7 + isEscape = (evt.keyCode == 27); 8 + } 9 + if (isEscape) { 10 + window.close(); 11 + } 12 + };
-10
data/content.js
··· 1 - function sendWindowSize() { 2 - self.port.emit('resize', { 3 - height: window.outerHeight, 4 - width: window.outerWidth 5 - }); 6 - } 7 - 8 - window.addEventListener('resize', sendWindowSize, false); 9 - 10 - sendWindowSize();
-13
data/panel.js
··· 1 - // Convert all links to open in new tab 2 - var matches = window.document.querySelectorAll('a'); 3 - for (var i = 0; i < matches.length; i++) 4 - matches[i].setAttribute('target', '_blank'); 5 - 6 - window.addEventListener('click', function(event) { 7 - self.port.emit('click-link') 8 - /* 9 - var t = event.target 10 - if (t.nodeName == 'A') 11 - self.port.emit('click-link', t.toString()) 12 - */ 13 - }, false)
-2
doc/main.md
··· 1 - The main module is a program that creates a widget. When a user clicks on 2 - the widget, the program loads the mozilla.org website in a new tab.
+5
icons/_head.html
··· 1 + <link rel="icon" type="image/png" href="/iconx/favicon-16x16.png" sizes="16x16"> 2 + <link rel="icon" type="image/png" href="/iconx/favicon-32x32.png" sizes="32x32"> 3 + <link rel="icon" type="image/png" href="/iconx/android-192x192.png" sizes="192x192"> 4 + <link rel="apple-touch-icon" href="/iconx/apple-touch-icon-180x180.png" sizes="180x180"> 5 + <meta name="msapplication-config" content="/iconx/browserconfig.xml">
icons/apple-touch-icon-180x180.png

This is a binary file and will not be displayed.

+13
icons/browserconfig.xml
··· 1 + <?xml version="1.0" encoding="utf-8" ?> 2 + <browserconfig> 3 + <msapplication> 4 + <tile> 5 + <square70x70logo src="/iconx/browserconfig/tile70x70.png" /> 6 + <square150x150logo src="/iconx/browserconfig/tile150x150.png" /> 7 + <wide310x150logo src="/iconx/browserconfig/tile310x150.png" /> 8 + <square310x310logo src="/iconx/browserconfig/tile310x310.png" /> 9 + <tilecolor>transparent</tilecolor> 10 + </tile> 11 + </msapplication> 12 + </browserconfig> 13 +
icons/browserconfig/tile150x150.png

This is a binary file and will not be displayed.

icons/browserconfig/tile310x150.png

This is a binary file and will not be displayed.

icons/browserconfig/tile310x310.png

This is a binary file and will not be displayed.

icons/browserconfig/tile70x70.png

This is a binary file and will not be displayed.

icons/favicon-16x16.png

This is a binary file and will not be displayed.

icons/favicon-32x32.png

This is a binary file and will not be displayed.

icons/favicon.ico

This is a binary file and will not be displayed.

+20
icons/peek.svg
··· 1 + <?xml version="1.0" encoding="UTF-8"?> 2 + <svg width="512px" height="512px" viewBox="0 0 512 512" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 3 + <!-- Generator: Sketch 43.2 (39069) - http://www.bohemiancoding.com/sketch --> 4 + <title>Group 2</title> 5 + <desc>Created with Sketch.</desc> 6 + <defs> 7 + <rect id="path-1" x="0" y="0" width="512" height="512" rx="8"></rect> 8 + </defs> 9 + <g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd"> 10 + <g id="Group-2"> 11 + <mask id="mask-2" fill="white"> 12 + <use xlink:href="#path-1"></use> 13 + </mask> 14 + <use id="Rectangle" fill="#FFF46D" xlink:href="#path-1"></use> 15 + <ellipse id="Oval" stroke="#312929" stroke-width="3" fill="#FBF3F3" mask="url(#mask-2)" cx="256.5" cy="569.5" rx="292.5" ry="244.5"></ellipse> 16 + <ellipse id="Oval-2" fill="#4E6BED" mask="url(#mask-2)" cx="257" cy="555.5" rx="169" ry="171.5"></ellipse> 17 + <ellipse id="Oval-2" fill="#3D4255" mask="url(#mask-2)" cx="256.5" cy="526.5" rx="97.5" ry="96.5"></ellipse> 18 + </g> 19 + </g> 20 + </svg>
icons/pwa-192x192.png

This is a binary file and will not be displayed.

icons/pwa-512x512.png

This is a binary file and will not be displayed.

-110
lib/main.js
··· 1 - var { Hotkey } = require('sdk/hotkeys'), 2 - { Panel } = require('sdk/panel'), 3 - UI = require('sdk/ui'), 4 - { URL } = require('sdk/url'), 5 - Self = require('sdk/self'), 6 - Prefs = require('sdk/preferences/service'), 7 - AddonPrefs = require('sdk/simple-prefs'), 8 - TAB_PREF = 'browser.tabs.loadDivertedInBackground', 9 - COMBO_PREFIX = 'alt-shift-', 10 - lastPrefVal = null, 11 - hotkeys = [], 12 - windowHeight = null, 13 - windowWidth = null, 14 - BUTTON_TITLE = 'P' 15 - 16 - let prefsPanel = Panel({ 17 - contentURL: Self.data.url('prefs.html') 18 - }) 19 - 20 - let button = UI.ActionButton({ 21 - id: 'PeekPreferences', 22 - label: 'Peek Preferences', 23 - //contentURL: 'data:text/html,' + BUTTON_TITLE, 24 - icon: 'data:image/gif;base64,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', 25 - onClick: function() { 26 - prefsPanel.show() 27 - } 28 - }) 29 - 30 - // initialize 31 - var savedText = AddonPrefs.prefs['urls'] 32 - processText(savedText) 33 - prefsPanel.port.emit('text', savedText) 34 - 35 - prefsPanel.port.on('text', function(text) { 36 - AddonPrefs.prefs['urls'] = text 37 - processText(text) 38 - prefsPanel.hide() 39 - }) 40 - 41 - function processText(text) { 42 - var parts = text.split('\n'), 43 - urls = [] 44 - 45 - parts.forEach(function(part) { 46 - try { 47 - var url = URL(part) 48 - urls.push(part) 49 - } catch(ex) { 50 - console.log('not a url', part) 51 - } 52 - }) 53 - 54 - addHotkeys(urls) 55 - } 56 - 57 - function addHotkeys(urls) { 58 - hotkeys.forEach(function(entry) { 59 - entry.hotkey.destroy() 60 - entry.panel.destroy() 61 - }) 62 - 63 - urls.forEach(function(url, i) { 64 - var panel = getPanel(url) 65 - hotkeys.push({ 66 - hotkey: Hotkey({ 67 - combo: COMBO_PREFIX + (i + 1), 68 - onPress: function() { 69 - panel.show() 70 - } 71 - }), 72 - panel: panel 73 - }) 74 - }) 75 - } 76 - 77 - // Create a new panel for the given URL. 78 - // The panel is hidden by default. 79 - function getPanel(url) { 80 - var shrink = 0.9, 81 - {height, width} = getWindowDimensions() 82 - let panel = Panel({ 83 - contentURL: url || 'about:blank', 84 - height: height * shrink, 85 - width: width * shrink, 86 - contentScriptFile: Self.data.url('panel.js'), 87 - contentScriptWhen: 'ready', 88 - onShow: function() { 89 - lastPrefVal = Prefs.get(TAB_PREF) 90 - if (lastPrefVal === false) 91 - Prefs.set(TAB_PREF, true) 92 - }, 93 - onHide: function() { 94 - if (lastPrefVal !== undefined && lastPrefVal != Prefs.get(TAB_PREF)) 95 - Prefs.set(TAB_PREF, lastPrefVal) 96 - panel.destroy() 97 - } 98 - }) 99 - panel.on('click-link', function() { 100 - panel.hide() 101 - }) 102 - return panel; 103 - } 104 - 105 - function getWindowDimensions() { 106 - var { viewFor } = require("sdk/view/core") 107 - var browserWindow = require('sdk/windows').browserWindows.activeWindow 108 - var domWindow = viewFor(browserWindow) 109 - return { height: domWindow.outerHeight, width: domWindow.outerWidth } 110 - }
-380
lib/panel-custom-frame.js
··· 1 - /* This Source Code Form is subject to the terms of the Mozilla Public 2 - * License, v. 2.0. If a copy of the MPL was not distributed with this 3 - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 - 5 - "use strict"; 6 - 7 - if (!require("api-utils/xul-app").is("Firefox")) { 8 - throw new Error([ 9 - "The panel module currently supports only Firefox. In the future ", 10 - "we would like it to support other applications, however. Please see ", 11 - "https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps ", 12 - "for more information." 13 - ].join("")); 14 - } 15 - 16 - const { Cc, Ci } = require("chrome"); 17 - 18 - const { validateOptions: valid } = require("api-utils/api-utils"); 19 - const { Symbiont } = require("api-utils/content"); 20 - const { EventEmitter } = require('api-utils/events'); 21 - const timer = require("api-utils/timer"); 22 - const runtime = require("api-utils/runtime"); 23 - 24 - const windowMediator = Cc['@mozilla.org/appshell/window-mediator;1']. 25 - getService(Ci.nsIWindowMediator); 26 - 27 - const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", 28 - ON_SHOW = 'popupshown', 29 - ON_HIDE = 'popuphidden', 30 - validNumber = { is: ['number', 'undefined', 'null'] }; 31 - 32 - /** 33 - * Emits show and hide events. 34 - */ 35 - const Panel = Symbiont.resolve({ 36 - constructor: '_init', 37 - _onInit: '_onSymbiontInit', 38 - destroy: '_symbiontDestructor', 39 - _documentUnload: '_workerDocumentUnload' 40 - }).compose({ 41 - _frame: Symbiont.required, 42 - _init: Symbiont.required, 43 - _onSymbiontInit: Symbiont.required, 44 - _symbiontDestructor: Symbiont.required, 45 - _emit: Symbiont.required, 46 - _asyncEmit: Symbiont.required, 47 - on: Symbiont.required, 48 - removeListener: Symbiont.required, 49 - 50 - _inited: false, 51 - 52 - /** 53 - * If set to `true` frame loaders between xul panel frame and 54 - * hidden frame are swapped. If set to `false` frame loaders are 55 - * set back to normal. Setting the value that was already set will 56 - * have no effect. 57 - */ 58 - set _frameLoadersSwapped(value) { 59 - if (this.__frameLoadersSwapped == value) return; 60 - console.log('swapping fls, frame: ', this._frame); 61 - //console.log('uri:', this._frame.currentURI.spec); 62 - this._frame.QueryInterface(Ci.nsIFrameLoaderOwner) 63 - .swapFrameLoaders(this._viewFrame); 64 - this.__frameLoadersSwapped = value; 65 - }, 66 - __frameLoadersSwapped: false, 67 - 68 - constructor: function Panel(options) { 69 - this._onShow = this._onShow.bind(this); 70 - this._onHide = this._onHide.bind(this); 71 - this.on('inited', this._onSymbiontInit.bind(this)); 72 - 73 - options = options || {}; 74 - if ('onShow' in options) 75 - this.on('show', options.onShow); 76 - if ('onHide' in options) 77 - this.on('hide', options.onHide); 78 - if ('width' in options) 79 - this.width = options.width; 80 - if ('height' in options) 81 - this.height = options.height; 82 - if ('contentURL' in options) 83 - this.contentURL = options.contentURL; 84 - 85 - this._init(options); 86 - }, 87 - _destructor: function _destructor() { 88 - this.hide(); 89 - this._removeAllListeners('show'); 90 - // defer cleanup to be performed after panel gets hidden 91 - this._xulPanel = null; 92 - this._symbiontDestructor(this); 93 - this._removeAllListeners(); 94 - }, 95 - destroy: function destroy() { 96 - this._destructor(); 97 - }, 98 - /* Public API: Panel.width */ 99 - get width() this._width, 100 - set width(value) 101 - this._width = valid({ $: value }, { $: validNumber }).$ || this._width, 102 - _width: 320, 103 - /* Public API: Panel.height */ 104 - get height() this._height, 105 - set height(value) 106 - this._height = valid({ $: value }, { $: validNumber }).$ || this._height, 107 - _height: 240, 108 - 109 - get frame() this._frame, 110 - set frame(value) { 111 - console.log('set frame(): ', value); 112 - this._frame = value; 113 - }, 114 - 115 - /* Public API: Panel.isShowing */ 116 - get isShowing() !!this._xulPanel && this._xulPanel.state == "open", 117 - 118 - /* Public API: Panel.show */ 119 - show: function show(anchor) { 120 - anchor = anchor || null; 121 - let document = getWindow(anchor).document; 122 - let xulPanel = this._xulPanel; 123 - if (!xulPanel) { 124 - xulPanel = this._xulPanel = document.createElementNS(XUL_NS, 'panel'); 125 - xulPanel.setAttribute("type", "arrow"); 126 - 127 - // One anonymous node has a big padding that doesn't work well with 128 - // Jetpack, as we would like to display an iframe that completely fills 129 - // the panel. 130 - // -> Use a XBL wrapper with inner stylesheet to remove this padding. 131 - let css = ".panel-inner-arrowcontent, .panel-arrowcontent {padding: 0;}"; 132 - let originalXBL = "chrome://global/content/bindings/popup.xml#arrowpanel"; 133 - let binding = 134 - '<bindings xmlns="http://www.mozilla.org/xbl">' + 135 - '<binding id="id" extends="' + originalXBL + '">' + 136 - '<resources>' + 137 - '<stylesheet src="data:text/css,' + 138 - document.defaultView.encodeURIComponent(css) + '"/>' + 139 - '</resources>' + 140 - '</binding>' + 141 - '</bindings>'; 142 - xulPanel.style.MozBinding = 'url("data:text/xml,' + 143 - document.defaultView.encodeURIComponent(binding) + '")'; 144 - 145 - let frame = document.createElementNS(XUL_NS, 'iframe'); 146 - frame.setAttribute('type', 'content'); 147 - frame.setAttribute('flex', '1'); 148 - frame.setAttribute('transparent', 'transparent'); 149 - if (runtime.OS === "Darwin") { 150 - frame.style.borderRadius = "6px"; 151 - frame.style.padding = "1px"; 152 - } 153 - 154 - // Load an empty document in order to have an immediatly loaded iframe, 155 - // so swapFrameLoaders is going to work without having to wait for load. 156 - frame.setAttribute("src","data:,"); 157 - 158 - xulPanel.appendChild(frame); 159 - document.getElementById("mainPopupSet").appendChild(xulPanel); 160 - } 161 - let { width, height } = this, x, y, position; 162 - 163 - if (!anchor) { 164 - // Open the popup in the middle of the window. 165 - x = document.documentElement.clientWidth / 2 - width / 2; 166 - y = document.documentElement.clientHeight / 2 - height / 2; 167 - position = null; 168 - } 169 - else { 170 - // Open the popup by the anchor. 171 - let rect = anchor.getBoundingClientRect(); 172 - 173 - let window = anchor.ownerDocument.defaultView; 174 - 175 - let zoom = window.mozScreenPixelsPerCSSPixel; 176 - let screenX = rect.left + window.mozInnerScreenX * zoom; 177 - let screenY = rect.top + window.mozInnerScreenY * zoom; 178 - 179 - // Set up the vertical position of the popup relative to the anchor 180 - // (always display the arrow on anchor center) 181 - let horizontal, vertical; 182 - if (screenY > window.screen.availHeight / 2 + height) 183 - vertical = "top"; 184 - else 185 - vertical = "bottom"; 186 - 187 - if (screenY > window.screen.availWidth / 2 + width) 188 - horizontal = "left"; 189 - else 190 - horizontal = "right"; 191 - 192 - let verticalInverse = vertical == "top" ? "bottom" : "top"; 193 - position = vertical + "center " + verticalInverse + horizontal; 194 - 195 - // Allow panel to flip itself if the panel can't be displayed at the 196 - // specified position (useful if we compute a bad position or if the 197 - // user moves the window and panel remains visible) 198 - xulPanel.setAttribute("flip","both"); 199 - } 200 - 201 - // Resize the iframe instead of using panel.sizeTo 202 - // because sizeTo doesn't work with arrow panels 203 - xulPanel.firstChild.style.width = width + "px"; 204 - xulPanel.firstChild.style.height = height + "px"; 205 - 206 - // Wait for the XBL binding to be constructed 207 - function waitForBinding() { 208 - if (!xulPanel.openPopup) { 209 - timer.setTimeout(waitForBinding, 50); 210 - return; 211 - } 212 - xulPanel.openPopup(anchor, position, x, y); 213 - } 214 - waitForBinding(); 215 - 216 - return this._public; 217 - }, 218 - /* Public API: Panel.hide */ 219 - hide: function hide() { 220 - // The popuphiding handler takes care of swapping back the frame loaders 221 - // and removing the XUL panel from the application window, we just have to 222 - // trigger it by hiding the popup. 223 - // XXX Sometimes I get "TypeError: xulPanel.hidePopup is not a function" 224 - // when quitting the host application while a panel is visible. To suppress 225 - // them, this now checks for "hidePopup" in xulPanel before calling it. 226 - // It's not clear if there's an actual issue or the error is just normal. 227 - let xulPanel = this._xulPanel; 228 - if (xulPanel && "hidePopup" in xulPanel) 229 - xulPanel.hidePopup(); 230 - return this._public; 231 - }, 232 - 233 - /* Public API: Panel.resize */ 234 - resize: function resize(width, height) { 235 - this.width = width; 236 - this.height = height; 237 - // Resize the iframe instead of using panel.sizeTo 238 - // because sizeTo doesn't work with arrow panels 239 - let xulPanel = this._xulPanel; 240 - if (xulPanel) { 241 - xulPanel.firstChild.style.width = width + "px"; 242 - xulPanel.firstChild.style.height = height + "px"; 243 - } 244 - }, 245 - 246 - // While the panel is visible, this is the XUL <panel> we use to display it. 247 - // Otherwise, it's null. 248 - get _xulPanel() this.__xulPanel, 249 - set _xulPanel(value) { 250 - let xulPanel = this.__xulPanel; 251 - if (value === xulPanel) return; 252 - if (xulPanel) { 253 - xulPanel.removeEventListener(ON_HIDE, this._onHide, false); 254 - xulPanel.removeEventListener(ON_SHOW, this._onShow, false); 255 - xulPanel.parentNode.removeChild(xulPanel); 256 - } 257 - if (value) { 258 - value.addEventListener(ON_HIDE, this._onHide, false); 259 - value.addEventListener(ON_SHOW, this._onShow, false); 260 - } 261 - this.__xulPanel = value; 262 - }, 263 - __xulPanel: null, 264 - get _viewFrame() this.__xulPanel.children[0], 265 - /** 266 - * When the XUL panel becomes hidden, we swap frame loaders back to move 267 - * the content of the panel to the hidden frame & remove panel element. 268 - */ 269 - _onHide: function _onHide() { 270 - try { 271 - this._frameLoadersSwapped = false; 272 - this._xulPanel = null; 273 - this._emit('hide'); 274 - } catch(e) { 275 - this._emit('error', e); 276 - } 277 - }, 278 - /** 279 - * When the XUL panel becomes shown, we swap frame loaders between panel 280 - * frame and hidden frame to preserve state of the content dom. 281 - */ 282 - _onShow: function _onShow() { 283 - try { 284 - if (!this._inited) { // defer if not initialized yet 285 - this.on('inited', this._onShow.bind(this)); 286 - } else { 287 - console.log('_onShow(): frame', typeof this._frame); 288 - //console.log('_onShow(): ', this._frame.currentURI.spec); 289 - //this._frameLoadersSwapped.bind(this); 290 - this._frameLoadersSwapped = true; 291 - 292 - // Retrieve computed text color style in order to apply to the iframe 293 - // document. As MacOS background is dark gray, we need to use skin's 294 - // text color. 295 - let win = this._xulPanel.ownerDocument.defaultView; 296 - let node = win.document.getAnonymousElementByAttribute(this._xulPanel, 297 - "class", "panel-inner-arrowcontent"); 298 - let textColor = win.getComputedStyle(node).getPropertyValue("color"); 299 - let doc = this._xulPanel.firstChild.contentDocument; 300 - let style = doc.createElement("style"); 301 - style.textContent = "body { color: " + textColor + "; }"; 302 - let container = doc.head ? doc.head : doc.documentElement; 303 - 304 - if (container.firstChild) 305 - container.insertBefore(style, container.firstChild); 306 - else 307 - container.appendChild(style); 308 - 309 - this._emit('show'); 310 - } 311 - } catch(e) { 312 - this._emit('error', e); 313 - } 314 - }, 315 - /** 316 - * Notification that panel was fully initialized. 317 - */ 318 - _onInit: function _onInit() { 319 - this._inited = true; 320 - 321 - // Avoid panel document from resizing the browser window 322 - // New platform capability added through bug 635673 323 - if ("allowWindowControl" in this._frame.docShell) 324 - this._frame.docShell.allowWindowControl = false; 325 - 326 - // perform all deferred tasks like initSymbiont, show, hide ... 327 - // TODO: We're publicly exposing a private event here; this 328 - // 'inited' event should really be made private, somehow. 329 - this._emit('inited'); 330 - }, 331 - 332 - // Catch document unload event in order to rebind load event listener with 333 - // Symbiont._initFrame if Worker._documentUnload destroyed the worker 334 - _documentUnload: function(subject, topic, data) { 335 - if (this._workerDocumentUnload(subject, topic, data)) { 336 - this._initFrame(this._frame); 337 - return true; 338 - } 339 - return false; 340 - } 341 - }); 342 - exports.Panel = function(options) Panel(options) 343 - exports.Panel.prototype = Panel.prototype; 344 - 345 - function getWindow(anchor) { 346 - let window; 347 - 348 - if (anchor) { 349 - let anchorWindow = anchor.ownerDocument.defaultView.top; 350 - let anchorDocument = anchorWindow.document; 351 - 352 - let enumerator = windowMediator.getEnumerator("navigator:browser"); 353 - while (enumerator.hasMoreElements()) { 354 - let enumWindow = enumerator.getNext(); 355 - 356 - // Check if the anchor is in this browser window. 357 - if (enumWindow == anchorWindow) { 358 - window = anchorWindow; 359 - break; 360 - } 361 - 362 - // Check if the anchor is in a browser tab in this browser window. 363 - let browser = enumWindow.gBrowser.getBrowserForDocument(anchorDocument); 364 - if (browser) { 365 - window = enumWindow; 366 - break; 367 - } 368 - 369 - // Look in other subdocuments (sidebar, etc.)? 370 - } 371 - } 372 - 373 - // If we didn't find the anchor's window (or we have no anchor), 374 - // return the most recent browser window. 375 - if (!window) 376 - window = windowMediator.getMostRecentWindow("navigator:browser"); 377 - 378 - return window; 379 - } 380 -
-2270
lib/places.js
··· 1 - /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 - /* vim:set ts=2 sw=2 sts=2 et: */ 3 - /* ***** BEGIN LICENSE BLOCK ***** 4 - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 5 - * 6 - * The contents of this file are subject to the Mozilla Public License Version 7 - * 1.1 (the "License"); you may not use this file except in compliance with 8 - * the License. You may obtain a copy of the License at 9 - * http://www.mozilla.org/MPL/ 10 - * 11 - * Software distributed under the License is distributed on an "AS IS" basis, 12 - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 - * for the specific language governing rights and limitations under the 14 - * License. 15 - * 16 - * The Original Code is Jetpack. 17 - * 18 - * The Initial Developer of the Original Code is the Mozilla Foundation. 19 - * Portions created by the Initial Developer are Copyright (C) 2010 20 - * the Initial Developer. All Rights Reserved. 21 - * 22 - * Contributor(s): 23 - * Marco Bonardo <mak77@bonardo.net> (Original Author) 24 - * 25 - * Alternatively, the contents of this file may be used under the terms of 26 - * either the GNU General Public License Version 2 or later (the "GPL"), or 27 - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 28 - * in which case the provisions of the GPL or the LGPL are applicable instead 29 - * of those above. If you wish to allow use of your version of this file only 30 - * under the terms of either the GPL or the LGPL, and not to allow others to 31 - * use your version of this file under the terms of the MPL, indicate your 32 - * decision by deleting the provisions above and replace them with the notice 33 - * and other provisions required by the GPL or the LGPL. If you do not delete 34 - * the provisions above, a recipient may use your version of this file under 35 - * the terms of any one of the MPL, the GPL or the LGPL. 36 - * 37 - * ***** END LICENSE BLOCK ***** */ 38 - 39 - const {Cc, Ci, Cr, Cu} = require("chrome"); 40 - 41 - // PlacesQuery is currently included at the bottom of this file, 42 - // to ease distribution by not tying Jetpack's usage of it to a 43 - // particular Firefox version. 44 - //Cu.import("resource://gre/modules/PlacesQuery.jsm", this); 45 - Cu.import("resource://gre/modules/PlacesUtils.jsm", this); 46 - 47 - const apiUtils = require("api-utils"); 48 - const collection = require("collection"); 49 - const errors = require("errors"); 50 - 51 - 52 - // Main search function. 53 - exports.search = (new PlacesHandler()).search; 54 - 55 - 56 - // Shortcut helper to search visited places. 57 - exports.history = new PlacesHandler({ visited: {} }); 58 - // Shortcut helper to search bookmarked places. 59 - exports.bookmarks = new PlacesHandler({ bookmarked: {} }); 60 - 61 - 62 - // Add bookmark root folder shortcuts. 63 - exports.bookmarks.unfiled = PlacesUtils.unfiledBookmarksFolderId; 64 - exports.bookmarks.toolbar = PlacesUtils.toolbarFolderId; 65 - exports.bookmarks.menu = PlacesUtils.bookmarksMenuFolderId; 66 - 67 - 68 - // Method for creating a bookmark. Can take an options object or an array of 69 - // options objects to create bookmarks in batch. 70 - exports.bookmarks.create = function PF_create(aOptions) { 71 - let options = validateBookmarkInfo(aOptions, true); 72 - 73 - let bs = PlacesUtils.bookmarks; 74 - 75 - // Create the bookmark item. 76 - try { 77 - switch(options.type) { 78 - case "bookmark": 79 - options._itemId = 80 - bs.insertBookmark(options.folder, 81 - PlacesUtils._uri(options.location), 82 - options.position, 83 - options.title); 84 - 85 - if (options.tags.length > 0) { 86 - PlacesUtils.tagging.tagURI(PlacesUtils._uri(options.location), 87 - options.tags); 88 - } 89 - break; 90 - case "folder": 91 - options._itemId = 92 - PlacesUtils.bookmarks.createFolder(options.folder, 93 - options.title, 94 - options.position); 95 - break; 96 - case "separator": 97 - options._itemId = 98 - PlacesUtils.bookmarks.insertSeparator(options.folder, 99 - options.position); 100 - } 101 - 102 - /* 103 - if (options.annotations) { 104 - PlacesUtils.setAnnotationsForItem(options._itemId, 105 - options.annotations); 106 - } 107 - */ 108 - } 109 - catch (err) { 110 - console.exception("Failed to create new bookmark. " + err); 111 - } 112 - 113 - if (options.onCreate) { 114 - safeCallback(undefined, options.onCreate, options); 115 - } 116 - }; 117 - 118 - 119 - /** 120 - * Wrapper for safely calling user-callback functions. 121 - * TODO: file a bug for getting this into api-utils. 122 - */ 123 - function safeCallback(aArgument, aCallbackFunc, aCallbackScope) { 124 - if (aCallbackFunc) { 125 - require("timer").setTimeout(function() { 126 - try { 127 - if (aCallbackScope) 128 - aCallbackFunc.call(aCallbackScope, aArgument); 129 - else 130 - aCallbackFunc.call(exports, aArgument); // safe "this". 131 - } 132 - catch (err) { 133 - console.exception(err); 134 - } 135 - }, 0); 136 - } 137 - } 138 - 139 - 140 - /** 141 - * This is the basic exposed object for searching. 142 - * The caller will get access to it via an alias such as "bookmarks" 143 - * or "history" and call it's .search() method. 144 - */ 145 - function PlacesHandler(helperOptions) { 146 - this.search = function PH_createNewFilter(userOptions) { 147 - // Merge helper configuration to user configurations. 148 - let options = validateAndMergeConfigs(userOptions, helperOptions); 149 - // Create and return a PlacesSearch. 150 - return new PlacesSearch(options); 151 - } 152 - } 153 - PlacesHandler.prototype = {} 154 - 155 - 156 - /** 157 - * apiUtils method does not support "date" type. 158 - */ 159 - function checkType(entry, type) { 160 - switch (type) { 161 - case "undefined": 162 - return entry === undefined; 163 - case "null": 164 - return entry === null; 165 - case "date": 166 - return Object.prototype.toString.call(entry) === "[object Date]"; 167 - case "array": 168 - return Object.prototype.toString.call(entry) === "[object Array]"; 169 - default: 170 - return typeof(entry) == type; 171 - } 172 - } 173 - 174 - /** 175 - * apiUtils method does not support things like "array of optional string" or 176 - * "array of positive optional number". 177 - */ 178 - function checkArrayElementsType(array, type, allowOptionalElement) { 179 - let arrayIsValid = true; 180 - array.every(function(elm) { 181 - if (allowOptionalElement && (elm === undefined || elm === null)) 182 - return true; 183 - return arrayIsValid = checkType(elm, type); 184 - }); 185 - return arrayIsValid; 186 - } 187 - 188 - /** 189 - * Take caller-supplied options and merge them with a set of default 190 - * options. 191 - */ 192 - function validateAndMergeConfigs(userOptions, additionalOptions) { 193 - userOptions = apiUtils.validateOptions(userOptions, { 194 - phrase: { 195 - map: function(v) v.toString(), 196 - is: ["undefined", "string"], 197 - ok: function(v) !v || v.length > 0, 198 - msg: "Provided phrase must be a non-empty string." 199 - }, 200 - host: { 201 - map: function(v) v.toString(), 202 - is: ["undefined", "string"], 203 - ok: function(v) !v || v.length > 0, 204 - msg: "Provided host must be a non-empty string." 205 - }, 206 - uri: { 207 - map: function(v) v.toString(), 208 - is: ["undefined", "string"], 209 - ok: function(v) !v || v.length > 0, 210 - msg: "Provided uri must be a non empty string." 211 - }, 212 - annotated: { 213 - is: ["undefined", "array"], 214 - ok: function (v) !v || v.length > 0, 215 - msg: "Required annotations must be a valid array of strings." 216 - }, 217 - bookmarked: apiUtils.validateOptions(userOptions.bookmarked, { 218 - is: ["undefined", "boolean"], 219 - ok: function (v) !v || apiUtils.validateOptions(userOptions.bookmarked, { 220 - tags: { 221 - is: ["undefined", "array"], 222 - ok: function(v) !v || (v.length > 0 && checkArrayElementsType(v, "string")), 223 - msg: "Tags must be a valid array of strings." 224 - }, 225 - folder: { 226 - is: ["undefined", "number"], 227 - ok: function(v) !v || v > 0, 228 - msg: "Folder id must be a positive number." 229 - }, 230 - position: { 231 - is: ["undefined", "number"], 232 - ok: function(v) !v || v > 0, 233 - msg: "Position must be a positive number." 234 - }, 235 - id: { 236 - is: ["undefined", "number"], 237 - ok: function(v) !v || v > 0, 238 - msg: "Bookmark id must be a positive number." 239 - }, 240 - created: { 241 - is: ["undefined", "array"], 242 - ok: function(v) !v || (v.length > 0 && checkArrayElementsType(v, "date", true)), 243 - msg: "Bookmark creation times must be an array of two optional Date objects." 244 - }, 245 - modified: { 246 - is: ["undefined", "array"], 247 - ok: function(v) !v || (v.length > 0 && checkArrayElementsType(v, "date", true)), 248 - msg: "Bookmark modification times must be an array of two optional Date objects." 249 - } 250 - }), 251 - msg: "Bookmarked configuration is incorrect." 252 - }), 253 - visited: apiUtils.validateOptions(userOptions.visited, { 254 - is: ["undefined", "object", "boolean"], 255 - ok: function (v) !v || apiUtils.validateOptions(userOptions.visited, { 256 - count: { 257 - is: ["undefined", "array"], 258 - ok: function(v) !v || (v.length > 0 && checkArrayElementsType(v, "number", true)), 259 - msg: "Visit count must be an array of two optional numbers." 260 - }, 261 - transitions: { 262 - is: ["undefined", "array"], 263 - ok: function(v) !v || (v.length > 0 && checkArrayElementsType(v, "number", true)), 264 - msg: "Transitions must be an array of valid transition values." 265 - }, 266 - when: { 267 - is: ["undefined", "array"], 268 - ok: function(v) !v || (v.length > 0 && checkArrayElementsType(v, "date", true)), 269 - msg: "Visit times must be an array of two optional Date objects." 270 - }, 271 - includeAllVisits: { 272 - is: ["undefined", "boolean"] 273 - } 274 - }), 275 - msg: "Visited configuration is incorrect." 276 - }), 277 - sortBy: { 278 - is: ["undefined", "string"], 279 - ok: function(v) !v || ["none", "title", "time", "uri", "accessCount", 280 - "lastModified", "frecency"].indexOf(v) != -1, 281 - msg: "Sorting must define an acceptable string for by." 282 - }, 283 - sortDir: { 284 - is: ["undefined", "string"], 285 - ok: function(v) !v || ["asc", "desc"].indexOf(v) != -1, 286 - msg: "sorting must define an acceptable direction." 287 - }, 288 - limit: { 289 - is: ["undefined", "number"], 290 - ok: function (v) !v || v > 0, 291 - msg: "Can limit only on positive number of results." 292 - }, 293 - onResult: { 294 - is: ["undefined", "function"] 295 - }, 296 - onComplete: { 297 - is: ["undefined", "function"] 298 - }, 299 - onChange: { 300 - is: ["undefined", "function"] 301 - }, 302 - onRemove: { 303 - is: ["undefined", "function"] 304 - } 305 - }); 306 - 307 - // This will only contain visited or bookmarked properties. 308 - additionalOptions = apiUtils.validateOptions(additionalOptions, { 309 - visited: { 310 - is: ["undefined", "object", "boolean"] 311 - }, 312 - bookmarked: { 313 - is: ["undefined", "object", "boolean"] 314 - }, 315 - }); 316 - 317 - // Do the merge. 318 - for (let prop in additionalOptions) { 319 - if (!userOptions[prop]) 320 - userOptions[prop] = additionalOptions[prop]; 321 - } 322 - 323 - return userOptions; 324 - } 325 - 326 - 327 - // Defaults for bookmark properties. 328 - let bookmarkDefaults = { 329 - title: null, 330 - type: "bookmark", 331 - folder: PlacesUtils.unfiledBookmarksFolderId, 332 - position: PlacesUtils.bookmarks.DEFAULT_INDEX, 333 - tags: [] 334 - }; 335 - 336 - function validateBookmarkInfo(aOptions, aProvideDefaults) { 337 - aOptions = apiUtils.validateOptions(aOptions, { 338 - location: { 339 - map: function(v) v.toString(), 340 - is: ["undefined", "string"], 341 - ok: function(v) !v || v.length > 0, 342 - msg: "Bookmark location must be a non empty string." 343 - }, 344 - title: { 345 - map: function(v) v.toString(), 346 - is: ["undefined", "string"], 347 - ok: function(v) !v || v.length > 0 348 - }, 349 - folder: { 350 - is: ["undefined", "number"], 351 - ok: function(v) !v || v > 0, 352 - msg: "Required containing folder id must be a positive number." 353 - }, 354 - position: { 355 - is: ["undefined", "number"], 356 - ok: function(v) !v || v >= 0, 357 - msg: "Bookmark position, if present, must be a non-negative number." 358 - }, 359 - tags: { 360 - is: ["undefined", "array"], 361 - ok: function(v) !v || (v.length > 0 && checkArrayElementsType(v, "string")), 362 - msg: "Tags must be a valid array of strings." 363 - }, 364 - //annotations: validateAnnotations, 365 - type: { 366 - is: ["undefined", "string"], 367 - ok: function(v) !v || ["bookmark", "separator", "folder"].indexOf(v) != -1, 368 - msg: "Bookmark type must be one of: bookmark, separator or folder." 369 - }, 370 - onCreate: { 371 - is: ["undefined", "function"], 372 - } 373 - }); 374 - 375 - if (aProvideDefaults && !aOptions.type) { 376 - function checkProps(aObject, aDefaultObject) { 377 - for (let prop in aDefaultObject) { 378 - if (!(prop in aObject)) 379 - aObject[prop] = aDefaultObject[prop]; 380 - else if (typeof(aObject[prop]) == "object") 381 - checkProps(aObject[prop], aDefaultObject[prop]) 382 - } 383 - } 384 - checkProps(aOptions, bookmarkDefaults); 385 - 386 - if (aOptions.type == "bookmark" && 387 - !("location" in aOptions) || aOptions.title.length == 0) 388 - throw new Error("Must provide a valid location for the bookmark."); 389 - 390 - } 391 - return aOptions; 392 - } 393 - 394 - let validateAnnotations = { 395 - is: ["undefined", "array"], 396 - ok: function(v) { 397 - return !v || (v.length > 0 && 398 - checkArrayElementsType(v, "object") && 399 - v.every(function(a) a.name && a.value)) 400 - }, 401 - msg: "Annotations must be a valid array of { name: '', value: '' } objects." 402 - }; 403 - 404 - 405 - /** 406 - * An object that is returned by .search() and can be used to act on 407 - * entries. 408 - */ 409 - function PlacesSearch(aOptions) { 410 - let query = new PlacesQuery(aOptions); 411 - 412 - this.change = function PS_change(aChangeOptions) { 413 - // Allow editing of bookmark properties if a bookmark query. 414 - if ("bookmarked" in aOptions) { 415 - validateBookmarkInfo(aChangeOptions); 416 - } 417 - else { 418 - throw new Error("Editing of history is not supported at this time."); 419 - } 420 - /* 421 - // Otherwise only validate annotation properties 422 - else { 423 - aChangeOptions = apiUtils.validateOptions(aChangeOptions, { 424 - annotations: validateAnnotations 425 - }); 426 - } 427 - */ 428 - 429 - // When the owning query has finished, pass results to the walker that 430 - // will make the changes, re-query to update the results, and then call 431 - // the user's callback. 432 - function changeCallback() { 433 - new QueryExecutor(query, null, aOptions.onChange, aOptions); 434 - } 435 - 436 - let walker = new Walker(changeCallback, {}, function(result) { 437 - let txns = []; 438 - if ("bookmarked" in aOptions) { 439 - let bs = PlacesUtils.bookmarks; 440 - // location 441 - if (aChangeOptions.location) 442 - txns.push(new PlacesEditBookmarkURITransaction(result._itemId, 443 - PlacesUtils._uri(aChangeOptions.location))); 444 - // title 445 - if (aChangeOptions.title) { 446 - txns.push(new PlacesEditItemTitleTransaction(result._itemId, aChangeOptions.title)); 447 - } 448 - // folder & position 449 - if (aChangeOptions.folder != undefined || aChangeOptions.position != undefined) { 450 - let position = (aChangeOptions.position === undefined) ? -1 : aChangeOptions.position; 451 - txns.push(new PlacesMoveItemTransaction(result._itemId, 452 - aChangeOptions.folder || result.folder, 453 - position)); 454 - } 455 - // tags 456 - if (aChangeOptions.tags) { 457 - let uri = PlacesUtils._uri(aChangeOptions.location || result.location); 458 - txns.push(new PlacesTagURITransaction(uri, aChangeOptions.tags)); 459 - } 460 - /* 461 - // annotations 462 - if (aChangeOptions.annotations) { 463 - aChangeOptions.annotations.forEach(function(anno) { 464 - txns.push(new PlacesSetItemAnnotationTransaction(result._itemId, anno)); 465 - }); 466 - } 467 - */ 468 - } 469 - else if (aChangeOptions.annotations) { 470 - aChangeOptions.annotations.forEach(function(anno) { 471 - txns.push(new PlacesSetPageAnnotationTransaction(result.location, anno)); 472 - }); 473 - } 474 - 475 - (new PlacesAggregatedTransaction("Changing " + result.title, txns)).doTransaction(); 476 - }); 477 - new QueryExecutor(query, null, walker.run, walker); 478 - }; 479 - 480 - this.remove = function PS_remove() { 481 - if (!("bookmarked" in aOptions)) { 482 - throw new Error("Removal of history is not supported at this time."); 483 - } 484 - 485 - // When the owning query has finished, pass results to the walker that 486 - // will make the changes, re-query to update the results, and then call 487 - // the user's callback. 488 - function removeCallback() { 489 - new QueryExecutor(query, null, aOptions.onRemove, aOptions); 490 - } 491 - 492 - // When the owning query has finished, pass results to the walker that 493 - // will remove them from the database. 494 - let walker = new Walker(removeCallback, aOptions, function(result) { 495 - (new PlacesRemoveItemTransaction(result._itemId)).doTransaction(); 496 - }); 497 - new QueryExecutor(query, null, walker.run, walker); 498 - }; 499 - 500 - if (aOptions.onResult || aOptions.onComplete) 501 - new QueryExecutor(query, aOptions.onResult, aOptions.onComplete, aOptions); 502 - } 503 - PlacesSearch.prototype = {} 504 - 505 - 506 - /** 507 - * Executes a query and receives results from it. 508 - */ 509 - function QueryExecutor(aPlacesQuery, aOnResult, aOnComplete, aScope) { 510 - this.onResult = aOnResult; 511 - this.onComplete = aOnComplete; 512 - this.scope = aScope; 513 - this.results = []; 514 - 515 - aPlacesQuery.execute(this.resultsCallback, this); 516 - } 517 - 518 - QueryExecutor.prototype = { 519 - resultsCallback: function QX_resultsCallback(aResult) { 520 - // Query has finished returning results. 521 - if (!aResult && this.onComplete) { 522 - this.scope.results = this.results; 523 - safeCallback(null, this.onComplete, this.scope); 524 - } 525 - 526 - // There are results but we don't want to notify caller before completion. 527 - else if (this.onComplete) 528 - this.results.push(new Place(aResult)); 529 - 530 - // Send result to the caller. 531 - if (this.onResult) 532 - safeCallback(new Place(aResult), this.onResult, this.scope); 533 - } 534 - } 535 - 536 - 537 - /** 538 - * Walks through all results from an owning query that are passed to run, 539 - * then calls aUserCallback in the scope of aUserScope. It will also set 540 - * the results of the owning query as aUserScope.results. This ensures that 541 - * when query results have their change/remove methods called, the result set 542 - * is updated to reflect those calls. 543 - */ 544 - function Walker(aUserCallback, aUserScope, aMapFunction) { 545 - this.userCallback = aUserCallback; 546 - this.userScope = aUserScope; 547 - this.mapFunction = aMapFunction; 548 - } 549 - 550 - Walker.prototype = { 551 - run: function WLKR_run() { 552 - // Process results. 553 - this.results.forEach(this.mapFunction); 554 - if (this.userScope) 555 - this.userScope.results = this.results; 556 - if (this.userCallback) 557 - safeCallback(null, this.userCallback, this.userScope || undefined); 558 - } 559 - } 560 - 561 - 562 - /** 563 - * Place object, representing a single result in a set of search results. 564 - */ 565 - function Place(aOptions) { 566 - for (var i in aOptions) { 567 - switch (i) { 568 - // Omitted for now. 569 - case "pageId": // id from moz_places table, used for sql queries 570 - case "referringVisitId": 571 - case "revHost": 572 - case "sessionId": 573 - case "transitionType": 574 - case "type": // type const from nsINavBookmarksService 575 - case "visitId": 576 - continue; 577 - break; 578 - // Rename bookmarkIndex to position. 579 - case "bookmarkIndex": 580 - this.position = aOptions[i]; 581 - break; 582 - // Id from moz_bookmarks table, used for the internal boomark apis. 583 - // HACK: Expose as "private" because we need to access it for 584 - // internal use such as deletion, and query folders. 585 - case "itemId": 586 - this._itemId = aOptions[i]; 587 - break; 588 - // Rename parentId to folder. 589 - case "parentId": 590 - this.folder = aOptions[i]; 591 - // Rename readableType to bookmarkType. 592 - case "readableType": 593 - this.type = aOptions[i] == "container" ? "folder" : aOptions[i]; 594 - break; 595 - // Rename referringUri to referrer. 596 - case "referringUri": 597 - this.referrer = aOptions[i]; 598 - break; 599 - // Rename uri to location. 600 - case "uri": 601 - this.location = aOptions[i]; 602 - break; 603 - // Name/value does not need to change. 604 - case "accessCount": 605 - case "dateAdded": 606 - case "frecency": 607 - case "host": 608 - case "icon": // is a URL, should rename to iconURL? 609 - case "isBookmarked": 610 - case "lastModified": 611 - case "tags": 612 - case "title": 613 - case "time": 614 - this[i] = aOptions[i]; 615 - break; 616 - } 617 - } 618 - } 619 - 620 - /****************************************************************************** 621 - * THE CODE FROM HERE TO THE END OF THE FILE IS THE JETPACK-LESS PLACES QUERY 622 - * MODULE. IT MUST REMAIN JETPACK-FREE. ANY MODIFICATIONS MUST BE FILED AS 623 - * BUGS AND MARKED AS BLOCKING BUG 522572. 624 - *****************************************************************************/ 625 - 626 - /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- 627 - * vim: sw=2 ts=2 sts=2 expandtab 628 - * ***** BEGIN LICENSE BLOCK ***** 629 - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 630 - * 631 - * The contents of this file are subject to the Mozilla Public License Version 632 - * 1.1 (the "License"); you may not use this file except in compliance with 633 - * the License. You may obtain a copy of the License at 634 - * http://www.mozilla.org/MPL/ 635 - * 636 - * Software distributed under the License is distributed on an "AS IS" basis, 637 - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 638 - * for the specific language governing rights and limitations under the 639 - * License. 640 - * 641 - * The Original Code is mozilla.org code. 642 - * 643 - * The Initial Developer of the Original Code is 644 - * Mozilla Corporation. 645 - * Portions created by the Initial Developer are Copyright (C) 2010 646 - * the Initial Developer. All Rights Reserved. 647 - * 648 - * Contributor(s): 649 - * Marco Bonardo <mak77@bonardo.net> (original author) 650 - * David Dahl <ddahl@mozilla.com> 651 - * Dietrich Ayala <dietrich@mozilla.com> 652 - * 653 - * Alternatively, the contents of this file may be used under the terms of 654 - * either the GNU General Public License Version 2 or later (the "GPL"), or 655 - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), 656 - * in which case the provisions of the GPL or the LGPL are applicable instead 657 - * of those above. If you wish to allow use of your version of this file only 658 - * under the terms of either the GPL or the LGPL, and not to allow others to 659 - * use your version of this file under the terms of the MPL, indicate your 660 - * decision by deleting the provisions above and replace them with the notice 661 - * and other provisions required by the GPL or the LGPL. If you do not delete 662 - * the provisions above, a recipient may use your version of this file under 663 - * the terms of any one of the MPL, the GPL or the LGPL. 664 - * 665 - * ***** END LICENSE BLOCK ***** */ 666 - 667 - //const EXPORTED_SYMBOLS = ["PlacesQuery"]; 668 - 669 - /* This is a pure async querying API. 670 - * It provides non-liveupdating query results passed to a callback function. 671 - * 672 - * NOTE: history results returned by this object may be up to two minutes behind 673 - * since it does not handle TEMP tables. We plan to remove them, so this bad 674 - * behavior will be rectified at that point. 675 - * 676 - * TODO: 677 - * - Hierarchal queries. 678 - * - Accept a place: uri as input. 679 - * - Par querying capabilities with the old querying API. 680 - * - Faster queries. 681 - * - Create a PlacesLiveQuery wrapper that will query through an internal 682 - * PlacesQuery object and then will maintain an updated copy of the results. 683 - * - Use PlacesLiveQuery wrapper in our views. 684 - * - Add further querying capabilities. 685 - * 686 - * EXAMPLE: 687 - * 688 - * let query = new PlacesQuery({_QueryConf_}); 689 - * 690 - * query.execute(function(result) { 691 - * if (result) 692 - * dump("Got a result: " + [result.title, result.uri, result.readableType].join(", ")); 693 - * else 694 - * dump("Finished executing query!\n"); 695 - * }, this); 696 - * 697 - * 698 - * _QueryConf_ = { 699 - * phrase: string. 700 - * Containing this string in either title, uri or tags. Case 701 - * insensitive. Can use ^ and $ to match at beginning or end. 702 - * host: string. 703 - * Containing this string in the host. Case insensitive. 704 - * Can use ^ and $ to match at beginning or end. 705 - * uri: string. 706 - * Containing this string in the uri. Case insensitive. 707 - * Can use ^ and $ to match beginning or end. 708 - * annotated: array of strings. 709 - * With these annotations (Either page or item). 710 - * bookmarked: object 711 - * { 712 - * tags: array of strings. 713 - * Tagged with these tags. 714 - * folder: number. 715 - * Inside this folder. (non-recursive) 716 - * position: number. 717 - * At this position. (relative to folder). 718 - * If undefined or null matches all children. 719 - * If no folder is defined, position is ignored. 720 - * id: number. 721 - * Bookmarked with this id. 722 - * createdBegin: optional Date object 723 - * Bookmarks created after this time (included). 724 - * Defaults to epoch. 725 - * createdEnd: optional Date object 726 - * Bookmarks created before this time (included). 727 - * Defaults to now. 728 - * modifiedBegin: optional Date object 729 - * Bookmarks modified after this time (included). 730 - * Defaults to epoch. 731 - * modifiedEnd: optional Date object 732 - * Bookmarks modified before this time (included). 733 - * Defaults to now. 734 - * onlyContainers: boolean. 735 - * Removes any non-container from results. 736 - * Default is false. 737 - * excludeReadOnlyContainers: boolean. 738 - * Removes read only containers from results. 739 - * Default is false. 740 - * } 741 - * visited: object 742 - * { 743 - * countMin: optional number. 744 - * With more than this many visits. 745 - * Defaults to 0. 746 - * This is lazily based on visit_count, thus is not going to work 747 - * for not counted transitions: embed, download, framed_link. 748 - * countMax: optional number. 749 - * With less than this many visits. 750 - * Defaults to inf. 751 - * This is lazily based on visit_count, thus is not going to work 752 - * for not counted transitions: embed, download, framed_link. 753 - * transitions: array of transition types. 754 - * With at least one visit for each of these transitions. 755 - * begin: optional Date object 756 - * With visits after this time (included). 757 - * Defaults to epoch. 758 - * end: optional Date object 759 - * With visits before this time (included). 760 - * Defaults to now. 761 - * excludeRedirectSources: boolean. 762 - * Removes redirects sources from results. 763 - * Default is false. 764 - * excludeRedirectTargets: boolean. 765 - * Removes redirects targets from results. 766 - * Default is false. 767 - * includeHidden: boolean. 768 - * Includes also pages marked as hidden. 769 - * Default is false. 770 - * includeAllVisits: boolean. 771 - * Returns all visits ungrouped. 772 - * Default is false, that means visits are grouped by uri. 773 - * } 774 - * sortBy: string. 775 - * Either "none", "title", "time", "uri", "accessCount", "lastModified", 776 - * "frecency". Defaults to "none". 777 - * sortDir: string. 778 - * Either "asc" or "desc". Defaults to "asc". 779 - * group: string. 780 - * Either "tags", "containers", "days", "months", "years" or "domains". 781 - * Defaults to "none". 782 - * NOTE: Not yet implemented. 783 - * limit: number. 784 - * Maximum number of results to return. Defaults to all results. 785 - * merge: string. 786 - * How to merge this query's results with others in the same request. 787 - * Valid values: 788 - * - "union": merge results from the 2 queries. 789 - * - "except": exclude current results from the previous ones. 790 - * - "intersect": only current results that are also in previous ones. 791 - * } 792 - * 793 - */ 794 - 795 - //////////////////////////////////////////////////////////////////////////////// 796 - //// Constants and Getters 797 - 798 - //const Cc = Components.classes; 799 - //const Ci = Components.interfaces; 800 - //const Cr = Components.results; 801 - //const Cu = Components.utils; 802 - 803 - const TAGS_SEPARATOR = ", "; 804 - 805 - const TAGS_SQL_FRAGMENT = 806 - "(" 807 - + "SELECT GROUP_CONCAT(tag_title, ', ') " 808 - + "FROM ( " 809 - + "SELECT t_t.title AS tag_title " 810 - + "FROM moz_bookmarks b_t " 811 - + "JOIN moz_bookmarks t_t ON t_t.id = b_t.parent " 812 - + "WHERE b_t.fk = h.id " 813 - + "AND LENGTH(t_t.title) > 0 " 814 - + "AND t_t.parent = :tags_folder " 815 - + "ORDER BY t_t.title COLLATE NOCASE ASC " 816 - + ") WHERE b.id NOTNULL " 817 - + ")"; 818 - 819 - const REFERRING_URI_SQL_FRAGMENT = 820 - "(" 821 - + "SELECT refh.url FROM moz_places refh " 822 - + "JOIN moz_historyvisits refv ON refh.id = refv.place_id " 823 - + "WHERE refv.id = v.from_visit " 824 - + ")"; 825 - 826 - Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); 827 - Cu.import("resource://gre/modules/Services.jsm", this); 828 - Cu.import("resource://gre/modules/PlacesUtils.jsm", this); 829 - 830 - XPCOMUtils.defineLazyGetter(this, "DB", function() { 831 - return PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase) 832 - .DBConnection; 833 - }); 834 - 835 - 836 - //////////////////////////////////////////////////////////////////////////////// 837 - //// Utils and Helpers 838 - 839 - function checkType(entry, type) { 840 - switch (type) { 841 - case "undefined": 842 - return entry === undefined; 843 - case "null": 844 - return entry === null; 845 - case "date": 846 - return Object.prototype.toString.call(entry) === "[object Date]"; 847 - case "array": 848 - // TODO: Use ES5 isArray() once available. 849 - // NOTE: current method fails if the array comes from JSON.parse. 850 - return Object.prototype.toString.call(entry) === "[object Array]"; 851 - default: 852 - if (entry === null) // typeof(null) == "object" but we have a "null" type. 853 - return false; 854 - return typeof(entry) == type; 855 - } 856 - } 857 - 858 - 859 - function checkArrayElementsType(array, type, allowOptionalElement) { 860 - let arrayIsValid = true; 861 - array.every(function(elm) { 862 - if (allowOptionalElement && (elm === undefined || elm === null)) 863 - return true; 864 - return arrayIsValid = checkType(elm, type); 865 - }); 866 - return arrayIsValid; 867 - } 868 - 869 - 870 - function isValidArray(aObj, aValidator) 871 - { 872 - let validArray = checkType(aObj, "array"); 873 - if (validArray && aValidator) { 874 - if (!checkType(aValidator, "function")) 875 - throw new Error("Array validator must be a function."); 876 - return aValidator(aObj); 877 - } 878 - return validArray; 879 - } 880 - 881 - 882 - function getReadableItemType(aResultItem, aItemType) 883 - { 884 - if (aItemType) { 885 - // it's a bookmark. 886 - if (!aResultItem.uri || aResultItem.uri.substr(0, 6) == "place:") { 887 - switch (aItemType) { 888 - case Ci.nsINavBookmarksService.TYPE_SEPARATOR: 889 - return "separator"; 890 - default: 891 - return "container"; 892 - } 893 - } 894 - return "bookmark"; 895 - } 896 - if (aResultItem.visitId) 897 - return "visit"; 898 - return "page"; 899 - } 900 - 901 - 902 - function getNodeType(aResultItem, aItemType) { 903 - if (aResultItem.transitionType) 904 - return Ci.nsINavHistoryResultNode.RESULT_TYPE_FULL_VISIT; 905 - 906 - let isQuery = aResultItem.uri && aResultItem.uri.substr(0, 6) == "place:"; 907 - if (aResultItem.isBookmarked) { 908 - if (aItemType == PlacesUtils.bookmarks.TYPE_FOLDER) 909 - return Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER; 910 - if (aItemType == PlacesUtils.bookmarks.TYPE_SEPARATOR) 911 - return Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR; 912 - 913 - if (isQuery && /^place:folder=[^&]+$/i.test(aResultItem.uri)) 914 - return Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT; 915 - } 916 - 917 - return isQuery ? Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY 918 - : Ci.nsINavHistoryResultNode.RESULT_TYPE_URI; 919 - } 920 - 921 - 922 - function TextMatch(aText) 923 - { 924 - if (aText.substr(0, 1) == "^") 925 - this.matchBegin = true; 926 - if (aText.substr(-1, 1) == "$") 927 - this.matchEnd = true; 928 - this.exactMatch = this.matchEnd && this.matchBegin; 929 - let cutFrom = this.matchBegin ? 1 : 0; 930 - let cutLen = aText.length - cutFrom - (this.matchEnd ? 1 : 0); 931 - this.value = aText.substr(cutFrom, cutLen); 932 - } 933 - 934 - TextMatch.prototype = { 935 - matchBegin: false, 936 - matchEnd: false, 937 - exactMatch: false, 938 - value: "", 939 - 940 - getStringForLike: function TM_getStringForLike(aStmt) { 941 - let escValue = aStmt.escapeStringForLIKE(this.value, '/'); 942 - if (this.exactMatch) 943 - return escValue; 944 - if (this.matchBegin) 945 - return escValue + "%"; 946 - if (this.matchEnd) 947 - return "%" + escValue; 948 - return "%" + escValue + "%"; 949 - }, 950 - 951 - getRegExp: function TM_getRegExp(aUseWordBoundaries) { 952 - let beginMod = aUseWordBoundaries ? "\\b" : "^"; 953 - let endMod = aUseWordBoundaries ? "\\b" : "$"; 954 - if (this.exactMatch) 955 - return new RegExp(beginMod + this.value + endMod, "i"); 956 - if (this.matchBegin) 957 - return new RegExp(beginMod + this.value, "i"); 958 - if (this.matchEnd) 959 - return new RegExp(this.value + endMod, "i"); 960 - return new RegExp(this.value, "i"); 961 - } 962 - } 963 - 964 - 965 - //////////////////////////////////////////////////////////////////////////////// 966 - //// (De)Serializers 967 - 968 - const SPECIAL_FOLDERS = { 969 - BOOKMARKS_MENU_FOLDER: PlacesUtils.bookmarksMenuFolderId 970 - , TAGS_FOLDER: PlacesUtils.tagsFolderId 971 - , UNFILED_BOOKMARKS_FOLDER: PlacesUtils.unfiledBookmarksFolderId 972 - , TOOLBAR_FOLDER: PlacesUtils.toolbarFolderId 973 - }; 974 - 975 - const TIME_REFERENCE = { 976 - 0: 0 // EPOCH 977 - , 1: new Date().setHours(0,0,0,0) * 1000 // TODAY'S START 978 - , 2: Date.now() * 1000 // NOW 979 - }; 980 - 981 - function deserializeLegacyPlaceUrl(aUrl) { 982 - let queryConfs = []; 983 - // Strip "place:" scheme. 984 - aUrl = aUrl.substr(7); 985 - // Split multiple queries. 986 - let queries = aQuery.split("OR"); 987 - // Put each param in an array of objects like { name:, value: }. 988 - let re = new RegExp("([^?=&]+)(=([^&]*))?", "gi"); 989 - queries.forEach(function(aQuery) { 990 - let params = {}; 991 - let match = null; 992 - while ((match = re.exec(aQuery))) { 993 - let name = match[1].toLowerCase(); 994 - let value = match[3]; 995 - // Same key can have multiple params, for simplicity make values arrays. 996 - if (!(name in params)) 997 - params[name] = []; 998 - params[name].push(value); 999 - }; 1000 - 1001 - let conf = {} 1002 - for (let name in params) { 1003 - switch(name) { 1004 - case "begintime": 1005 - if (!("visited" in conf)) 1006 - conf.visited = {} 1007 - let begintimeref = 0; 1008 - if ("begintimeref" in params) 1009 - begintimeref += params["begintimeref"]; 1010 - conf.visited.begin = new Date((timeref + params["begintime"][0])/1000); 1011 - break; 1012 - case "endtime": 1013 - if (!("visited" in conf)) 1014 - conf.visited = {} 1015 - let endtimeref = 0; 1016 - if ("endtimeref" in params) 1017 - endtimeref += params["endtimeref"]; 1018 - conf.visited.end = new Date((timeref + params["endtime"][0])/1000); 1019 - break; 1020 - case "terms": 1021 - conf.phrase = params["terms"][0]; 1022 - break; 1023 - case "minvisits": 1024 - if (!("visited" in conf)) 1025 - conf.visited = {} 1026 - conf.visited.countMin = params["minvisits"][0]; 1027 - break; 1028 - case "maxvisits": 1029 - if (!("visited" in conf)) 1030 - conf.visited = {} 1031 - conf.visited.countMax = params["maxvisits"][0]; 1032 - break; 1033 - case "onlybookmarked": 1034 - if (!("bookmarked" in conf)) 1035 - conf.bookmarked = {}; 1036 - break; 1037 - case "domain": 1038 - if ("domainishost" in params) { 1039 - if (params["domainishost"] == 1) 1040 - conf.host = "^" + params["domain"][0] + "$"; 1041 - } 1042 - else 1043 - conf.host = params["domain"][0]; 1044 - break; 1045 - case "folder": 1046 - if (!("bookmarked" in conf)) 1047 - conf.bookmarked = {}; 1048 - if (params["folder"].length == 1) { 1049 - let folderId; 1050 - if (/[a-z]/.test(folderId)) { 1051 - if (folderId in SPECIAL_FOLDERS) 1052 - folderId = SPECIAL_FOLDERS[folderId]; 1053 - } 1054 - else { 1055 - folderId = params["folder"][0]; 1056 - } 1057 - if (folderId) 1058 - conf.bookmarked.folder = folderId; 1059 - } 1060 - // TODO: due to a nice API confusion, if there is more than one folder 1061 - // they are wrongly ORed. 1062 - break; 1063 - case "annotation": 1064 - if ("!annotation" in params) { 1065 - // TODO: handle !annotation=1, should split an except query. 1066 - } 1067 - else { 1068 - conf.annotated = params["annotation"]; 1069 - } 1070 - break; 1071 - case "uri": 1072 - if ("uriisprefix" in params) { 1073 - if (params["uriisprefix"] == 1) 1074 - conf.host = "^" + params["uri"][0]; 1075 - } 1076 - else 1077 - conf.uri = "^" + params["domain"][0] + "$"; 1078 - break; 1079 - case "group": 1080 - // Sadly this has been killed lot of time ago for result type. 1081 - break; 1082 - case "sort": 1083 - let opts = Ci.nsINavHistoryQueryOptions; 1084 - switch(params["sort"][0]) { 1085 - case opts.SORT_BY_TITLE_ASCENDING: 1086 - conf.sortBy = "title"; 1087 - conf.sortDir = "ASC"; 1088 - break; 1089 - case opts.SORT_BY_TITLE_DESCENDING: 1090 - conf.sortBy = "title"; 1091 - conf.sortDir = "DESC"; 1092 - break; 1093 - case opts.SORT_BY_DATE_ASCENDING: 1094 - conf.sortBy = "time"; 1095 - conf.sortDir = "ASC"; 1096 - break; 1097 - case opts.SORT_BY_DATE_DESCENDING: 1098 - conf.sortBy = "time"; 1099 - conf.sortDir = "DESC"; 1100 - break; 1101 - case opts.SORT_BY_URI_ASCENDING: 1102 - conf.sortBy = "uri"; 1103 - conf.sortDir = "ASC"; 1104 - break; 1105 - case opts.SORT_BY_URI_DESCENDING: 1106 - conf.sortBy = "uri"; 1107 - conf.sortDir = "DESC"; 1108 - break; 1109 - case opts.SORT_BY_VISITCOUNT_ASCENDING: 1110 - conf.sortBy = "accessCount"; 1111 - conf.sortDir = "ASC"; 1112 - break; 1113 - case opts.SORT_BY_VISITCOUNT_DESCENDING: 1114 - conf.sortBy = "accessCount"; 1115 - conf.sortDir = "DESC"; 1116 - break; 1117 - case opts.SORT_BY_DATEADDED_ASCENDING: 1118 - conf.sortBy = "dateAdded"; 1119 - conf.sortDir = "ASC"; 1120 - break; 1121 - case opts.SORT_BY_DATEADDED_DESCENDING: 1122 - conf.sortBy = "dateAdded"; 1123 - conf.sortDir = "DESC"; 1124 - break; 1125 - case opts.SORT_BY_LASTMODIFIED_ASCENDING: 1126 - conf.sortBy = "lastModified"; 1127 - conf.sortDir = "ASC"; 1128 - break; 1129 - case opts.SORT_BY_LASTMODIFIED_DESCENDING: 1130 - conf.sortBy = "lastModified"; 1131 - conf.sortDir = "DESC"; 1132 - break; 1133 - case opts.SORT_BY_NONE: 1134 - // default. 1135 - break; 1136 - case opts.SORT_BY_KEYWORD_ASCENDING: 1137 - case opts.SORT_BY_KEYWORD_DESCENDING: 1138 - case opts.SORT_BY_TAGS_ASCENDING: 1139 - case opts.SORT_BY_TAGS_DESCENDING: 1140 - case opts.SORT_BY_ANNOTATION_ASCENDING: 1141 - case opts.SORT_BY_ANNOTATION_DESCENDING: 1142 - // Not supported. 1143 - break; 1144 - }; 1145 - break; 1146 - case "type": 1147 - switch (params["type"][0]) { 1148 - case Ci.nsINavHistoryQueryOptions.RESULTS_AS_VISIT: 1149 - case Ci.nsINavHistoryQueryOptions.RESULTS_AS_FULL_VISIT: 1150 - if (!("visited" in conf)) 1151 - conf.visited = {}; 1152 - conf.visited.includeAllVisits = true; 1153 - break; 1154 - case Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_QUERY: 1155 - case Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY: 1156 - case Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY: 1157 - // TODO, need to define how to make date grouping. 1158 - break; 1159 - case Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY: 1160 - case Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_CONTENTS: 1161 - conf.group = "tags"; 1162 - break; 1163 - } 1164 - break; 1165 - case "excludeitems": 1166 - if (!("bookmarked" in conf)) 1167 - conf.bookmarked = {}; 1168 - if (params["excludeitems"][0] == 1) 1169 - conf.bookmarked.onlyContainers = true; 1170 - break; 1171 - case "excludequeries": 1172 - if (!("bookmarked" in conf)) 1173 - conf.bookmarked = {}; 1174 - break; 1175 - case "excludereadonlyfolders": 1176 - if (!("bookmarked" in conf)) 1177 - conf.bookmarked = {}; 1178 - if (params["excludereadonlyfolders"][0] == 1) 1179 - conf.bookmarked.excludeReadOnlyContainers = true; 1180 - break; 1181 - case "excludeitemifparenthasannotation": 1182 - // Not supported, we should remove livemarks children from bookmarks 1183 - // instead. 1184 - break; 1185 - case "expandqueries": 1186 - // Not supported, the query should have onlyContainers instead. 1187 - break; 1188 - case "originaltitle": 1189 - // Never been implemented, and it is not yet. 1190 - break; 1191 - case "includehidden": 1192 - if (!("visited" in conf)) 1193 - conf.visited = {}; 1194 - if (params["includehidden"][0] == 1) 1195 - conf.visited.includeHidden = true; 1196 - break; 1197 - case "redirectsmode": 1198 - if (!("visited" in conf)) 1199 - conf.visited = {}; 1200 - switch(params["redirectsMode"][0]) { 1201 - case Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_TARGET: 1202 - conf.visited.excludeRedirectSources = true; 1203 - break; 1204 - case Ci.nsINavHistoryQueryOptions.REDIRECTS_MODE_SOURCE: 1205 - conf.visited.excludeRedirectTargets = true; 1206 - break; 1207 - } 1208 - break; 1209 - case "maxresults": 1210 - conf.limit = params["maxresults"][0]; 1211 - break; 1212 - case "querytype": 1213 - if (params["querytype"][0] == Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS && 1214 - !("bookmarked" in conf)) 1215 - conf.bookmarked = {}; 1216 - break; 1217 - case "tag": 1218 - if ("!tags" in params) { 1219 - // TODO: handle !annotation=1, should split out an except query. 1220 - } 1221 - else { 1222 - if (!("bookmarked" in conf)) 1223 - conf.bookmarked = {}; 1224 - conf.bookmarked.tags = params["tag"]; 1225 - } 1226 - break; 1227 - case "asyncenabled": 1228 - // Ignored, this is always async. 1229 - break; 1230 - } 1231 - } 1232 - 1233 - // Folder shortcuts. 1234 - if (/place:folder=[^&]/.test(aUrl)) 1235 - conf.group = "containers"; 1236 - 1237 - queryConfs.push(conf); 1238 - }); 1239 - return queryConfs; 1240 - } 1241 - 1242 - 1243 - //////////////////////////////////////////////////////////////////////////////// 1244 - //// QueryConf 1245 - 1246 - function QueryConf(aQueryConf) 1247 - { 1248 - // Safe initialize: use default values if inputs are invalid. 1249 - for (let prop in aQueryConf) { 1250 - this[prop] = aQueryConf[prop]; 1251 - } 1252 - } 1253 - 1254 - QueryConf.prototype = { 1255 - _phrase: new TextMatch(""), 1256 - get phrase() this._phrase.value, 1257 - set phrase(aVal) 1258 - { 1259 - if (checkType(aVal, "string")) 1260 - this._phrase = new TextMatch(aVal); 1261 - return this._phrase.value; 1262 - }, 1263 - 1264 - _host: new TextMatch(""), 1265 - get host() this._host.value, 1266 - set host(aVal) 1267 - { 1268 - if (checkType(aVal, "string")) 1269 - this._host = new TextMatch(aVal); 1270 - return this._host.value; 1271 - }, 1272 - 1273 - _uri: new TextMatch(""), 1274 - get uri() this._uri.value, 1275 - set uri(aVal) 1276 - { 1277 - if (checkType(aVal, "string")) 1278 - this._uri = new TextMatch(aVal); 1279 - return this._uri.value; 1280 - }, 1281 - 1282 - _annotated: [], 1283 - get annotated() this._annotated, 1284 - set annotated(aVal) 1285 - { 1286 - if (isValidArray(aVal, function(v) v.length > 0 && checkArrayElementsType(v, "string"))) 1287 - this._annotated = aVal; 1288 - return this._annotated; 1289 - }, 1290 - 1291 - _bookmarked: null, 1292 - get bookmarked() this._bookmarked, 1293 - set bookmarked(aVal) 1294 - { 1295 - if (checkType(aVal, "object")) { 1296 - let options = { tags: [] 1297 - , folder: null 1298 - , position: null 1299 - , id: null 1300 - , createdBegin: null 1301 - , createdEnd: null 1302 - , modifiedBegin: null 1303 - , modifiedEnd: null 1304 - , onlyContainers: false 1305 - , excludeReadOnlyContainers: false 1306 - }; 1307 - 1308 - if ("tags" in aVal && 1309 - isValidArray(aVal.tags, function(v) v.length > 0 && checkArrayElementsType(v, "string"))) 1310 - options.tags = aVal.tags; 1311 - 1312 - if ("folder" in aVal && aVal.folder > 0) 1313 - options.folder = aVal.folder; 1314 - 1315 - if ("position" in aVal && aVal.position >= 0) 1316 - options.position = aVal.position; 1317 - 1318 - if ("id" in aVal && checkType(aVal.id, "number")) 1319 - options.id = aVal.id; 1320 - 1321 - if ("createdBegin" in aVal && checkType(aVal.createdBegin, "date")) 1322 - options.createdBegin = aVal.createdBegin; 1323 - 1324 - if ("createdEnd" in aVal && checkType(aVal.createdEnd, "date")) 1325 - options.createdEnd = aVal.createdEnd; 1326 - 1327 - if ("modifiedBegin" in aVal && checkType(aVal.modifiedBegin, "date")) 1328 - modifiedBegin = aVal.modifiedBegin; 1329 - if ("end" in aVal && checkType(aVal.modifiedEnd, "date")) 1330 - modifiedEnd = aVal.modifiedEnd; 1331 - 1332 - if ("onlyContainers" in aVal && 1333 - checkType(aVal.onlyContainers, "boolean")) 1334 - options.onlyContainers = aVal.onlyContainers; 1335 - 1336 - if ("excludeReadOnlyContainers" in aVal && 1337 - checkType(aVal.excludeReadOnlyContainers, "boolean")) 1338 - options.excludeReadOnlyContainers = aVal.excludeReadOnlyContainers; 1339 - 1340 - this._bookmarked = options; 1341 - } 1342 - // Set simple bool for isBookmarked with no other parameters. 1343 - else if(aVal) { 1344 - this._bookmarked = true; 1345 - } 1346 - return this._bookmarked; 1347 - }, 1348 - 1349 - _visited: null, 1350 - get visited() this._visited, 1351 - set visited(aVal) 1352 - { 1353 - if (checkType(aVal, "object")) { 1354 - let options = { countMin: null 1355 - , countMax: null 1356 - , transitions: [] 1357 - , begin: null 1358 - , end: null 1359 - , exclude: [] 1360 - , include: [] 1361 - }; 1362 - 1363 - if ("countMin" in aVal && checkType(aVal.countMin, "number")) 1364 - options.countMin = aVal.countMin; 1365 - if ("countMax" in aVal && checkType(aVal.countMax, "number")) 1366 - options.countMax = aVal.countMax; 1367 - 1368 - if ("transitions" in aVal && 1369 - isValidArray(aVal.transitions, function(v) v.length > 0 && checkArrayElementsType(v, "number"))) 1370 - options.transitions = aVal.transitions; 1371 - 1372 - if ("begin" in aVal && checkType(aVal.begin, "date")) 1373 - options.begin = aVal.begin; 1374 - 1375 - if ("end" in aVal && checkType(aVal.end, "date")) 1376 - options.end = aVal.end; 1377 - 1378 - if ("excludeRedirectSources" in aVal && 1379 - checkType(aVal.excludeRedirectSources, "boolean")) 1380 - options.excludeRedirectSources = aVal.excludeRedirectSources; 1381 - 1382 - if ("excludeRedirectTargets" in aVal && 1383 - checkType(aVal.excludeRedirectTargets, "boolean")) 1384 - options.excludeRedirectTargets = aVal.excludeRedirectTargets; 1385 - 1386 - if ("includeHidden" in aVal && checkType(aVal.includeHidden, "boolean")) 1387 - options.includeHidden = aVal.includeHidden; 1388 - 1389 - if ("includeAllVisits" in aVal && checkType(aVal.includeAllVisits, "boolean")) 1390 - options.includeAllVisits = aVal.includeAllVisits; 1391 - 1392 - this._visited = options; 1393 - } 1394 - // Set simple bool for isVisited with no other parameters. 1395 - else if(aVal) { 1396 - this._visited = true; 1397 - } 1398 - return this._visited; 1399 - }, 1400 - 1401 - // TODO: not yet implemented for callers. Internally 1402 - // it's used already, so just disabling the setter. 1403 - _group: "none", 1404 - get group() this._group, 1405 - /* 1406 - set group(aVal) 1407 - { 1408 - if (["none", "containers" 1409 - //, "tags", "month", "year", "host" 1410 - ].indexOf(aVal) != -1) 1411 - this._group = aVal; 1412 - return this._group; 1413 - }, 1414 - */ 1415 - 1416 - _sortBy: "none", 1417 - get sortBy() this._sortBy, 1418 - set sortBy(aVal) 1419 - { 1420 - let sortingOptions = ["none", "title", "time", "uri", "accessCount", "lastModified", "frecency"]; 1421 - if (checkType(aVal, "string") && sortingOptions.indexOf(aVal) != -1) { 1422 - this._sortBy = aVal; 1423 - } 1424 - return this._sortBy; 1425 - }, 1426 - 1427 - _sortDir: "ASC", 1428 - get sortDir() this._sortDir, 1429 - set sortDir(aVal) 1430 - { 1431 - this._sortDir = ["asc", "desc"].indexOf(aVal) != -1 ? aVal.toUpperCase() : "ASC"; 1432 - return this._sortDir; 1433 - }, 1434 - 1435 - _limit: -1, 1436 - get limit() this._limit, 1437 - set limit(aVal) 1438 - { 1439 - if (checkType(aVal, "number")) 1440 - this._limit = aVal; 1441 - return this._limit; 1442 - }, 1443 - 1444 - /* 1445 - _merge: "union", 1446 - get merge() this._merge, 1447 - set merge(aVal) 1448 - { 1449 - if (["union", "intersect", "except"].indexOf(aVal) != -1) 1450 - this._merge = aVal; 1451 - return this._merge; 1452 - } 1453 - */ 1454 - } 1455 - 1456 - 1457 - //////////////////////////////////////////////////////////////////////////////// 1458 - //// PlacesQuery 1459 - 1460 - // Note: Multiple queryconf support is currently denied from callers 1461 - // as the API is not complete. However, the support is kept in the back-end 1462 - // so we're just wrapping the query conf in an array in two places 1463 - // in this ctor for now. 1464 - function PlacesQuery(aQueryConf) 1465 - { 1466 - let queryConfs = []; 1467 - 1468 - // Allow passing a place: url. 1469 - if (checkType(aQueryConf, "string") && 1470 - aQueryConf.substr(0, 6) == "place:") { 1471 - queryConfs.push(deserializeLegacyPlaceUrl(aQueryConf)); 1472 - // TODO: check valid conf object here 1473 - } 1474 - // Allow array for future compat, but currently 1475 - // only accepting single query. 1476 - //else if (checkType(aQueryConf, "array")) 1477 - // queryConfs.push(new QueryConf(aQueryConf[0])); 1478 - else if (checkType(aQueryConf, "object")) 1479 - queryConfs.push(new QueryConf(aQueryConf)); 1480 - else 1481 - throw Cr.NS_ERROR_INVALID_ARG; // TODO: nice errors please. 1482 - 1483 - let pendingQuery = this; 1484 - this.execute = function PQ_execute(aCallback, aThisObject) 1485 - { 1486 - // A callback is required, otherwise running the query would be useless. 1487 - if (!aCallback || !checkType(aCallback, "function")) 1488 - throw Cr.NS_ERROR_INVALID_ARG; // TODO: nice errors please. 1489 - 1490 - let [sql, stmt] = QueryBuilder.build(queryConfs); 1491 - 1492 - // DEBUG 1493 - //dump("\nDEBUG SQL PRINT\n" + sql + "\n\n"); 1494 - 1495 - // Run query, call back. 1496 - let stmtCallback = new StmtCallback(queryConfs, aCallback, aThisObject); 1497 - pendingQuery._pending = stmt.executeAsync(stmtCallback); 1498 - stmtCallback.pendingQuery = pendingQuery; 1499 - stmt.finalize(); 1500 - } 1501 - 1502 - this.cancel = function PQ_cancel() 1503 - { 1504 - if (pendingQuery._pending) { 1505 - pendingQuery._pending.cancel(); 1506 - delete pendingQuery._pending; 1507 - } 1508 - } 1509 - } 1510 - 1511 - PlacesQuery.prototype = {} 1512 - 1513 - 1514 - //////////////////////////////////////////////////////////////////////////////// 1515 - //// QueryBuilder 1516 - 1517 - let QueryBuilder = { 1518 - build: function QB_build(aQueryConfs) 1519 - { 1520 - // Get global options, we use the first query's ones. 1521 - let globalGroup = aQueryConfs[0].group; 1522 - let globalSortBy = aQueryConfs[0].sortBy; 1523 - let globalSortDir = aQueryConfs[0].sortDir; 1524 - let globalLimit = aQueryConfs[0].limit; 1525 - 1526 - // Optimizations will come later, but some query could be hard to silent. 1527 - let sql = "/* do not warn (bug 522572) */"; 1528 - for (let i = 0; i < aQueryConfs.length; i++) { 1529 - aQueryConfs[i]._qIndex = i; 1530 - if (i > 0) { 1531 - switch (aQueryConfs[i - 1].merge) { 1532 - case "intersect": 1533 - sql += " INSERSECT "; 1534 - break; 1535 - case "except": 1536 - sql += " EXCEPT "; 1537 - break; 1538 - case "union": 1539 - default: 1540 - sql += " UNION "; 1541 - break; 1542 - } 1543 - } 1544 - sql += this._SQLFor(aQueryConfs[i], globalGroup); 1545 - } 1546 - 1547 - if (globalSortBy || globalSortDir) { 1548 - function getNeutralSorting() { 1549 - if (globalGroup == "containers" || globalGroup == "tags") 1550 - return "position"; 1551 - return "page_id"; 1552 - } 1553 - const COLUMNS = { none: getNeutralSorting() 1554 - , title: "page_title COLLATE NOCASE" 1555 - , time: "visit_date" 1556 - , uri: "page_url" 1557 - , accessCount: "visit_count" 1558 - , lastModified: "lastModified" 1559 - , frecency: "frecency" 1560 - }; 1561 - sql += " ORDER BY " + COLUMNS[globalSortBy] + " " + globalSortDir; 1562 - } 1563 - 1564 - // Check if we can apply a direct LIMIT to the query, if there is any sort 1565 - // of post filtering or processing, we clearly can't. 1566 - if (globalLimit != -1) { 1567 - let canSQLLimit = globalGroup == "none"; 1568 - for (let i = 0; i < aQueryConfs.length && canSQLLimit; i++) { 1569 - canSQLLimit = aQueryConfs[i]._postFilteringTasks.length == 0 && 1570 - aQueryConfs[i]._postProcessingTasks.length == 0; 1571 - } 1572 - if (canSQLLimit) 1573 - sql += " LIMIT " + globalLimit; 1574 - } 1575 - 1576 - let stmt = DB.createAsyncStatement(sql); 1577 - this._bind(stmt, aQueryConfs); 1578 - 1579 - return [sql, stmt]; 1580 - }, 1581 - 1582 - _bind: function QB__bind(aStmt, aQueryConfs) 1583 - { 1584 - // Collect all binding params. 1585 - let params = []; 1586 - aQueryConfs.forEach(function(aQueryConf) { 1587 - params = params.concat(aQueryConf._params); 1588 - }); 1589 - 1590 - params.forEach(function(aParam) { 1591 - let value = aParam.value; 1592 - if (checkType(value, "object") && 1593 - TextMatch.prototype.isPrototypeOf(value)) { 1594 - // This is a LIKE clause, thus value must be escaped. 1595 - aStmt.params[aParam.name] = value.getStringForLike(aStmt); 1596 - } 1597 - else { 1598 - aStmt.params[aParam.name] = value; 1599 - } 1600 - }); 1601 - }, 1602 - 1603 - _SQLFor: function QB__SQLFor(aQueryConf, aGroup) 1604 - { 1605 - aQueryConf._params = []; 1606 - aQueryConf._postFilteringTasks = []; 1607 - aQueryConf._postProcessingTasks = []; 1608 - 1609 - // Used in all queries. 1610 - aQueryConf._params.push({ name: "tags_folder", 1611 - value: PlacesUtils.tagsFolderId }); 1612 - 1613 - if (aQueryConf.visited && aQueryConf.visited.includeAllVisits) 1614 - return this._SQLForVisitsQuery(aQueryConf, aGroup); 1615 - 1616 - if (aQueryConf.bookmarked) 1617 - return this._SQLForBookmarksQuery(aQueryConf, aGroup); 1618 - 1619 - return this._SQLForPagesQuery(aQueryConf, aGroup); 1620 - }, 1621 - 1622 - _SQLForVisitsQuery: function QB__SQLForVisitsQuery(aQueryConf, aGroup) 1623 - { 1624 - let sql 1625 - = "SELECT h.id AS page_id, h.url AS page_url, " 1626 - + "COALESCE(b.title, h.title) AS page_title, h.rev_host AS rev_host, " 1627 - + "h.visit_count AS visit_count, v.visit_date AS visit_date, " 1628 - + "f.url AS icon_url, v.session AS session, b.id AS item_id, " 1629 - + "b.dateAdded AS dateAdded, b.lastModified AS lastModified, " 1630 - + "b.parent AS parent_id, " + TAGS_SQL_FRAGMENT + " AS tags, " 1631 - + "b.position AS position, b.type AS item_type, " 1632 - + "h.frecency AS frecency, v.id AS visit_id, " 1633 - + "v.from_visit AS from_visit, " 1634 - + REFERRING_URI_SQL_FRAGMENT + " AS from_visit_uri, " 1635 - + "v.visit_type AS visit_type " 1636 - + "FROM moz_places h " 1637 - + "JOIN moz_historyvisits v ON v.place_id = h.id " 1638 - + "LEFT JOIN moz_bookmarks b ON b.fk = h.id " 1639 - + "LEFT JOIN moz_favicons f ON f.id = h.favicon_id " 1640 - ; 1641 - 1642 - return sql + this._getConditions([], aQueryConf, "visits", aGroup); 1643 - }, 1644 - 1645 - _SQLForPagesQuery: function QB__SQLForPagesQuery(aQueryConf, aGroup) 1646 - { 1647 - let sql 1648 - = "SELECT h.id AS page_id, h.url AS page_url, " 1649 - + "COALESCE(b.title, h.title) AS page_title, h.rev_host AS rev_host, " 1650 - + "h.visit_count AS visit_count, h.last_visit_date AS visit_date, " 1651 - + "f.url AS icon_url, NULL AS session, b.id AS item_id, " 1652 - + "b.dateAdded AS dateAdded, b.lastModified AS lastModified, " 1653 - + "b.parent AS parent_id, " + TAGS_SQL_FRAGMENT + " AS tags, " 1654 - + "b.position AS position, b.type AS item_type, " 1655 - + "h.frecency AS frecency, NULL AS visit_id, NULL AS from_visit, " 1656 - + "NULL AS from_visit_uri, NULL AS visit_type " 1657 - + "FROM moz_places h " 1658 - + "LEFT JOIN moz_bookmarks b ON b.fk = h.id " 1659 - + "LEFT JOIN moz_favicons f ON f.id = h.favicon_id " 1660 - ; 1661 - 1662 - return sql + this._getConditions([], aQueryConf, "pages", aGroup); 1663 - }, 1664 - 1665 - _SQLForBookmarksQuery: function QB__SQLForBookmarksQuery(aQueryConf, aGroup) 1666 - { 1667 - // If we are grouping, or querying a folder's contents, show containers. 1668 - let showContainers = (aGroup != "none" || 1669 - (aQueryConf.bookmarked && aQueryConf.bookmarked.folder)); 1670 - let join = showContainers ? "LEFT JOIN" : "JOIN"; 1671 - 1672 - let sql 1673 - = "SELECT h.id AS page_id, h.url AS page_url, " 1674 - + "COALESCE(b.title, h.title) AS page_title, h.rev_host AS rev_host, " 1675 - + "h.visit_count AS visit_count, h.last_visit_date AS visit_date, " 1676 - + "f.url AS icon_url, NULL AS session, b.id AS item_id, " 1677 - + "b.dateAdded AS dateAdded, b.lastModified AS lastModified, " 1678 - + "b.parent AS parent_id, " + TAGS_SQL_FRAGMENT + " AS tags, " 1679 - + "b.position AS position, b.type AS item_type, " 1680 - + "h.frecency AS frecency, NULL AS visit_id, NULL AS from_visit, " 1681 - + "NULL AS from_visit_uri, NULL AS visit_type " 1682 - + "FROM moz_bookmarks b " 1683 - + join + " moz_places h ON b.fk = h.id " 1684 - + "LEFT JOIN moz_favicons f ON f.id = h.favicon_id " 1685 - ; 1686 - 1687 - let conditions = [] 1688 - //if (aGroup == "none") { 1689 - if (!showContainers) { 1690 - // We want a flat list, exclude query containers. 1691 - conditions.push("SUBSTR(page_url, 0, 6) <> 'place:'"); 1692 - } 1693 - 1694 - return sql + this._getConditions(conditions, aQueryConf, "bookmarks", aGroup); 1695 - }, 1696 - 1697 - _getConditions: function QB__getConditions(aConditions, aQueryConf, aBaseQuery, aGroup) 1698 - { 1699 - // We can use LIKE only for ASCII searches, for anything other we must 1700 - // fallback to post-filtering. Otherwise we should bundle a lib like ICU. 1701 - // Moreover searching "bàr" won't match "bar" and viceversa. 1702 - function needsRegExpLIKE(aText) /[^a-z0-9]/i.test(aText); 1703 - 1704 - 1705 - if (aQueryConf.phrase) { 1706 - let textMatch = aQueryConf._phrase; 1707 - if (needsRegExpLIKE(aQueryConf.phrase)) { 1708 - aQueryConf._postFilteringTasks.push(function filter(aResultItem) { 1709 - let reTags = textMatch.getRegExp(true); 1710 - let re = textMatch.getRegExp(false); 1711 - return re.test(aResultItem.title) || 1712 - re.test(aResultItem.uri) || 1713 - reTags.test(aResultItem.tags.join(" ")); 1714 - }); 1715 - } 1716 - else { 1717 - let param = "phrase" + aQueryConf._qIndex; 1718 - aConditions.push( 1719 - "(" 1720 - + "page_url LIKE :" + param + " ESCAPE '/' OR " 1721 - + "page_title LIKE :" + param + " ESCAPE '/' OR " 1722 - + "tags LIKE :" + param + " ESCAPE '/' " 1723 - + ")" 1724 - ); 1725 - aQueryConf._params.push({ name: param, 1726 - value: textMatch }); 1727 - } 1728 - } 1729 - 1730 - 1731 - if (aQueryConf.host) { 1732 - let textMatch = aQueryConf._host; 1733 - if (needsRegExpLIKE(aQueryConf.host)) { 1734 - aQueryConf._postFilteringTasks.push(function filter(aResultItem) { 1735 - let re = textMatch.getRegExp(false); 1736 - return re.test(aResultItem.host); 1737 - }); 1738 - } 1739 - else { 1740 - let param = "revHost" + aQueryConf._qIndex; 1741 - aConditions.push("(rev_host LIKE :" + param + " ESCAPE '/')"); 1742 - let value = textMatch.value.split("").reverse().join(""); 1743 - if (textMatch.exactMatch) 1744 - value = "^" + value + ".$"; 1745 - else if (textMatch.matchBegin) 1746 - value = value + ".$"; 1747 - else if (textMatch.matchEnd) 1748 - value = "^" + value; 1749 - aQueryConf._params.push({ name: param, 1750 - value: new TextMatch(value) }); 1751 - } 1752 - } 1753 - 1754 - 1755 - if (aQueryConf.uri) { 1756 - let textMatch = aQueryConf._uri; 1757 - if (needsRegExpLIKE(aQueryConf.uri)) { 1758 - aQueryConf._postFilteringTasks.push(function filter(aResultItem) { 1759 - let re = textMatch.getRegExp(false); 1760 - return re.test(aResultItem.uri); 1761 - }); 1762 - } 1763 - else { 1764 - let param = "uri" + aQueryConf._qIndex; 1765 - aConditions.push("(page_url LIKE :" + param + " ESCAPE '/')"); 1766 - aQueryConf._params.push({ name: param, 1767 - value: textMatch }); 1768 - } 1769 - } 1770 - 1771 - 1772 - if (aQueryConf.bookmarked) { 1773 - let options = aQueryConf.bookmarked; 1774 - 1775 - // Exclude bookmarks in tags folders. 1776 - aConditions.push( 1777 - "NOT EXISTS (" 1778 - + "SELECT 1 FROM moz_bookmarks parents " 1779 - + "WHERE parents.id = parent_id AND parents.parent = :tags_folder " 1780 - + "LIMIT 1 " 1781 - + ") " 1782 - ); 1783 - 1784 - if (checkType(options, "object")) { 1785 - 1786 - if (options.tags.length > 0) { 1787 - // tags filtering. 1788 - let paramPrefix = "tag" + aQueryConf._qIndex; 1789 - let params = []; 1790 - for (let i = 0; i < options.tags.length; i++) { 1791 - let param = paramPrefix + "_" + i 1792 - params.push(":" + param); 1793 - aQueryConf._params.push({ name: param, 1794 - value: options.tags[i] }); 1795 - } 1796 - let param = "tagsCount" + aQueryConf._qIndex; 1797 - aQueryConf._params.push({ name: param, 1798 - value: options.tags.length }); 1799 - aConditions.push( 1800 - ":" + param + " = ( " 1801 - + "SELECT count(*) FROM moz_bookmarks tags_map " 1802 - + "JOIN moz_bookmarks tags ON tags_map.parent = tags.id " 1803 - + "WHERE tags.parent = :tags_folder " 1804 - + "AND tags.title IN (" + params.join(",") + ") " 1805 - + "AND tags_map.fk = page_id " 1806 - + ") " 1807 - ); 1808 - } 1809 - 1810 - if (options.folder) { 1811 - // folder id filtering. 1812 - let param = "folderId" + aQueryConf._qIndex; 1813 - aConditions.push("parent_id = :" + param); 1814 - aQueryConf._params.push({ name: param, 1815 - value: options.folder }); 1816 - if (checkType(options.position, "number")) { 1817 - // position in folder filtering. 1818 - let param = "positionInFolder" + aQueryConf._qIndex; 1819 - aConditions.push("position = :" + param); 1820 - aQueryConf._params.push({ name: param, 1821 - value: options.position }); 1822 - } 1823 - } 1824 - 1825 - if (options.id) { 1826 - // id filtering. 1827 - let param = "itemId" + aQueryConf._qIndex; 1828 - aConditions.push("item_id = :" + param); 1829 - aQueryConf._params.push({ name: param, 1830 - value: options.id }); 1831 - } 1832 - 1833 - if (options.createdBegin) { 1834 - let param = "createdBeginTime" + aQueryConf._qIndex; 1835 - let beginTime = options.createdBegin.getTime() * 1000; 1836 - aConditions.push("dateAdded >= :" + param); 1837 - aQueryConf._params.push({ name: param, 1838 - value: beginTime }); 1839 - } 1840 - if (options.createdEnd) { 1841 - let param = "createdEndTime" + aQueryConf._qIndex; 1842 - let endTime = options.createdEnd.getTime() * 1000; 1843 - aConditions.push("dateAdded <= :" + param); 1844 - aQueryConf._params.push({ name: param, 1845 - value: endTime }); 1846 - } 1847 - 1848 - if (options.modifiedBegin) { 1849 - let param = "modifiedBeginTime" + aQueryConf._qIndex; 1850 - let beginTime = options.modifiedBegin.getTime() * 1000; 1851 - aConditions.push("lastModified >= :" + param); 1852 - aQueryConf._params.push({ name: param, 1853 - value: beginTime }); 1854 - } 1855 - if (options.modifiedEnd) { 1856 - let param = "modifiedEndTime" + aQueryConf._qIndex; 1857 - let endTime = options.modifiedEnd.getTime() * 1000; 1858 - aConditions.push("lastModified <= :" + param); 1859 - aQueryConf._params.push({ name: param, 1860 - value: endTime }); 1861 - } 1862 - 1863 - if (options.excludeReadOnlyContainers) { 1864 - // Exclude queries and folders annotated as read-only. 1865 - aConditions.push("SUBSTR(page_url, 0, 6) <> 'place:'"); 1866 - aConditions.push( 1867 - "NOT EXISTS( " 1868 - + "SELECT 1 FROM moz_items_annos a " 1869 - + "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " 1870 - + "WHERE a.item_id = b.id AND n.name = :readOnlyAnno " 1871 - + "LIMIT 1 " 1872 - + ")" 1873 - ); 1874 - aQueryConf._params.push({ name: "readOnlyAnno", 1875 - value: PlacesUtils.READ_ONLY_ANNO }); 1876 - } 1877 - 1878 - if (options.onlyContainers) { 1879 - aConditions.push( 1880 - "(item_type <> :bookmark_type OR " 1881 - + "(page_url >= 'place:' AND page_url < 'place;') " 1882 - + ")" 1883 - ); 1884 - aConditions.push("item_type <> :separator_type"); 1885 - aQueryConf._params.push({ name: "separator_type", 1886 - value: PlacesUtils.bookmarks.TYPE_SEPARATOR }); 1887 - } 1888 - 1889 - } 1890 - } 1891 - 1892 - 1893 - if (aQueryConf.visited) { 1894 - if (aBaseQuery != "visits") { 1895 - aConditions.push( 1896 - "EXISTS (SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1)" 1897 - ); 1898 - } 1899 - let options = aQueryConf.visited; 1900 - 1901 - if (checkType(options, "object")) { 1902 - if (options.countMin) { 1903 - let param = "minVisitCount" + aQueryConf._qIndex; 1904 - aConditions.push("visit_count >= :" + param); 1905 - aQueryConf._params.push({ name: param, 1906 - value: options.countMin }); 1907 - } 1908 - if (options.countMax) { 1909 - let param = "maxVisitCount" + aQueryConf._qIndex; 1910 - aConditions.push("visit_count <= :" + param); 1911 - aQueryConf._params.push({ name: param, 1912 - value: options.countMax }); 1913 - } 1914 - 1915 - if (options.transitions.length > 0) { 1916 - let paramPrefix = "transition" + aQueryConf._qIndex; 1917 - if (aBaseQuery == "visits" && options.transitions.length == 1) { 1918 - aConditions.push("visit_type = : " + paramPrefix); 1919 - aQueryConf._params.push({ name: paramPrefix, 1920 - value: options.transitions[0] }); 1921 - } 1922 - else { 1923 - let params = []; 1924 - for (let i = 0; i < options.transitions.length; i++) { 1925 - let param = paramPrefix + "_" + i 1926 - params.push(":" + param); 1927 - aQueryConf._params.push({ name: param, 1928 - value: options.transitions[i] }); 1929 - aConditions.push( 1930 - "EXISTS ( " 1931 - + "SELECT 1 FROM moz_historyvisits " 1932 - + "WHERE place_id = page_id AND visit_type = :" + param + " " 1933 - + "LIMIT 1 " 1934 - + ")" 1935 - ); 1936 - } 1937 - } 1938 - } 1939 - 1940 - if (options.begin) { 1941 - let param = "visitedBeginTime" + aQueryConf._qIndex; 1942 - let beginTime = options.begin.getTime() * 1000; 1943 - aQueryConf._params.push({ name: param, 1944 - value: beginTime }); 1945 - if (aBaseQuery == "visits") { 1946 - aConditions.push("visit_date >= :" + param); 1947 - } 1948 - else { 1949 - aConditions.push( 1950 - "EXISTS( " 1951 - + "SELECT 1 FROM moz_historyvisits " 1952 - + "WHERE visit_date >= :" + param + " AND place_id = page_id " 1953 - + "LIMIT 1 " 1954 - + ")" 1955 - ); 1956 - } 1957 - } 1958 - if (options.end) { 1959 - let param = "visitedEndTime" + aQueryConf._qIndex; 1960 - let endTime = options.end.getTime() * 1000; 1961 - aQueryConf._params.push({ name: param, 1962 - value: endTime }); 1963 - if (aBaseQuery == "visits") { 1964 - aConditions.push("visit_date <= :" + param); 1965 - } 1966 - else { 1967 - aConditions.push( 1968 - "EXISTS( " 1969 - + "SELECT 1 FROM moz_historyvisits " 1970 - + "WHERE visit_date <= :" + param + " AND place_id = page_id " 1971 - + "LIMIT 1 " 1972 - + ")" 1973 - ); 1974 - } 1975 - } 1976 - 1977 - if (options.excludeRedirectSources) { 1978 - aQueryConf._params.push({ name: "transition_redirect_permanent", 1979 - value: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT }); 1980 - aQueryConf._params.push({ name: "transition_redirect_temporary", 1981 - value: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY }); 1982 - if (aBaseQuery == "visits") { 1983 - aConditions.push( 1984 - "NOT EXISTS ( " 1985 - + "SELECT id FROM moz_historyvisits " 1986 - + "WHERE from_visit = visit_id AND visit_type IN (:transition_redirect_permanent, :transition_redirect_temporary) " 1987 - + ")" 1988 - ); 1989 - } 1990 - else { 1991 - // Exclude pages that are only redirect sources. 1992 - aConditions.push( 1993 - "EXISTS ( " 1994 - + "SELECT 1 FROM moz_historyvisits srcs " 1995 - + "LEFT JOIN moz_historyvisits dests ON dests.from_visit = srcs.id " 1996 - + "WHERE srcs.place_id = page_id " 1997 - + "AND (dests.id IS NULL OR dests.visit_type NOT IN (:transition_redirect_permanent, :transition_redirect_temporary)) " 1998 - + "LIMIT 1 " 1999 - + ")" 2000 - ); 2001 - } 2002 - } 2003 - 2004 - if (options.excludeRedirectTargets) { 2005 - aQueryConf._params.push({ name: "transition_redirect_permanent", 2006 - value: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT }); 2007 - aQueryConf._params.push({ name: "transition_redirect_temporary", 2008 - value: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY }); 2009 - if (aBaseQuery == "visits") { 2010 - aConditions.push( 2011 - "visit_type NOT IN (:transition_redirect_permanent, :transition_redirect_temporary)" 2012 - ); 2013 - } 2014 - else { 2015 - // Exclude pages that are only redirect targets. 2016 - aConditions.push( 2017 - "EXISTS ( " 2018 - + "SELECT 1 FROM moz_historyvisits " 2019 - + "WHERE place_id = page_id " 2020 - + "AND visit_type NOT IN (:transition_redirect_permanent, :transition_redirect_temporary) " 2021 - + "LIMIT 1 " 2022 - + ")" 2023 - ); 2024 - } 2025 - } 2026 - 2027 - if (!options.includeHidden) { 2028 - aConditions.push("h.hidden = 0"); 2029 - if (aBaseQuery == "visits") { 2030 - aConditions.push( 2031 - "visit_type NOT IN (:transition_embed, :transition_framed_link)" 2032 - ); 2033 - aQueryConf._params.push({ name: "transition_embed", 2034 - value: Ci.nsINavHistoryService.TRANSITION_EMBED }); 2035 - aQueryConf._params.push({ name: "transition_framed_link", 2036 - value: Ci.nsINavHistoryService.TRANSITION_FRAMED_LINK }); 2037 - } 2038 - } 2039 - } 2040 - } 2041 - 2042 - 2043 - if (aQueryConf.annotated.length > 0) { 2044 - let paramPrefix = "annoName" + aQueryConf._qIndex; 2045 - let params = []; 2046 - for (let i = 0; i < aQueryConf.annotated.length; i++) { 2047 - let param = paramPrefix + "_" + i; 2048 - params.push(":" + param); 2049 - aQueryConf._params.push({ name: param, 2050 - value: aQueryConf.annotated[i] }); 2051 - } 2052 - let param = "annosCount" + aQueryConf._qIndex; 2053 - aQueryConf._params.push({ name: param, 2054 - value: aQueryConf.annotated.length }); 2055 - aConditions.push( 2056 - ":" + param + " = ( " 2057 - + "SELECT count(*) FROM moz_anno_attributes n " 2058 - + "LEFT JOIN moz_annos a ON n.id = a.anno_attribute_id AND a.place_id = h.id " 2059 - + "LEFT JOIN moz_items_annos ia ON n.id =ia.anno_attribute_id AND ia.item_id = b.id " 2060 - + "WHERE name IN (" + params.join(",") + ") " 2061 - + "AND IFNULL(place_id, item_id) NOTNULL " 2062 - + ") " 2063 - ); 2064 - } 2065 - 2066 - 2067 - return aConditions.length > 0 ? "WHERE " + aConditions.join(" AND ") 2068 - : ""; 2069 - } 2070 - } 2071 - 2072 - //////////////////////////////////////////////////////////////////////////////// 2073 - //// StmtCallback 2074 - 2075 - function StmtCallback(aQueryConfs, aCallback, aThisObject) 2076 - { 2077 - this._queryConfs = aQueryConfs; 2078 - this._callbackInfo = { cb: aCallback, scope: aThisObject }; 2079 - this._results = []; 2080 - this._limit = aQueryConfs[0].limit; 2081 - this._currentResultsCount = 0; 2082 - this.pendingQuery = null; 2083 - 2084 - // Collect all post-filtering tasks. These are run as soon as results are 2085 - // available. Filtered results are then immediately returned to the caller 2086 - // unless post-processing has to happen. 2087 - this._postFilteringTasks = []; 2088 - this._queryConfs.forEach(function(aQueryConf) { 2089 - this._postFilteringTasks = 2090 - this._postFilteringTasks.concat(aQueryConf._postFilteringTasks.slice()); 2091 - }, this); 2092 - 2093 - // Collect all post-processing tasks. These are run after all results have 2094 - // been cached. If any post-processing task is defined then no results are 2095 - // returned to the caller till all post-processing is finished. 2096 - this._postProcessingTasks = []; 2097 - this._queryConfs.forEach(function(aQueryConf) { 2098 - this._postProcessingTasks = 2099 - this._postProcessingTasks.concat(aQueryConf._postProcessingTasks.slice()); 2100 - }, this); 2101 - } 2102 - 2103 - StmtCallback.prototype = { 2104 - handleResult: function SC_handleResult(aResultSet) 2105 - { 2106 - let row; 2107 - let results = []; 2108 - while ((row = aResultSet.getNextRow()) != null) { 2109 - results.push(new ResultItem(row, this._queryConfs)); 2110 - } 2111 - 2112 - this._postFilter(results); 2113 - 2114 - this._currentResultsCount += results.length; 2115 - if (this._limit != -1 && this._postProcessingTasks.length == 0 && 2116 - this._currentResultsCount >= this._limit) { 2117 - // No reason for this query to return other results. 2118 - if (this.pendingQuery) 2119 - this.pendingQuery.cancel(); 2120 - // Remove exceeding results. 2121 - let excess = this._currentResultsCount - this._limit; 2122 - results.splice(results.length - excess, excess); 2123 - } 2124 - 2125 - // If this query does not require postProcessing, just push results to the 2126 - // caller. Notice that pushing an empty result set means that we are done 2127 - // so we must avoid it. 2128 - if (this._postProcessingTasks.length == 0 && results.length > 0) 2129 - this._callback(results); 2130 - else 2131 - this._results = this._results.concat(results); 2132 - }, 2133 - 2134 - handleError: function SC_handleError(aError) 2135 - { 2136 - Cu.reportError("PlacesQuery: An error occured while executing a query."); 2137 - }, 2138 - 2139 - handleCompletion: function SC_handleCompletion(aReason) 2140 - { 2141 - if (aReason == Ci.mozIStorageStatementCallback.REASON_FINISHED || 2142 - aReason == Ci.mozIStorageStatementCallback.REASON_CANCELED && 2143 - this._results.length > 0) { 2144 - this._postProcess(this._results); 2145 - 2146 - if (this._limit != -1 && this._results.length > this._limit) { 2147 - // Remove exceeding results. 2148 - let excess = this._results.length - this._limit; 2149 - this._results.splice(this._results.length - excess, excess); 2150 - } 2151 - } 2152 - 2153 - // Notify the caller we have finished pushing results, by pushing an empty 2154 - // set. This happens regardless completion reason. 2155 - this._callback(this._results); 2156 - }, 2157 - 2158 - _postProcess: function SC__postProcess(aResults) { 2159 - // Bail out if there is nothing to post-process. 2160 - if (this._postProcessingTasks.length == 0) 2161 - return; 2162 - 2163 - for (let i = 0; i < this._results.length; i++) { 2164 - this._postProcessingTasks.forEach(function(aPPTask) { 2165 - // Each post-processing task should be able to work on the full set. 2166 - aPPTask(this._results); // TODO: define this better. 2167 - }, this); 2168 - } 2169 - 2170 - // Push results to the caller, if we have any. 2171 - if (aResults.length) 2172 - this._callback(aResults); 2173 - }, 2174 - 2175 - _postFilter: function SC__postFilter(aResults) { 2176 - // Bail out if there is nothing to post-filter. 2177 - if (this._postFilteringTasks.length == 0) 2178 - return; 2179 - 2180 - for (let i = 0; i < aResults.length; i++) { 2181 - this._postFilteringTasks.forEach(function(aPassFilter) { 2182 - if (!aPassFilter(aResults[i])) { 2183 - // Be sure to decrease i since we are removing one element. 2184 - aResults.splice(i--, 1); 2185 - } 2186 - }, this); 2187 - } 2188 - }, 2189 - 2190 - _callback: function SC__callback(aResults) { 2191 - // Enqueue the call, so it runs out of the current task. 2192 - Services.tm.mainThread.dispatch({ 2193 - _callbackInfo: this._callbackInfo, 2194 - run: function() { 2195 - let callback = this._callbackInfo.cb; 2196 - let scope = this._callbackInfo.scope || 2197 - Cu.getGlobalForObject(this._callbackInfo.cb); 2198 - // If there are results, call the callback for each individual result. 2199 - if (aResults.length) 2200 - aResults.forEach(callback, scope); 2201 - // Otherwise, the query must be complete. 2202 - else 2203 - callback.call(scope, false); 2204 - } 2205 - }, Ci.nsIThread.DISPATCH_NORMAL); 2206 - } 2207 - } 2208 - 2209 - 2210 - //////////////////////////////////////////////////////////////////////////////// 2211 - //// ResultItem 2212 - 2213 - function ResultItem(aResultRow, aQueryConfs){ 2214 - if (!(aResultRow instanceof Ci.mozIStorageRow)) 2215 - return; 2216 - this.pageId = aResultRow.getResultByName("page_id"); 2217 - this.uri = aResultRow.getResultByName("page_url"); 2218 - this.title = aResultRow.getResultByName("page_title"); 2219 - let revHost = aResultRow.getResultByName("rev_host"); 2220 - this.host = revHost ? revHost.split("").reverse().join("").substr(1) : ""; 2221 - this.accessCount = aResultRow.getResultByName("visit_count"); 2222 - // TODO: if there is a time constraint time should be the last visit in 2223 - // that time instead. 2224 - this.time = new Date(aResultRow.getResultByName("visit_date")/1000); 2225 - this.icon = aResultRow.getResultByName("icon_url"); 2226 - this.sessionId = aResultRow.getResultByName("session"); 2227 - this.itemId = aResultRow.getResultByName("item_id"); 2228 - this.isBookmarked = !!this.itemId; 2229 - this.dateAdded = new Date(aResultRow.getResultByName("dateAdded")/1000); 2230 - this.lastModified = new Date(aResultRow.getResultByName("lastModified")/1000); 2231 - this.parentId = aResultRow.getResultByName("parent_id"); 2232 - let tags = aResultRow.getResultByName("tags"); 2233 - this.tags = tags ? tags.split(TAGS_SEPARATOR) : []; 2234 - this.bookmarkIndex = aResultRow.getResultByName("position"); 2235 - this.frecency = aResultRow.getResultByName("frecency"); 2236 - this.visitId = aResultRow.getResultByName("visit_id"); 2237 - this.referringVisitId = aResultRow.getResultByName("from_visit"); 2238 - this.referringUri = aResultRow.getResultByName("from_visit_uri"); 2239 - this.transitionType = aResultRow.getResultByName("visit_type"); 2240 - let itemType = aResultRow.getResultByName("item_type"); 2241 - this.type = getNodeType(this, itemType); 2242 - this.readableType = getReadableItemType(this, itemType); 2243 - 2244 - let currentResult = this; 2245 - // Index of the query that generated this result. 2246 - 2247 - XPCOMUtils.defineLazyGetter(this, "query", function() { 2248 - if (currentResult.readableType != "container") 2249 - throw new Error("Cannot get query for a non container."); 2250 - 2251 - if (currentResult.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_QUERY) { 2252 - // PlacesQuery can deserialize most place: uris. 2253 - // This is not completely correct, since options from the place: uri and 2254 - // current ones should be merged. 2255 - return new PlacesQuery(currentResult.uri); 2256 - } 2257 - 2258 - if (currentResult.type == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER) { 2259 - let queryConfs = [].concat(aQueryConfs); 2260 - queryConfs.forEach(function(aQueryConf) { 2261 - aQueryConf.bookmarked.folder = currentResult.itemId; 2262 - }); 2263 - return new PlacesQuery(queryConfs); 2264 - } 2265 - 2266 - throw new Error("Cannot get query for this kind of container."); 2267 - }); 2268 - } 2269 - 2270 - ResultItem.prototype = {}
+85
manifest.json
··· 1 + { 2 + "name": "Peek", 3 + "description": "Peek at your favorite sites without breaking your flow.", 4 + "version": "4.0.0", 5 + "manifest_version": 2, 6 + 7 + "background": { 8 + "scripts": ["background.js"] 9 + }, 10 + 11 + "permissions": [ 12 + "activeTab", 13 + "tabs", 14 + "<all_urls>", 15 + "bookmarks" 16 + ], 17 + 18 + "icons": { 19 + "48": "icons/peek.svg", 20 + "96": "icons/peek.svg" 21 + }, 22 + 23 + "commands": { 24 + "toggle-peek-1": { 25 + "suggested_key": { 26 + "default": "Alt+Shift+1" 27 + }, 28 + "description": "Open Peek" 29 + }, 30 + "toggle-peek-2": { 31 + "suggested_key": { 32 + "default": "Alt+Shift+2" 33 + }, 34 + "description": "Open Peek" 35 + }, 36 + "toggle-peek-3": { 37 + "suggested_key": { 38 + "default": "Alt+Shift+3" 39 + }, 40 + "description": "Open Peek" 41 + }, 42 + "toggle-peek-4": { 43 + "suggested_key": { 44 + "default": "Alt+Shift+4" 45 + }, 46 + "description": "Open Peek" 47 + }, 48 + "toggle-peek-5": { 49 + "suggested_key": { 50 + "default": "Alt+Shift+5" 51 + }, 52 + "description": "Open Peek" 53 + }, 54 + "toggle-peek-6": { 55 + "suggested_key": { 56 + "default": "Alt+Shift+6" 57 + }, 58 + "description": "Open Peek" 59 + }, 60 + "toggle-peek-7": { 61 + "suggested_key": { 62 + "default": "Alt+Shift+7" 63 + }, 64 + "description": "Open Peek" 65 + }, 66 + "toggle-peek-8": { 67 + "suggested_key": { 68 + "default": "Alt+Shift+8" 69 + }, 70 + "description": "Open Peek" 71 + }, 72 + "toggle-peek-9": { 73 + "suggested_key": { 74 + "default": "Alt+Shift+9" 75 + }, 76 + "description": "Open Peek" 77 + }, 78 + "toggle-peek-0": { 79 + "suggested_key": { 80 + "default": "Alt+Shift+0" 81 + }, 82 + "description": "Open Peek" 83 + } 84 + } 85 + }
misc/peek.sketch

This is a binary file and will not be displayed.

-16
package.json
··· 1 - { 2 - "name": "peek", 3 - "license": "MPL 1.1/GPL 2.0/LGPL 2.1", 4 - "author": "Dietrich Ayala", 5 - "version": "3.1", 6 - "fullName": "Peek", 7 - "id": "jid1-xEAuRv8GzibUdw", 8 - "description": "Peek at your favorite sites without breaking your flow.", 9 - "preferences": [{ 10 - "name": "urls", 11 - "title": "URLs", 12 - "type": "string", 13 - "value": "", 14 - "hidden": true 15 - }] 16 - }
-32
test/test-main.js
··· 1 - const main = require("main"); 2 - 3 - exports.test_test_run = function(test) { 4 - test.pass("Unit test running!"); 5 - }; 6 - 7 - exports.test_id = function(test) { 8 - test.assert(require("self").id.length > 0); 9 - }; 10 - 11 - exports.test_url = function(test) { 12 - require("request").Request({ 13 - url: "http://www.mozilla.org/", 14 - onComplete: function(response) { 15 - test.assertEqual(response.statusText, "OK"); 16 - test.done(); 17 - } 18 - }).get(); 19 - test.waitUntilDone(20000); 20 - }; 21 - 22 - exports.test_open_tab = function(test) { 23 - const tabs = require("tabs"); 24 - tabs.open({ 25 - url: "http://www.mozilla.org/", 26 - onReady: function(tab) { 27 - test.assertEqual(tab.url, "http://www.mozilla.org/"); 28 - test.done(); 29 - } 30 - }); 31 - test.waitUntilDone(20000); 32 - };