Trevor Alexander
9 years ago
16 changed files with 2704 additions and 0 deletions
@ -0,0 +1 @@ |
|||||||
|
web: java $JVM_OPTS -cp target/twister-renyan.jar clojure.main -m twister-renyan.server |
@ -0,0 +1,32 @@ |
|||||||
|
(ns twister-renyan.repl |
||||||
|
(:use twister-renyan.handler |
||||||
|
ring.server.standalone |
||||||
|
[ring.middleware file-info file])) |
||||||
|
|
||||||
|
(defonce server (atom nil)) |
||||||
|
|
||||||
|
(defn get-handler [] |
||||||
|
;; #'app expands to (var app) so that when we reload our code, |
||||||
|
;; the server is forced to re-resolve the symbol in the var |
||||||
|
;; rather than having its own copy. When the root binding |
||||||
|
;; changes, the server picks it up without having to restart. |
||||||
|
(-> #'app |
||||||
|
; Makes static assets in $PROJECT_DIR/resources/public/ available. |
||||||
|
(wrap-file "resources") |
||||||
|
; Content-Type, Content-Length, and Last Modified headers for files in body |
||||||
|
(wrap-file-info))) |
||||||
|
|
||||||
|
(defn start-server |
||||||
|
"used for starting the server in development mode from REPL" |
||||||
|
[& [port]] |
||||||
|
(let [port (if port (Integer/parseInt port) 3000)] |
||||||
|
(reset! server |
||||||
|
(serve (get-handler) |
||||||
|
{:port port |
||||||
|
:auto-reload? true |
||||||
|
:join? false})) |
||||||
|
(println (str "You can view the site at http://localhost:" port)))) |
||||||
|
|
||||||
|
(defn stop-server [] |
||||||
|
(.stop @server) |
||||||
|
(reset! server nil)) |
@ -0,0 +1,11 @@ |
|||||||
|
(ns ^:figwheel-no-load twister-renyan.dev |
||||||
|
(:require [twister-renyan.core :as core] |
||||||
|
[figwheel.client :as figwheel :include-macros true])) |
||||||
|
|
||||||
|
(enable-console-print!) |
||||||
|
|
||||||
|
(figwheel/watch-and-reload |
||||||
|
:websocket-url "ws://localhost:3449/figwheel-ws" |
||||||
|
:jsload-callback core/mount-root) |
||||||
|
|
||||||
|
(core/init!) |
@ -0,0 +1,7 @@ |
|||||||
|
(ns twister-renyan.prod |
||||||
|
(:require [twister-renyan.core :as core])) |
||||||
|
|
||||||
|
;;ignore println statements in prod |
||||||
|
(set! *print-fn* (fn [& _])) |
||||||
|
|
||||||
|
(core/init!) |
@ -0,0 +1,96 @@ |
|||||||
|
(defproject twister-renyan "0.1.0-SNAPSHOT" |
||||||
|
:description "FIXME: write description" |
||||||
|
:url "http://example.com/FIXME" |
||||||
|
:license {:name "Eclipse Public License" |
||||||
|
:url "http://www.eclipse.org/legal/epl-v10.html"} |
||||||
|
|
||||||
|
:dependencies [[org.clojure/clojure "1.7.0"] |
||||||
|
[ring-server "0.4.0"] |
||||||
|
[reagent "0.5.1"] |
||||||
|
[reagent-forms "0.5.11"] |
||||||
|
[reagent-utils "0.1.5"] |
||||||
|
[ring "1.4.0"] |
||||||
|
[ring/ring-defaults "0.1.5"] |
||||||
|
[prone "0.8.2"] |
||||||
|
[compojure "1.4.0"] |
||||||
|
[hiccup "1.0.5"] |
||||||
|
[environ "1.0.1"] |
||||||
|
[org.clojure/clojurescript "1.7.122" :scope "provided"] |
||||||
|
[secretary "1.2.3"]] |
||||||
|
|
||||||
|
:plugins [[lein-environ "1.0.1"] |
||||||
|
[lein-asset-minifier "0.2.2"]] |
||||||
|
|
||||||
|
:ring {:handler twister-renyan.handler/app |
||||||
|
:uberwar-name "twister-renyan.war"} |
||||||
|
|
||||||
|
:min-lein-version "2.5.0" |
||||||
|
|
||||||
|
:uberjar-name "twister-renyan.jar" |
||||||
|
|
||||||
|
:main twister-renyan.server |
||||||
|
|
||||||
|
:clean-targets ^{:protect false} [:target-path |
||||||
|
[:cljsbuild :builds :app :compiler :output-dir] |
||||||
|
[:cljsbuild :builds :app :compiler :output-to]] |
||||||
|
|
||||||
|
:source-paths ["src/clj" "src/cljc"] |
||||||
|
|
||||||
|
:minify-assets |
||||||
|
{:assets |
||||||
|
{"resources/public/css/site.min.css" "resources/public/css/site.css"}} |
||||||
|
|
||||||
|
:cljsbuild {:builds {:app {:source-paths ["src/cljs" "src/cljc"] |
||||||
|
:compiler {:output-to "resources/public/js/app.js" |
||||||
|
:output-dir "resources/public/js/out" |
||||||
|
:asset-path "js/out" |
||||||
|
:optimizations :none |
||||||
|
:pretty-print true}}}} |
||||||
|
|
||||||
|
:profiles {:dev {:repl-options {:init-ns twister-renyan.repl} |
||||||
|
|
||||||
|
:dependencies [[ring/ring-mock "0.3.0"] |
||||||
|
[ring/ring-devel "1.4.0"] |
||||||
|
[lein-figwheel "0.4.0"] |
||||||
|
[org.clojure/tools.nrepl "0.2.11"] |
||||||
|
[pjstadig/humane-test-output "0.7.0"]] |
||||||
|
|
||||||
|
:source-paths ["env/dev/clj"] |
||||||
|
:plugins [[lein-figwheel "0.4.0"] |
||||||
|
[lein-cljsbuild "1.0.6"] |
||||||
|
[com.cemerick/clojurescript.test "0.3.3"]] |
||||||
|
|
||||||
|
:injections [(require 'pjstadig.humane-test-output) |
||||||
|
(pjstadig.humane-test-output/activate!)] |
||||||
|
|
||||||
|
:figwheel {:http-server-root "public" |
||||||
|
:server-port 3449 |
||||||
|
:nrepl-port 7002 |
||||||
|
:css-dirs ["resources/public/css"] |
||||||
|
:ring-handler twister-renyan.handler/app} |
||||||
|
|
||||||
|
:env {:dev true} |
||||||
|
|
||||||
|
:cljsbuild {:builds {:app {:source-paths ["env/dev/cljs"] |
||||||
|
:compiler {:main "twister-renyan.dev" |
||||||
|
:source-map true}} |
||||||
|
:test {:source-paths ["src/cljs" "src/cljc" "test/cljs"] |
||||||
|
:compiler {:output-to "target/test.js" |
||||||
|
:optimizations :whitespace |
||||||
|
:pretty-print true}}} |
||||||
|
:test-commands {"unit" ["phantomjs" :runner |
||||||
|
"test/vendor/es5-shim.js" |
||||||
|
"test/vendor/es5-sham.js" |
||||||
|
"test/vendor/console-polyfill.js" |
||||||
|
"target/test.js"]}}} |
||||||
|
|
||||||
|
:uberjar {:hooks [leiningen.cljsbuild minify-assets.plugin/hooks] |
||||||
|
:env {:production true} |
||||||
|
:aot :all |
||||||
|
:omit-source true |
||||||
|
:cljsbuild {:jar true |
||||||
|
:builds {:app |
||||||
|
{:source-paths ["env/prod/cljs"] |
||||||
|
:compiler |
||||||
|
{:optimizations :advanced |
||||||
|
:pretty-print false}}}}}}) |
@ -0,0 +1,34 @@ |
|||||||
|
body { |
||||||
|
font-family: 'Helvetica Neue', Verdana, Helvetica, Arial, sans-serif; |
||||||
|
max-width: 600px; |
||||||
|
margin: 0 auto; |
||||||
|
padding-top: 72px; |
||||||
|
-webkit-font-smoothing: antialiased; |
||||||
|
font-size: 1.125em; |
||||||
|
color: #333; |
||||||
|
line-height: 1.5em; |
||||||
|
} |
||||||
|
|
||||||
|
h1, h2, h3 { |
||||||
|
color: #000; |
||||||
|
} |
||||||
|
h1 { |
||||||
|
font-size: 2.5em |
||||||
|
} |
||||||
|
|
||||||
|
h2 { |
||||||
|
font-size: 2em |
||||||
|
} |
||||||
|
|
||||||
|
h3 { |
||||||
|
font-size: 1.5em |
||||||
|
} |
||||||
|
|
||||||
|
a { |
||||||
|
text-decoration: none; |
||||||
|
color: #09f; |
||||||
|
} |
||||||
|
|
||||||
|
a:hover { |
||||||
|
text-decoration: underline; |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
(ns twister-renyan.handler |
||||||
|
(:require [compojure.core :refer [GET defroutes]] |
||||||
|
[compojure.route :refer [not-found resources]] |
||||||
|
[ring.middleware.defaults :refer [site-defaults wrap-defaults]] |
||||||
|
[hiccup.core :refer [html]] |
||||||
|
[hiccup.page :refer [include-js include-css]] |
||||||
|
[prone.middleware :refer [wrap-exceptions]] |
||||||
|
[ring.middleware.reload :refer [wrap-reload]] |
||||||
|
[environ.core :refer [env]])) |
||||||
|
|
||||||
|
(def home-page |
||||||
|
(html |
||||||
|
[:html |
||||||
|
[:head |
||||||
|
[:meta {:charset "utf-8"}] |
||||||
|
[:meta {:name "viewport" |
||||||
|
:content "width=device-width, initial-scale=1"}] |
||||||
|
(include-css (if (env :dev) "css/site.css" "css/site.min.css"))] |
||||||
|
[:body |
||||||
|
[:div#app |
||||||
|
[:h3 "ClojureScript has not been compiled!"] |
||||||
|
[:p "please run " |
||||||
|
[:b "lein figwheel"] |
||||||
|
" in order to start the compiler"]] |
||||||
|
(include-js "js/app.js")]])) |
||||||
|
|
||||||
|
(defroutes routes |
||||||
|
(GET "/" [] home-page) |
||||||
|
(resources "/") |
||||||
|
(not-found "Not Found")) |
||||||
|
|
||||||
|
(def app |
||||||
|
(let [handler (wrap-defaults #'routes site-defaults)] |
||||||
|
(if (env :dev) (-> handler wrap-exceptions wrap-reload) handler))) |
@ -0,0 +1,9 @@ |
|||||||
|
(ns twister-renyan.server |
||||||
|
(:require [twister-renyan.handler :refer [app]] |
||||||
|
[environ.core :refer [env]] |
||||||
|
[ring.adapter.jetty :refer [run-jetty]]) |
||||||
|
(:gen-class)) |
||||||
|
|
||||||
|
(defn -main [& args] |
||||||
|
(let [port (Integer/parseInt (or (env :port) "3000"))] |
||||||
|
(run-jetty app {:port port :join? false}))) |
@ -0,0 +1,6 @@ |
|||||||
|
(ns twister-renyan.util) |
||||||
|
|
||||||
|
(defn foo-cljx [x] |
||||||
|
"I don't do a whole lot." |
||||||
|
[x] |
||||||
|
(println x "Hello, World!")) |
@ -0,0 +1,590 @@ |
|||||||
|
(ns twister-renyan.core |
||||||
|
(:require [reagent.core :as reagent :refer [atom]] |
||||||
|
[reagent.session :as session] |
||||||
|
[secretary.core :as secretary :include-macros true] |
||||||
|
[goog.events :as events] |
||||||
|
[goog.history.EventType :as EventType]) |
||||||
|
(:import goog.History)) |
||||||
|
|
||||||
|
;; ------------------------- |
||||||
|
;; Components/Templates |
||||||
|
|
||||||
|
(defn post-area [] |
||||||
|
[:div.post-area |
||||||
|
[:form.post-area-new |
||||||
|
[:textarea {:placeholder "New Post..."}] |
||||||
|
[:div.post-area-extras |
||||||
|
[:span.post-area-remaining 140] |
||||||
|
[:button.undo-unicode.disabled {:disabled "disabled"} "undo"] |
||||||
|
[:button.post-submit.disabled {:disabled "disabled"} "post"]]]]) |
||||||
|
|
||||||
|
(defn loading-roller [] |
||||||
|
[:div.loading-roller [:div]]) |
||||||
|
|
||||||
|
(defn refresh-button |
||||||
|
([] [:a.refresh.label "Refresh"]) |
||||||
|
;; optional argument: string of extra classes to append |
||||||
|
([class-string] [:a.refresh.label {:class class-string }"Refresh"])) |
||||||
|
|
||||||
|
(defn user-photo |
||||||
|
([] [:img.twister-user-photo |
||||||
|
{:src "img/grayed_avatar_placeholder_24.png" :alt "user-photo"}]) |
||||||
|
([extra-img-classes-string] [:img.twister-user-photo |
||||||
|
{:src "img/grayed_avatar_placeholder_24.png" |
||||||
|
:alt "user-photo" |
||||||
|
:class extra-img-classes-string}]) |
||||||
|
([extra-img-classes-string photo-url] [:img.twister-user-photo |
||||||
|
{:src photo-url :alt "user-photo" |
||||||
|
:class extra-img-classes-string}])) |
||||||
|
|
||||||
|
(defn user-photo-link |
||||||
|
;; default case--no photo url |
||||||
|
([] [:a.twister-user-name.open-profile-modal |
||||||
|
{:href "#"} (user-photo)]) |
||||||
|
;; extra classes for img element |
||||||
|
([extra-img-classes-string] [:a.twister-user-name.open-profile-modal |
||||||
|
{:href "#"} |
||||||
|
(user-photo extra-img-classes-string)]) |
||||||
|
;; photo url and extra classes |
||||||
|
([extra-img-classes-string photo-url] [:a.twister-user-name.open-profile-modal |
||||||
|
{:href "#"} |
||||||
|
(user-photo extra-img-classes-string |
||||||
|
photo-url)])) |
||||||
|
|
||||||
|
(defn search-profile-template [] |
||||||
|
[:div#search-profile-template |
||||||
|
[:li |
||||||
|
[:div.mini-profile.info |
||||||
|
(user-photo-link "mini-profile-photo") |
||||||
|
[:span.mini-screen-name "@"] |
||||||
|
[:span.mini-profile-name]] |
||||||
|
[:button.follow "Follow"]]]) |
||||||
|
|
||||||
|
(defn who-to-follow-template [] |
||||||
|
[:div#who-to-follow-template |
||||||
|
[:div |
||||||
|
[:h3.label "Who to Follow"] |
||||||
|
[:small "."] |
||||||
|
(refresh-button "refresh-user") |
||||||
|
[:small "."] |
||||||
|
[:a.view-all-users {:href "#whotofollow"} "View All"] |
||||||
|
[:ol.follow-suggestions |
||||||
|
;; follow-suggestion-template here |
||||||
|
]] |
||||||
|
(loading-roller)]) |
||||||
|
|
||||||
|
(defn toptrends-template [] |
||||||
|
[:div#toptrends-template |
||||||
|
[:div |
||||||
|
[:h3.label "Top Trends"] |
||||||
|
[:small "."] |
||||||
|
(refresh-button "refresh-toptrends") |
||||||
|
[:ol.toptrends-list]] |
||||||
|
(loading-roller)]) |
||||||
|
|
||||||
|
(defn twistday-reminder-template [] |
||||||
|
[:div#twistday-reminder-template |
||||||
|
[:div |
||||||
|
[:h3.label "Who's celebrating their Twistday?"] |
||||||
|
[:small "."] |
||||||
|
(refresh-button) |
||||||
|
[:div.current |
||||||
|
[:h4.label "Today's luckies: "] |
||||||
|
[:ol.list |
||||||
|
;; twistday-reminder-suggestion-template here |
||||||
|
]] |
||||||
|
[:div.upcoming |
||||||
|
[:h4.label "Upcoming ones: "] |
||||||
|
[:ol.list |
||||||
|
;; twistday-reminder-suggestion-template here |
||||||
|
]]] |
||||||
|
(loading-roller)]) |
||||||
|
|
||||||
|
(defn twistday-reminder-suggestion-template [] |
||||||
|
[:li#twistday-reminder-suggestion-template.twister-user |
||||||
|
[:div.twister-user-photo (user-photo-link)] |
||||||
|
[:div.twister-user-info {:data-screen-name ""} |
||||||
|
[:a.twister-user-name.open-profile-modal {:href "#"} |
||||||
|
[:div.twister-user-full] |
||||||
|
[:div.twister-user-tag]]] |
||||||
|
[:div |
||||||
|
[:span.twisterday]]]) |
||||||
|
|
||||||
|
(defn follow-suggestion-template [] |
||||||
|
[:li#follow-suggestion-template.twister-user |
||||||
|
[:div (user-photo-link)] |
||||||
|
[:div.twister-user-info {:data-screen-name ""} |
||||||
|
[:a.twister-user-name.open-profile-modal {:href "#"} |
||||||
|
[:span.twister-user-full] |
||||||
|
[:span.twister-user-tag]] |
||||||
|
[:div.bio] |
||||||
|
[:div.followers |
||||||
|
[:span.label "Followed by"] |
||||||
|
[:a.twister-by-user-name.open-profile-modal |
||||||
|
[:span.followed-by]]] |
||||||
|
[:a.twister-user-remove "×"] |
||||||
|
[:button.follow "Follow"]]]) |
||||||
|
|
||||||
|
(defn expanded-post [] |
||||||
|
[:ol.expanded-post]) |
||||||
|
|
||||||
|
(defn post-preview-template [] |
||||||
|
[:div#post-preview-template |
||||||
|
[:div#post-preview.post-text]]) |
||||||
|
|
||||||
|
(defn post-template [] |
||||||
|
[:li#post-template.module.post {:data-time ""} |
||||||
|
[:div.post-data {:data-userpost "" |
||||||
|
:data-content_to_rt "" |
||||||
|
:data-content_to_sigrt "" |
||||||
|
:data-screen-name "" |
||||||
|
:data-id "" |
||||||
|
:data-text "" |
||||||
|
:data-text-mentions ""} |
||||||
|
[:div.post-photo(user-photo)] |
||||||
|
[:div.post-info |
||||||
|
[:a.post-info-name.open-profile-modal {:href "#"}] |
||||||
|
[:span.post-info-tag] |
||||||
|
[:a.post-info-time [:span.post-info-sent] [:span]]] |
||||||
|
[:p.post-text] |
||||||
|
[:div.post-context {:style {:display "none"}}] |
||||||
|
[:span.post-expand "Expand"] |
||||||
|
[:div.post-interactions |
||||||
|
[:span.post-reply "Reply"] |
||||||
|
[:span.post-propagate "Retransmit"] |
||||||
|
;; [:span.post-favorite "Favorite"] one day... |
||||||
|
] |
||||||
|
[:div.expanded-content {:style {:display "none"}} |
||||||
|
[:ul.post-stats {:style {:display "none"}} |
||||||
|
[:li.stat-count |
||||||
|
[:span.stat-count-value] |
||||||
|
[:span "Retransmits"]] |
||||||
|
[:li.avatar-row |
||||||
|
;; avatar-row-template here |
||||||
|
]] |
||||||
|
[:div.preview-container] |
||||||
|
[:div.post-reply-content {:style {:display "block"}} |
||||||
|
(post-area)] |
||||||
|
[:span.show-more.label "Show more in this conversation..."]]]]) |
||||||
|
|
||||||
|
(defn post-rt-reference-template [] |
||||||
|
[:div.post-rt-reference |
||||||
|
[:div.post-photo (user-photo "avatar")] |
||||||
|
[:div.post-info |
||||||
|
[:a.post-info-name.open-profile-modal {:href "#"}] |
||||||
|
[:span.post-info-tag] |
||||||
|
[:a.post-info-time [:span]]] |
||||||
|
[:p.post-text]]) |
||||||
|
|
||||||
|
(defn post-retransmitted-by-template [] |
||||||
|
[:div#post-retransmitted-by-template |
||||||
|
[:i.post-retransmited-icon] |
||||||
|
[:span "twisted again by"] [:span] |
||||||
|
[:a.post-re-transmited-by.open-profile-modal {:href ""}]]) |
||||||
|
|
||||||
|
(defn msg-user-link-template [] |
||||||
|
[:a#msg-user-link-template.open-profile-modal]) |
||||||
|
(defn external-page-link-template [] |
||||||
|
[:a#external-page-link-template {:rel "nofollow" :target "_blank"}]) |
||||||
|
|
||||||
|
(defn hashtag-link-template [] |
||||||
|
[:a#hashtag-link-template.open-hashtag-modal]) |
||||||
|
|
||||||
|
(defn avatar-row-template [] |
||||||
|
[:a#avatar-row-template.open-profile-modal {:href ""} |
||||||
|
(user-photo) |
||||||
|
[:span.user-name-tooltip]]) |
||||||
|
|
||||||
|
(defn modal-wrapper [modal-content] |
||||||
|
[:div.modal-wrapper |
||||||
|
[:div.modal-header |
||||||
|
[:h3] |
||||||
|
[:span#closeModal.modal-close "×"] |
||||||
|
[:span.modal-back "<"] |
||||||
|
[:span.mark-all-as-read]] |
||||||
|
[:div.modal-content modal-content] |
||||||
|
[:div.modal-blackout]]) |
||||||
|
|
||||||
|
(defn prompt-wrapper [prompt-content] |
||||||
|
[:div.prompt-wrapper |
||||||
|
[:div.modal-header |
||||||
|
[:h3] |
||||||
|
[:span.modal-close.prompt-close "×"]] |
||||||
|
[:div.modal-content prompt-content]]) |
||||||
|
|
||||||
|
(defn confirm-popup-template [template-content] |
||||||
|
[:div#confirm-popup-template |
||||||
|
[:div.message template-content] |
||||||
|
[:div.modal-buttons |
||||||
|
[:button.confirm] |
||||||
|
[:button.cancel]]]) |
||||||
|
|
||||||
|
(defn retwist-modal-template [] |
||||||
|
[:div#retwist-modal-template |
||||||
|
(post-area) |
||||||
|
[:div.modal-buttons |
||||||
|
[:span.switch-mode "Switch to Reply"]]]) |
||||||
|
|
||||||
|
(defn reply-modal-template [] |
||||||
|
[:div#reply-modal-template |
||||||
|
(post-area) |
||||||
|
[:div.modal-buttons |
||||||
|
[:span.switch-mode "Switch to Retransmit"]]]) |
||||||
|
|
||||||
|
(defn direct-messages-template [] |
||||||
|
[:div.direct-messages-template |
||||||
|
[:ol.direct-messages-list |
||||||
|
;; dm-snippet-template here |
||||||
|
]]) |
||||||
|
|
||||||
|
(defn dm-snippet-template [] |
||||||
|
[:li#dm-snippet-template.module.post.message |
||||||
|
[:div.post-photo (user-photo)] |
||||||
|
[:div.post-info |
||||||
|
[:a.post-info-name.open-profile-modal {:href "#"}] |
||||||
|
[:span.post-info-tag "@"] |
||||||
|
[:a.post-info-time {:href "#" :title ""}] [:span]] |
||||||
|
[:pp.post-text]]) |
||||||
|
|
||||||
|
(defn messages-thread-template [] |
||||||
|
[:div.messages-thread-template |
||||||
|
:ol.direct-messages-thread |
||||||
|
;; dm-chat-template here |
||||||
|
]) |
||||||
|
|
||||||
|
(defn dm-chat-template [] |
||||||
|
[:li#dm-chat-template.module.post.message |
||||||
|
(user-photo) |
||||||
|
[:div.post-info |
||||||
|
[:a.post-info-name.open-profile.modal] |
||||||
|
[:a.post-info-time [:span.post-info-sent] [:span]]] |
||||||
|
[:p.post-text]]) |
||||||
|
|
||||||
|
(defn dm-form-template [] |
||||||
|
[:div.dm-form-template |
||||||
|
[:form.post-area-new.open |
||||||
|
[:textarea {:placeholder "New direct message..."}] |
||||||
|
[:div.post-area.extras |
||||||
|
[:span.post-area-remaining 140] |
||||||
|
[:button.undo-unicode.disabled {:disabled "disabled"} "undo"] |
||||||
|
[:button.dm-submit.disabled |
||||||
|
{:disabled "disabled" |
||||||
|
:title "Direct messages are encrypted; only you and the recipient can read them."}]]]]) |
||||||
|
|
||||||
|
(defn group-messages-profile-modal-control-template [] |
||||||
|
[:div.group-messages-control.b-buttons |
||||||
|
[:button.new "New group"] |
||||||
|
[:button.join "Join group"]]) |
||||||
|
|
||||||
|
(defn group-messages-messages-modal-control-template [] |
||||||
|
[:div.group-messages-control.b-buttons |
||||||
|
[:button.profile "Profile"] |
||||||
|
[:button.invite "Invite peers"] |
||||||
|
[:button.leave "Leave group"] |
||||||
|
[:div.invite-form |
||||||
|
[:textarea] |
||||||
|
[:button.disabled {:disabled "disabled"} "Invite"]]]) |
||||||
|
|
||||||
|
(defn group-profile-modal-template [] |
||||||
|
[:div#group-profile-modal-template |
||||||
|
[:div.profile-card {:data-screen-name ""} |
||||||
|
[:div.profile-card-main |
||||||
|
[:div.profile-bio]]] |
||||||
|
[:div.profile-card-buttons.group-messages.control.b-buttons |
||||||
|
[:button.direct-messages-with-user {:disabled "disabled"} "Messages"] |
||||||
|
[:button.invite {:disabled "disabled"} "Invite peers"] |
||||||
|
[:button.invite {:disabled "disabled"} "Secret Key"] |
||||||
|
[:button.invite {:disabled "disabled"} "Leave group"] |
||||||
|
[:div.invite-form |
||||||
|
[:textarea] |
||||||
|
[:button {:disabled "disabled"} "Invite"]] |
||||||
|
[:div.secret-key]] |
||||||
|
[:div.members]]) |
||||||
|
|
||||||
|
(defn group-profile-member-template [] |
||||||
|
[:div#group-profile-member-template |
||||||
|
[:div.twister-user |
||||||
|
(user-photo-link) |
||||||
|
[:div.twister-user-info {:data-screen-name ""} |
||||||
|
[:a.twister-user-name.open-profile-modal |
||||||
|
[:span.twister-user-full] |
||||||
|
[:span.twister-user-tag]] |
||||||
|
[:div.bio]]]]) |
||||||
|
|
||||||
|
(defn group-messages-new-group-template [] |
||||||
|
[:div#group-messages-new-group-template |
||||||
|
[:div.module |
||||||
|
[:div |
||||||
|
[:p.label "Group description"] |
||||||
|
[:textarea.description {:placeholder "Describe group"}]] |
||||||
|
[:div |
||||||
|
[:p.label "Peers to invite"] |
||||||
|
[:textarea.description {:placeholder "Invite someone"}]] |
||||||
|
[:div |
||||||
|
[:button.create {:disabled "disabled"} "Create"]]]]) |
||||||
|
|
||||||
|
(defn group-messages-join-group-template [] |
||||||
|
[:div#group-messages-join-group-template |
||||||
|
[:div.module |
||||||
|
[:div |
||||||
|
[:p.label "Select group(s)"] |
||||||
|
[:ul.groups-list]] |
||||||
|
[:div [:button.join {:disabled "disabled"} "Join"]]] |
||||||
|
[:div.module |
||||||
|
[:div |
||||||
|
[:p.label "Import secret key"] |
||||||
|
[:input.secret-key-import {:type "textbox" |
||||||
|
:placeholder "52-character secret" |
||||||
|
:size 52 |
||||||
|
:rows 1}]] |
||||||
|
[:p.label "With group alias"] |
||||||
|
[:input.username-import {:type "textbox" |
||||||
|
:placeholder "Type group alias here" |
||||||
|
:size 16 |
||||||
|
:rows 1}] |
||||||
|
[:button.import-secret-key {:disabled "disabled"} "Import key"]]]) |
||||||
|
|
||||||
|
(defn groups-list-item-template [] |
||||||
|
[:div#groups-list-item-template |
||||||
|
[:li |
||||||
|
[:input {:type "checkbox"}] |
||||||
|
[:a.twister-user-name.open-profile-modal] |
||||||
|
[:span.description]]]) |
||||||
|
|
||||||
|
(defn profile-card [] |
||||||
|
[:div.profile-card {:data-screen-name ""} |
||||||
|
[:div.profile-card-main |
||||||
|
(user-photo) |
||||||
|
[:h1.profile-name] |
||||||
|
[:h2.profile-screen-name [:strong "@"]] |
||||||
|
[:div |
||||||
|
[:span.profile-location] |
||||||
|
[:a.profile-url {:rel "nofollow" :target "_blank"}]] |
||||||
|
[:div.profile-bio] |
||||||
|
[:div#msngersw |
||||||
|
[:div#toxbtnwr.profile-extra-contact |
||||||
|
[:a.profile-tox |
||||||
|
[:span.selectable_theme.theme_nin "TOX"]]] |
||||||
|
[:div#bmbtnwr.profile-extra-contact |
||||||
|
[:a.profile-bitmessage |
||||||
|
[:span.selectable_theme.theme_nin "BitMessage"]]]]] |
||||||
|
[:div.twister-user-info |
||||||
|
[:div.clearfix |
||||||
|
[:ul.module.profile-data |
||||||
|
[:li [:a {:href "#"} |
||||||
|
[:span.posts-count " "] |
||||||
|
[:span.label "Posts"]]] |
||||||
|
[:li [:a.open-following-modal {:href "#"} |
||||||
|
[:span.following-count " "] |
||||||
|
[:span.label "Following"]]] |
||||||
|
[:li [:a {:href "#"} |
||||||
|
[:span.followers-count " "] |
||||||
|
[:span.label "Followers"]]]]] |
||||||
|
[:div.profile-card-buttons.b-buttons |
||||||
|
[:button.follow {:href "#"} "Follow"] |
||||||
|
[:button.direct-messages-with-user {:href "#"} "Direct Messages"] |
||||||
|
[:button.mentions-from-user {:href "#"} "Mentions"]]] |
||||||
|
[:div.who-follow]]) |
||||||
|
|
||||||
|
(defn profile-modal-template [] |
||||||
|
[:div#profile-modal-template |
||||||
|
(profile-card) |
||||||
|
[:div.postboard |
||||||
|
[:h2 |
||||||
|
[:span "Posts"] |
||||||
|
[:button.postboard-news {:style {:display "none"}}]] |
||||||
|
[:ol#profile-posts.postboard-posts]]]) |
||||||
|
|
||||||
|
(defn hashtag-modal-template [] |
||||||
|
[:div#hashtag-modal-template |
||||||
|
[:div.postbaord |
||||||
|
[:h2 |
||||||
|
[:span.selectable_theme.theme_original.theme_calm "Posts"] |
||||||
|
[:button.postboard-news {:style {:display "none"}}]] |
||||||
|
[:ol#profile-posts.postboard-posts] |
||||||
|
[:div.postboard-loading {:style {:display "none"}} |
||||||
|
[:div]]]]) |
||||||
|
|
||||||
|
(defn following-modal-template [] |
||||||
|
[:div#following-modal-template |
||||||
|
[:h2 "All users publicly followed by " |
||||||
|
[:span.following-screen-name [:strong "@"]]] |
||||||
|
[:ol |
||||||
|
[:li#following-by-user-template {:style {:display "none"}} |
||||||
|
[:div.mini-following-info {:data-screen-name ""} |
||||||
|
[:a.open-profile-modal {:href "#"} |
||||||
|
(user-photo "mini-profile-photo") |
||||||
|
[:span.mini-following-name "Nobody Yet"] |
||||||
|
[:span.mini-screen-name [:strong.following-screen-name "@"]]]]]]]) |
||||||
|
|
||||||
|
(defn following-config-modal-template [] |
||||||
|
[:div#following-config-modal-template |
||||||
|
[:div.following-config-modal-content {:data-screen-name ""} |
||||||
|
[:h2 |
||||||
|
[:span.following-config-method-message "Which way do you want to follow "] |
||||||
|
[:span.following-screen-name [:strong "@"]] |
||||||
|
":"] |
||||||
|
[:div.following-config-method-buttons |
||||||
|
[:button.public-following "Public"] |
||||||
|
[:button.public-following.private "Private"]]]]) |
||||||
|
|
||||||
|
;; ------------------------- |
||||||
|
;; Views |
||||||
|
|
||||||
|
(defn home-page [] |
||||||
|
[:div [:h2 "twister-renyan"] |
||||||
|
[:div [:a {:href "#/about"} "go to about page"]] |
||||||
|
[:nav.userMenu |
||||||
|
[:ul |
||||||
|
[:li.userMenu-home.current |
||||||
|
[:a {:href "home.html"} |
||||||
|
[:span.selectable_theme.theme_original.label "Home"] |
||||||
|
[:span.selectable_theme.theme_nin.menu-news]]] |
||||||
|
[:li.userMenu-network.selectable_theme.theme_original.theme_nin |
||||||
|
[:a.label {:href "network.html"} "Network"]] |
||||||
|
[:li.userMenu-profile.selectable_theme.theme_original.theme_nin |
||||||
|
[:a.label {:href "profile-edit.html"} "Profile"]] |
||||||
|
[:li.userMenu-config |
||||||
|
[:a.userMenu-config-dropdown {:href "#"} |
||||||
|
[:div.config-menu.dialog-modal |
||||||
|
[:div.mini-profile-info.selectable_theme.theme_original |
||||||
|
[:div.mini-profile-photo |
||||||
|
;; (user-photo "mini-profile-photo") |
||||||
|
] |
||||||
|
[:a.mini-profile-name {:href "#"} "Nobody Yet"] |
||||||
|
[:span.mini-profile-view "View"]] |
||||||
|
[:a.dropdown-menu-item {:href "options.html"} "Options"] |
||||||
|
[:a.dropdown-menu-item {:href "network.html"} "Network"] |
||||||
|
[:a.dropdown-menu-item {:href "profile-edit.html"} "Accounts"] |
||||||
|
[:a.dropdown-menu-item {:href "following.html"} "Following Users"] |
||||||
|
[:a.dropdown-menu-item {:href "login.html"} "Change User"] |
||||||
|
[:a.dropdown-menu-item.promoted-posts-only.selectable_theme.theme_original.theme_calm |
||||||
|
{:href "#"} "Switch to Promoted Posts"] |
||||||
|
[:a.dropdown-menu-item.direct-messages.selectable_theme.theme_original.theme_calm |
||||||
|
{:href "#"} "Direct Messages"] |
||||||
|
[:a.dropdown-menu-item.direct-messages.selectable_theme.theme_original.theme_calm |
||||||
|
{:href "#"} "Group Messages"]]]] |
||||||
|
[:li.userMenu-connections |
||||||
|
[:a {:href "#"} |
||||||
|
[:span.messages-qtd {:style {:display "none"}} 0]]] |
||||||
|
[:li.userMenu-messages |
||||||
|
[:a {:href "#"} |
||||||
|
[:span.messages-qtd {:style {:display "none"}} 0]]] |
||||||
|
[:li.userMenu-group |
||||||
|
[:a {:href "#"} |
||||||
|
[:span.messages-qtd {:style {:display "none"}} 0]]] |
||||||
|
[:li.userMenu-dhtindicator.selectable_theme.theme_calm |
||||||
|
[:a {:href "network.html"}]] |
||||||
|
;; Search |
||||||
|
[:li.userMenu-search |
||||||
|
[:input.userMenu-search-field {:type "text" :placeholder "search"}] |
||||||
|
[:div.search-results.dialog-modal |
||||||
|
[:ul.userMenu-search-sugestions {:style {:display "none"}} |
||||||
|
[:li [:a {:href "A Nobody"}]] |
||||||
|
[:li [:a {:href "Another Nobody"}]] |
||||||
|
[:li [:a {:href "One More Nobody"}]]] |
||||||
|
[:ul.userMenu-search-profiles]]]]] |
||||||
|
;; Nav end |
||||||
|
[:div.wrapper |
||||||
|
[:div.dashboard.left |
||||||
|
[:ul.mini-profile-indicators.selectable_theme.theme_nin |
||||||
|
[:li.userMenu-connections |
||||||
|
[:a {:href "#" :title "Mentions"} |
||||||
|
[:span.messages-qtd {:style {:display "none"}} 0] |
||||||
|
[:span "Mentions"]]] |
||||||
|
[:li.userMenu-groupmessages |
||||||
|
[:a {:href "#" :title "Group Messages"} |
||||||
|
[:span.messages-qtd {:style {:display "none"}} 0] |
||||||
|
[:span "Group Messages"]]] |
||||||
|
[:li.userMenu-messages |
||||||
|
[:a {:href "#" :title "Direct Messages"} |
||||||
|
[:span.messages-qtd {:style {:display "none"}} 0] |
||||||
|
[:span "Direct Messages"]]]] |
||||||
|
;; Profile widget |
||||||
|
[:div.module.mini-profile |
||||||
|
[:div.mini-profile-info |
||||||
|
[:div.mini-profile-photo |
||||||
|
(user-photo)] |
||||||
|
[:a.mini-profile-name.open-profile-modal {:href "#"}] |
||||||
|
[:span.mini-profile-view "View"]] |
||||||
|
[:ul.module.profile-data |
||||||
|
[:li |
||||||
|
[:a.open-profile-modal {:href "#"} |
||||||
|
[:span.posts-count " "] |
||||||
|
[:span.label "Posts"]]] |
||||||
|
[:li |
||||||
|
[:a.open-following-page {:href "following.html"} |
||||||
|
[:span.following-count " "] |
||||||
|
[:span.label "Following"]]] |
||||||
|
[:li |
||||||
|
[:a.open-followers {:href "#"} |
||||||
|
[:span.followers-count " "] |
||||||
|
[:span.label "Followers"]]]] |
||||||
|
(post-area)] |
||||||
|
;; Who to follow |
||||||
|
[:div.module.who-to-follow {:style {:display "none"}}] |
||||||
|
;; Trends |
||||||
|
[:div.module.toptrends {:style {:display "none"}}] |
||||||
|
;; Twistday |
||||||
|
[:div.module.twistday-reminder {:style {:display "none"}}]] |
||||||
|
|
||||||
|
;; Posts area |
||||||
|
[:div.postboard |
||||||
|
[:h2 |
||||||
|
[:span "Postboard"] |
||||||
|
[:button.postboard-news.selectable_theme.theme_original.theme_calm |
||||||
|
{:style {:display "none"}}]] |
||||||
|
;; Post type tab (normal, promoted) |
||||||
|
[:ul.promoted-posts-only.promoted.selectable_theme.theme_nin |
||||||
|
[:li.normal-posts.active [:span "Normal posts"]] |
||||||
|
[:li.promoted-posts.disabled [:span "Promoted posts"]]] |
||||||
|
;; Top of postboard postarea |
||||||
|
[:div#postboard-top.selectable_theme.theme_nin (post-area)] |
||||||
|
;; User pic |
||||||
|
[:div.profile-photo (user-photo "" "img/genericPerson.png")]] |
||||||
|
;; postboard-top end |
||||||
|
|
||||||
|
[:ol#posts.postboard-posts |
||||||
|
;; "post-template" here |
||||||
|
] |
||||||
|
[:div.postboard-loading {:style {:display "none"}} [:div]]] |
||||||
|
;; post area end |
||||||
|
[:div.dashboard.right]]) |
||||||
|
|
||||||
|
(defn about-page [] |
||||||
|
[:div [:h2 "About twister-renyan"] |
||||||
|
[:div [:a {:href "#/"} "go to the home page"]]]) |
||||||
|
|
||||||
|
(defn current-page [] |
||||||
|
[:div [(session/get :current-page)]]) |
||||||
|
|
||||||
|
;; ------------------------- |
||||||
|
;; Routes |
||||||
|
(secretary/set-config! :prefix "#") |
||||||
|
|
||||||
|
(secretary/defroute "/" [] |
||||||
|
(session/put! :current-page #'home-page)) |
||||||
|
|
||||||
|
(secretary/defroute "/about" [] |
||||||
|
(session/put! :current-page #'about-page)) |
||||||
|
|
||||||
|
|
||||||
|
;; ------------------------- |
||||||
|
;; History |
||||||
|
;; must be called after routes have been defined |
||||||
|
(defn hook-browser-navigation! [] |
||||||
|
(doto (History.) |
||||||
|
(events/listen |
||||||
|
EventType/NAVIGATE |
||||||
|
(fn [event] |
||||||
|
(secretary/dispatch! (.-token event)))) |
||||||
|
(.setEnabled true))) |
||||||
|
|
||||||
|
;; ------------------------- |
||||||
|
;; Initialize app |
||||||
|
(defn mount-root [] |
||||||
|
(reagent/render [current-page] (.getElementById js/document "app"))) |
||||||
|
|
||||||
|
(defn init! [] |
||||||
|
(hook-browser-navigation!) |
||||||
|
(mount-root)) |
@ -0,0 +1,39 @@ |
|||||||
|
(ns twister-renyan.core-test |
||||||
|
(:require [cemerick.cljs.test :refer-macros [is are deftest testing use-fixtures done]] |
||||||
|
[reagent.core :as reagent :refer [atom]] |
||||||
|
[twister-renyan.core :as rc])) |
||||||
|
|
||||||
|
|
||||||
|
(def isClient (not (nil? (try (.-document js/window) |
||||||
|
(catch js/Object e nil))))) |
||||||
|
|
||||||
|
(def rflush reagent/flush) |
||||||
|
|
||||||
|
(defn add-test-div [name] |
||||||
|
(let [doc js/document |
||||||
|
body (.-body js/document) |
||||||
|
div (.createElement doc "div")] |
||||||
|
(.appendChild body div) |
||||||
|
div)) |
||||||
|
|
||||||
|
(defn with-mounted-component [comp f] |
||||||
|
(when isClient |
||||||
|
(let [div (add-test-div "_testreagent")] |
||||||
|
(let [comp (reagent/render-component comp div #(f comp div))] |
||||||
|
(reagent/unmount-component-at-node div) |
||||||
|
(reagent/flush) |
||||||
|
(.removeChild (.-body js/document) div))))) |
||||||
|
|
||||||
|
|
||||||
|
(defn found-in [re div] |
||||||
|
(let [res (.-innerHTML div)] |
||||||
|
(if (re-find re res) |
||||||
|
true |
||||||
|
(do (println "Not found: " res) |
||||||
|
false)))) |
||||||
|
|
||||||
|
|
||||||
|
(deftest test-home |
||||||
|
(with-mounted-component (rc/home-page) |
||||||
|
(fn [c div] |
||||||
|
(is (found-in #"Welcome to" div))))) |
@ -0,0 +1,15 @@ |
|||||||
|
// Console-polyfill. MIT license.
|
||||||
|
// https://github.com/paulmillr/console-polyfill
|
||||||
|
// Make it safe to do console.log() always.
|
||||||
|
(function (con) { |
||||||
|
'use strict'; |
||||||
|
var prop, method; |
||||||
|
var empty = {}; |
||||||
|
var dummy = function() {}; |
||||||
|
var properties = 'memory'.split(','); |
||||||
|
var methods = ('assert,count,debug,dir,dirxml,error,exception,group,' + |
||||||
|
'groupCollapsed,groupEnd,info,log,markTimeline,profile,profileEnd,' + |
||||||
|
'time,timeEnd,trace,warn').split(','); |
||||||
|
while (prop = properties.pop()) con[prop] = con[prop] || empty; |
||||||
|
while (method = methods.pop()) con[method] = con[method] || dummy; |
||||||
|
})(window.console = window.console || {}); |
@ -0,0 +1,451 @@ |
|||||||
|
/*! |
||||||
|
* https://github.com/es-shims/es5-shim
|
||||||
|
* @license es5-shim Copyright 2009-2014 by contributors, MIT License |
||||||
|
* see https://github.com/es-shims/es5-shim/blob/master/LICENSE
|
||||||
|
*/ |
||||||
|
|
||||||
|
// vim: ts=4 sts=4 sw=4 expandtab
|
||||||
|
|
||||||
|
//Add semicolon to prevent IIFE from being passed as argument to concated code.
|
||||||
|
; |
||||||
|
// Module systems magic dance
|
||||||
|
(function (definition) { |
||||||
|
// RequireJS
|
||||||
|
if (typeof define == "function") { |
||||||
|
define(definition); |
||||||
|
// YUI3
|
||||||
|
} else if (typeof YUI == "function") { |
||||||
|
YUI.add("es5-sham", definition); |
||||||
|
// CommonJS and <script>
|
||||||
|
} else { |
||||||
|
definition(); |
||||||
|
} |
||||||
|
})(function () { |
||||||
|
|
||||||
|
|
||||||
|
var call = Function.prototype.call; |
||||||
|
var prototypeOfObject = Object.prototype; |
||||||
|
var owns = call.bind(prototypeOfObject.hasOwnProperty); |
||||||
|
|
||||||
|
// If JS engine supports accessors creating shortcuts.
|
||||||
|
var defineGetter; |
||||||
|
var defineSetter; |
||||||
|
var lookupGetter; |
||||||
|
var lookupSetter; |
||||||
|
var supportsAccessors; |
||||||
|
if ((supportsAccessors = owns(prototypeOfObject, "__defineGetter__"))) { |
||||||
|
defineGetter = call.bind(prototypeOfObject.__defineGetter__); |
||||||
|
defineSetter = call.bind(prototypeOfObject.__defineSetter__); |
||||||
|
lookupGetter = call.bind(prototypeOfObject.__lookupGetter__); |
||||||
|
lookupSetter = call.bind(prototypeOfObject.__lookupSetter__); |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.2
|
||||||
|
// http://es5.github.com/#x15.2.3.2
|
||||||
|
if (!Object.getPrototypeOf) { |
||||||
|
// https://github.com/es-shims/es5-shim/issues#issue/2
|
||||||
|
// http://ejohn.org/blog/objectgetprototypeof/
|
||||||
|
// recommended by fschaefer on github
|
||||||
|
Object.getPrototypeOf = function getPrototypeOf(object) { |
||||||
|
return object.__proto__ || ( |
||||||
|
object.constructor |
||||||
|
? object.constructor.prototype |
||||||
|
: prototypeOfObject |
||||||
|
); |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
//ES5 15.2.3.3
|
||||||
|
//http://es5.github.com/#x15.2.3.3
|
||||||
|
|
||||||
|
function doesGetOwnPropertyDescriptorWork(object) { |
||||||
|
try { |
||||||
|
object.sentinel = 0; |
||||||
|
return Object.getOwnPropertyDescriptor( |
||||||
|
object, |
||||||
|
"sentinel" |
||||||
|
).value === 0; |
||||||
|
} catch (exception) { |
||||||
|
// returns falsy
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//check whether getOwnPropertyDescriptor works if it's given. Otherwise,
|
||||||
|
//shim partially.
|
||||||
|
if (Object.defineProperty) { |
||||||
|
var getOwnPropertyDescriptorWorksOnObject = |
||||||
|
doesGetOwnPropertyDescriptorWork({}); |
||||||
|
var getOwnPropertyDescriptorWorksOnDom = typeof document == "undefined" || |
||||||
|
doesGetOwnPropertyDescriptorWork(document.createElement("div")); |
||||||
|
if (!getOwnPropertyDescriptorWorksOnDom || |
||||||
|
!getOwnPropertyDescriptorWorksOnObject |
||||||
|
) { |
||||||
|
var getOwnPropertyDescriptorFallback = Object.getOwnPropertyDescriptor; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!Object.getOwnPropertyDescriptor || getOwnPropertyDescriptorFallback) { |
||||||
|
var ERR_NON_OBJECT = "Object.getOwnPropertyDescriptor called on a non-object: "; |
||||||
|
|
||||||
|
Object.getOwnPropertyDescriptor = function getOwnPropertyDescriptor(object, property) { |
||||||
|
if ((typeof object != "object" && typeof object != "function") || object === null) { |
||||||
|
throw new TypeError(ERR_NON_OBJECT + object); |
||||||
|
} |
||||||
|
|
||||||
|
// make a valiant attempt to use the real getOwnPropertyDescriptor
|
||||||
|
// for I8's DOM elements.
|
||||||
|
if (getOwnPropertyDescriptorFallback) { |
||||||
|
try { |
||||||
|
return getOwnPropertyDescriptorFallback.call(Object, object, property); |
||||||
|
} catch (exception) { |
||||||
|
// try the shim if the real one doesn't work
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If object does not owns property return undefined immediately.
|
||||||
|
if (!owns(object, property)) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
// If object has a property then it's for sure both `enumerable` and
|
||||||
|
// `configurable`.
|
||||||
|
var descriptor = { enumerable: true, configurable: true }; |
||||||
|
|
||||||
|
// If JS engine supports accessor properties then property may be a
|
||||||
|
// getter or setter.
|
||||||
|
if (supportsAccessors) { |
||||||
|
// Unfortunately `__lookupGetter__` will return a getter even
|
||||||
|
// if object has own non getter property along with a same named
|
||||||
|
// inherited getter. To avoid misbehavior we temporary remove
|
||||||
|
// `__proto__` so that `__lookupGetter__` will return getter only
|
||||||
|
// if it's owned by an object.
|
||||||
|
var prototype = object.__proto__; |
||||||
|
object.__proto__ = prototypeOfObject; |
||||||
|
|
||||||
|
var getter = lookupGetter(object, property); |
||||||
|
var setter = lookupSetter(object, property); |
||||||
|
|
||||||
|
// Once we have getter and setter we can put values back.
|
||||||
|
object.__proto__ = prototype; |
||||||
|
|
||||||
|
if (getter || setter) { |
||||||
|
if (getter) { |
||||||
|
descriptor.get = getter; |
||||||
|
} |
||||||
|
if (setter) { |
||||||
|
descriptor.set = setter; |
||||||
|
} |
||||||
|
// If it was accessor property we're done and return here
|
||||||
|
// in order to avoid adding `value` to the descriptor.
|
||||||
|
return descriptor; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If we got this far we know that object has an own property that is
|
||||||
|
// not an accessor so we set it as a value and return descriptor.
|
||||||
|
descriptor.value = object[property]; |
||||||
|
descriptor.writable = true; |
||||||
|
return descriptor; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.4
|
||||||
|
// http://es5.github.com/#x15.2.3.4
|
||||||
|
if (!Object.getOwnPropertyNames) { |
||||||
|
Object.getOwnPropertyNames = function getOwnPropertyNames(object) { |
||||||
|
return Object.keys(object); |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.5
|
||||||
|
// http://es5.github.com/#x15.2.3.5
|
||||||
|
if (!Object.create) { |
||||||
|
|
||||||
|
// Contributed by Brandon Benvie, October, 2012
|
||||||
|
var createEmpty; |
||||||
|
var supportsProto = Object.prototype.__proto__ === null; |
||||||
|
if (supportsProto || typeof document == 'undefined') { |
||||||
|
createEmpty = function () { |
||||||
|
return { "__proto__": null }; |
||||||
|
}; |
||||||
|
} else { |
||||||
|
// In old IE __proto__ can't be used to manually set `null`, nor does
|
||||||
|
// any other method exist to make an object that inherits from nothing,
|
||||||
|
// aside from Object.prototype itself. Instead, create a new global
|
||||||
|
// object and *steal* its Object.prototype and strip it bare. This is
|
||||||
|
// used as the prototype to create nullary objects.
|
||||||
|
createEmpty = function () { |
||||||
|
var iframe = document.createElement('iframe'); |
||||||
|
var parent = document.body || document.documentElement; |
||||||
|
iframe.style.display = 'none'; |
||||||
|
parent.appendChild(iframe); |
||||||
|
iframe.src = 'javascript:'; |
||||||
|
var empty = iframe.contentWindow.Object.prototype; |
||||||
|
parent.removeChild(iframe); |
||||||
|
iframe = null; |
||||||
|
delete empty.constructor; |
||||||
|
delete empty.hasOwnProperty; |
||||||
|
delete empty.propertyIsEnumerable; |
||||||
|
delete empty.isPrototypeOf; |
||||||
|
delete empty.toLocaleString; |
||||||
|
delete empty.toString; |
||||||
|
delete empty.valueOf; |
||||||
|
empty.__proto__ = null; |
||||||
|
|
||||||
|
function Empty() {} |
||||||
|
Empty.prototype = empty; |
||||||
|
// short-circuit future calls
|
||||||
|
createEmpty = function () { |
||||||
|
return new Empty(); |
||||||
|
}; |
||||||
|
return new Empty(); |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
Object.create = function create(prototype, properties) { |
||||||
|
|
||||||
|
var object; |
||||||
|
function Type() {} // An empty constructor.
|
||||||
|
|
||||||
|
if (prototype === null) { |
||||||
|
object = createEmpty(); |
||||||
|
} else { |
||||||
|
if (typeof prototype !== "object" && typeof prototype !== "function") { |
||||||
|
// In the native implementation `parent` can be `null`
|
||||||
|
// OR *any* `instanceof Object` (Object|Function|Array|RegExp|etc)
|
||||||
|
// Use `typeof` tho, b/c in old IE, DOM elements are not `instanceof Object`
|
||||||
|
// like they are in modern browsers. Using `Object.create` on DOM elements
|
||||||
|
// is...err...probably inappropriate, but the native version allows for it.
|
||||||
|
throw new TypeError("Object prototype may only be an Object or null"); // same msg as Chrome
|
||||||
|
} |
||||||
|
Type.prototype = prototype; |
||||||
|
object = new Type(); |
||||||
|
// IE has no built-in implementation of `Object.getPrototypeOf`
|
||||||
|
// neither `__proto__`, but this manually setting `__proto__` will
|
||||||
|
// guarantee that `Object.getPrototypeOf` will work as expected with
|
||||||
|
// objects created using `Object.create`
|
||||||
|
object.__proto__ = prototype; |
||||||
|
} |
||||||
|
|
||||||
|
if (properties !== void 0) { |
||||||
|
Object.defineProperties(object, properties); |
||||||
|
} |
||||||
|
|
||||||
|
return object; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.6
|
||||||
|
// http://es5.github.com/#x15.2.3.6
|
||||||
|
|
||||||
|
// Patch for WebKit and IE8 standard mode
|
||||||
|
// Designed by hax <hax.github.com>
|
||||||
|
// related issue: https://github.com/es-shims/es5-shim/issues#issue/5
|
||||||
|
// IE8 Reference:
|
||||||
|
// http://msdn.microsoft.com/en-us/library/dd282900.aspx
|
||||||
|
// http://msdn.microsoft.com/en-us/library/dd229916.aspx
|
||||||
|
// WebKit Bugs:
|
||||||
|
// https://bugs.webkit.org/show_bug.cgi?id=36423
|
||||||
|
|
||||||
|
function doesDefinePropertyWork(object) { |
||||||
|
try { |
||||||
|
Object.defineProperty(object, "sentinel", {}); |
||||||
|
return "sentinel" in object; |
||||||
|
} catch (exception) { |
||||||
|
// returns falsy
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// check whether defineProperty works if it's given. Otherwise,
|
||||||
|
// shim partially.
|
||||||
|
if (Object.defineProperty) { |
||||||
|
var definePropertyWorksOnObject = doesDefinePropertyWork({}); |
||||||
|
var definePropertyWorksOnDom = typeof document == "undefined" || |
||||||
|
doesDefinePropertyWork(document.createElement("div")); |
||||||
|
if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) { |
||||||
|
var definePropertyFallback = Object.defineProperty, |
||||||
|
definePropertiesFallback = Object.defineProperties; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!Object.defineProperty || definePropertyFallback) { |
||||||
|
var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: "; |
||||||
|
var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: " |
||||||
|
var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " + |
||||||
|
"on this javascript engine"; |
||||||
|
|
||||||
|
Object.defineProperty = function defineProperty(object, property, descriptor) { |
||||||
|
if ((typeof object != "object" && typeof object != "function") || object === null) { |
||||||
|
throw new TypeError(ERR_NON_OBJECT_TARGET + object); |
||||||
|
} |
||||||
|
if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) { |
||||||
|
throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor); |
||||||
|
} |
||||||
|
// make a valiant attempt to use the real defineProperty
|
||||||
|
// for I8's DOM elements.
|
||||||
|
if (definePropertyFallback) { |
||||||
|
try { |
||||||
|
return definePropertyFallback.call(Object, object, property, descriptor); |
||||||
|
} catch (exception) { |
||||||
|
// try the shim if the real one doesn't work
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// If it's a data property.
|
||||||
|
if (owns(descriptor, "value")) { |
||||||
|
// fail silently if "writable", "enumerable", or "configurable"
|
||||||
|
// are requested but not supported
|
||||||
|
/* |
||||||
|
// alternate approach:
|
||||||
|
if ( // can't implement these features; allow false but not true
|
||||||
|
!(owns(descriptor, "writable") ? descriptor.writable : true) || |
||||||
|
!(owns(descriptor, "enumerable") ? descriptor.enumerable : true) || |
||||||
|
!(owns(descriptor, "configurable") ? descriptor.configurable : true) |
||||||
|
) |
||||||
|
throw new RangeError( |
||||||
|
"This implementation of Object.defineProperty does not " + |
||||||
|
"support configurable, enumerable, or writable." |
||||||
|
); |
||||||
|
*/ |
||||||
|
|
||||||
|
if (supportsAccessors && (lookupGetter(object, property) || |
||||||
|
lookupSetter(object, property))) |
||||||
|
{ |
||||||
|
// As accessors are supported only on engines implementing
|
||||||
|
// `__proto__` we can safely override `__proto__` while defining
|
||||||
|
// a property to make sure that we don't hit an inherited
|
||||||
|
// accessor.
|
||||||
|
var prototype = object.__proto__; |
||||||
|
object.__proto__ = prototypeOfObject; |
||||||
|
// Deleting a property anyway since getter / setter may be
|
||||||
|
// defined on object itself.
|
||||||
|
delete object[property]; |
||||||
|
object[property] = descriptor.value; |
||||||
|
// Setting original `__proto__` back now.
|
||||||
|
object.__proto__ = prototype; |
||||||
|
} else { |
||||||
|
object[property] = descriptor.value; |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (!supportsAccessors) { |
||||||
|
throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED); |
||||||
|
} |
||||||
|
// If we got that far then getters and setters can be defined !!
|
||||||
|
if (owns(descriptor, "get")) { |
||||||
|
defineGetter(object, property, descriptor.get); |
||||||
|
} |
||||||
|
if (owns(descriptor, "set")) { |
||||||
|
defineSetter(object, property, descriptor.set); |
||||||
|
} |
||||||
|
} |
||||||
|
return object; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.7
|
||||||
|
// http://es5.github.com/#x15.2.3.7
|
||||||
|
if (!Object.defineProperties || definePropertiesFallback) { |
||||||
|
Object.defineProperties = function defineProperties(object, properties) { |
||||||
|
// make a valiant attempt to use the real defineProperties
|
||||||
|
if (definePropertiesFallback) { |
||||||
|
try { |
||||||
|
return definePropertiesFallback.call(Object, object, properties); |
||||||
|
} catch (exception) { |
||||||
|
// try the shim if the real one doesn't work
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (var property in properties) { |
||||||
|
if (owns(properties, property) && property != "__proto__") { |
||||||
|
Object.defineProperty(object, property, properties[property]); |
||||||
|
} |
||||||
|
} |
||||||
|
return object; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.8
|
||||||
|
// http://es5.github.com/#x15.2.3.8
|
||||||
|
if (!Object.seal) { |
||||||
|
Object.seal = function seal(object) { |
||||||
|
// this is misleading and breaks feature-detection, but
|
||||||
|
// allows "securable" code to "gracefully" degrade to working
|
||||||
|
// but insecure code.
|
||||||
|
return object; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.9
|
||||||
|
// http://es5.github.com/#x15.2.3.9
|
||||||
|
if (!Object.freeze) { |
||||||
|
Object.freeze = function freeze(object) { |
||||||
|
// this is misleading and breaks feature-detection, but
|
||||||
|
// allows "securable" code to "gracefully" degrade to working
|
||||||
|
// but insecure code.
|
||||||
|
return object; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// detect a Rhino bug and patch it
|
||||||
|
try { |
||||||
|
Object.freeze(function () {}); |
||||||
|
} catch (exception) { |
||||||
|
Object.freeze = (function freeze(freezeObject) { |
||||||
|
return function freeze(object) { |
||||||
|
if (typeof object == "function") { |
||||||
|
return object; |
||||||
|
} else { |
||||||
|
return freezeObject(object); |
||||||
|
} |
||||||
|
}; |
||||||
|
})(Object.freeze); |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.10
|
||||||
|
// http://es5.github.com/#x15.2.3.10
|
||||||
|
if (!Object.preventExtensions) { |
||||||
|
Object.preventExtensions = function preventExtensions(object) { |
||||||
|
// this is misleading and breaks feature-detection, but
|
||||||
|
// allows "securable" code to "gracefully" degrade to working
|
||||||
|
// but insecure code.
|
||||||
|
return object; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.11
|
||||||
|
// http://es5.github.com/#x15.2.3.11
|
||||||
|
if (!Object.isSealed) { |
||||||
|
Object.isSealed = function isSealed(object) { |
||||||
|
return false; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.12
|
||||||
|
// http://es5.github.com/#x15.2.3.12
|
||||||
|
if (!Object.isFrozen) { |
||||||
|
Object.isFrozen = function isFrozen(object) { |
||||||
|
return false; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// ES5 15.2.3.13
|
||||||
|
// http://es5.github.com/#x15.2.3.13
|
||||||
|
if (!Object.isExtensible) { |
||||||
|
Object.isExtensible = function isExtensible(object) { |
||||||
|
// 1. If Type(O) is not Object throw a TypeError exception.
|
||||||
|
if (Object(object) !== object) { |
||||||
|
throw new TypeError(); // TODO message
|
||||||
|
} |
||||||
|
// 2. Return the Boolean value of the [[Extensible]] internal property of O.
|
||||||
|
var name = ''; |
||||||
|
while (owns(object, name)) { |
||||||
|
name += '?'; |
||||||
|
} |
||||||
|
object[name] = true; |
||||||
|
var returnValue = owns(object, name); |
||||||
|
delete object[name]; |
||||||
|
return returnValue; |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
}); |
Loading…
Reference in new issue