Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.lein-repl-history
target
.repl
out
.nrepl-port
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
# Clojurifier

A Chrome extension that replaces occurrences of the words "scala" and "haskell" to "Clojure" in web pages text nodes.

## how to build
```
lein chromebuild once
```
The unpacked extension will be in target/unpacked
23 changes: 23 additions & 0 deletions project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
(defproject clojurifier "0.2.0-SNAPSHOT"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]
[org.clojure/clojurescript "0.0-2156"]
[org.clojure/core.async "0.1.242.0-44b1e3-alpha"]
[khroma "0.0.2"]
[prismatic/dommy "0.1.2"]]
:source-paths ["src"]
:profiles {:dev {:plugins [[com.cemerick/austin "0.1.3"]
[lein-cljsbuild "1.0.1"]
[lein-resource "0.3.6"]
[lein-chromebuild "0.1.0"]]
:cljsbuild {:builds {:main
{:source-paths ["src"]
:compiler {:output-to "target/unpacked/clojurifier.js"
:output-dir "target/js"
:optimizations :whitespace
:pretty-print true}}}}
:chromebuild {:resource-paths ["resources/js" "resources/html" "resources/images"]
:target-path "target/unpacked"}
}
})
Empty file added resources/html/popup.html
Empty file.
Binary file added resources/images/icon128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/images/icon16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added resources/images/icon48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions resources/js/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
clojurifier.background.init();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What does it do? I couldn't find a clojurifier.background namespace.

1 change: 1 addition & 0 deletions resources/js/content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
clojurifier.content.init();
18 changes: 18 additions & 0 deletions resources/js/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"name": "Clojurifier",
"version": "0.2",
"icons": {
"16": "icon16.png",
"48": "icon48.png",
"128": "icon128.png"
},
"content_scripts": [
{
"matches": ["*://*/*"],
"js": ["clojurifier.js", "content.js"],
"run_at": "document_end"
}
],
"manifest_version": 2
}

33 changes: 33 additions & 0 deletions src/clojurifier/clojurifier.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
(ns clojurifier.clojurifier
(:require [clojure.string :as s]
[khroma.log :as console]))


; the strings we want to replace
(def mapping {(js/RegExp. "haskell" "i") "Clojure"
(js/RegExp. "scala" "i") "Clojure"})


(defn clojurize
"Replaces all matched strings by 'mapping' in the element"
[element]
(doseq [[k v] mapping]
(set! (.-textContent element) (.replace (.-textContent element) k v))))


(defn- clojurable?
"Decides if we want to try finding matching strings in the element.
Script and textarea elements are out of our scope."
[node]
(and (= (.-nodeType node) 1) (not (#{"script" "textarea"} (.-nodeName node)))))


(defn clojurify
"Replaces all matched strings by 'mapping' in the element and its children if the element is a text element"
[element]
(let [nn (s/lower-case (.-nodeName element))]
(if (= nn "#text")
(clojurize element)
(when (clojurable? element)
(dotimes [i (.-length (.-childNodes element))]
(clojurify (.item (.-childNodes element) i) clojurize))))))
12 changes: 12 additions & 0 deletions src/clojurifier/content.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
(ns clojurifier.content
(:require [clojurifier.mutant :refer [observe-body]]
[clojurifier.clojurifier :refer [clojurify]])
(:require-macros [dommy.macros :refer [sel1]]))

(defn init
"Clojurifies everything on the page and starts observing the body element for changes"
[]
(clojurify (sel1 :body))
(observe-body))


33 changes: 33 additions & 0 deletions src/clojurifier/mutant.cljs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
(ns clojurifier.mutant
(:require [khroma.log :as console]
[clojurifier.clojurifier :refer [clojurify]]))


; so we can use the circular dependency between observe-element and handle-mutation
(declare observe-element)

(defn handle-mutation
"Handles the change of an element. Clojurifies it and starts observing its children."
[mutation]
(clojurify (.-target mutation))
(doseq [child (-> mutation .-target .-childNodes (array-seq 0))]
(observe-element child)))

(defn handle-mutations
"Handles the incoming mutations one by one"
[mutations]
(doseq [m (js->clj mutations)]
(handle-mutation m)))

(defn observe-element
"Starts observing an element, calling handle-mutations on every attribute, child or text data change"
[elem]
(let [observer (js/MutationObserver. handle-mutations)]
(.observe observer elem
(clj->js {:attributes true :childList true :characterData true}))))

(defn observe-body
"Observes the body element for changes, indirectly watches all of it's children too"
[]
(observe-element js/document.body))