Git Product home page Git Product logo

hoplon's Introduction

Hoplon Logo

Hoplon

clojars cljdoc badge

Hoplon is a ClojureScript library that unify some of the web platform's idiosyncrasies and present a fun way to design and build single-page web applications.

Hoplon tightly integrates with Javelin to reactively bind DOM elements to the underlying Javelin cell graph.

Quickstart

Install deps-new if you haven't already:

clojure -Ttools install-latest :lib io.github.seancorfield/deps-new :as new

And then generate a starter project with:

clojure -Sdeps '{:deps {io.github.hoplon/project-template {:git/tag "v1.0.0" :git/sha "14361f1"}}}' -Tnew create :template hoplon/hoplon :name your/app-name

Example

A small bit of Hoplon:

(ns view.index
  (:require
    [hoplon.core  :as h]
    [hoplon.dom]
    [javelin.core :as j]))

(defn my-list [& items]
  (h/div :class "my-list"
    (apply h/ul (map #(h/li (h/div :class "my-list-item" %)) items))))

(def clicks (j/cell 0))

(defn hello []
  (h/div
    (h/h1 "Hello, Hoplon")
    (my-list
      (h/span "first thing")
      (h/span "second thing"))
    (h/p (h/text "You've clicked ~{clicks} times, so far."))
    (h/button :click #(swap! clicks inc) "click me")))

Browser Support

Hoplon has been thoroughly tested on desktop and mobile devices against the following browsers:

IEdge Firefox Safari Chrome Opera Android

Documentation

Demos

Developing Hoplon itself

# build and install locally
clojure -T:build ci :snapshot true
clojure -T:build install :snapshot true

Testing

This setup will run tests using chrome-webdriver.

Setup

npm install
npm install -g karma-cli

Run

; Run tests in simple compilation
clojure -T:build test

; Run tests in advanced compilation
clojure -T:build advanced-test

Contributors

This project exists thanks to all the people who contribute.

License

Copyright (c) Alan Dipert and Micha Niskin. All rights reserved.

The use and distribution terms for this software are covered by the Eclipse
Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) which can
be found in the file epl-v10.html at the root of this distribution. By using
this software in any fashion, you are agreeing to be bound by the terms of
this license. You must not remove this notice, or any other, from this software.

hoplon's People

Contributors

alandipert avatar amatus avatar bergm avatar burn2delete avatar candera avatar ccharles avatar daveyarwood avatar dependabot[bot] avatar dm3 avatar hockeyman0 avatar jab avatar jjttjj avatar jumblerg avatar laforge49 avatar leontalbot avatar livtanong avatar micha avatar mischov avatar monkeywithacupcake avatar mraveloarinjaka avatar mynomoto avatar onetom avatar pbzdyl avatar rwillig avatar thedavidmeister avatar ul avatar vigilancetech-com avatar waffle-iron avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

hoplon's Issues

interpolate links?

(audio :controls "controls"
           (source :src (text "~{rpc/get-song}") :type "audio/mpeg")
           (text "Your browser does not support the audio element."))

yields

<audio controls="controls">
  <source src="[object Text]" type="audio/mpeg">
  Your browser does not support the audio element.
</audio>

How can I get this value into the src property?

Add support for reactive markup via cell as element child

Sometimes DOM structure needs to be more dynamic than loop-tpl can support (i.e. template is not known at compile time). If the desired template is contained in a cell it should be possible to pass the cell as the first child of an element. The element would then replace its children with the value (the template) contained in the given cell whenever the cell's value changes.

Hoplon having trouble compiling sample Presioke app

When I run lein hoplon on the sample Presioke app (or on my own app), I get the following stacktrace:

java.lang.NoSuchMethodError: cljs.closure.JavaScriptFile.<init>(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V
 at cljs.closure$javascript_file.invoke (closure.clj:278)
    cljs.closure$map__GT_javascript_file.invoke (closure.clj:290)
    cljs.closure$compiled_file.invoke (closure.clj:373)
    clojure.core$map$fn__4207.invoke (core.clj:2485)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$concat$fn__3923.invoke (core.clj:678)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.Cons.next (Cons.java:39)
    clojure.lang.RT.boundedLength (RT.java:1654)
    clojure.lang.RestFn.applyTo (RestFn.java:130)
    clojure.core$apply.invoke (core.clj:619)
    cljs.closure$build.invoke (closure.clj:960)
    tailrecursion.hoplon.compiler.core$hoplon_compile.invoke (core.clj:95)
    clojure.lang.AFn.applyToHelper (AFn.java:161)
    clojure.lang.AFn.applyTo (AFn.java:151)
    clojure.core$apply.invoke (core.clj:617)
    tailrecursion.hoplon.compiler.core$elapsed_sec.doInvoke (core.clj:23)
    clojure.lang.RestFn.invoke (RestFn.java:423)
    tailrecursion.hoplon.compiler.core$compile_fancy.invoke (core.clj:107)
    tailrecursion.hoplon.compiler.core$start.doInvoke (core.clj:138)
    clojure.lang.RestFn.invoke (RestFn.java:464)
    leiningen.hoplon$start_compiler$start__4311.invoke (hoplon.clj:51)
    leiningen.hoplon$start_compiler.invoke (hoplon.clj:54)
    leiningen.hoplon/fn (hoplon.clj:57)
    leiningen.hoplon$hoplon.doInvoke (hoplon.clj:70)
    clojure.lang.RestFn.invoke (RestFn.java:410)
    clojure.lang.Var.invoke (Var.java:415)
    clojure.lang.AFn.applyToHelper (AFn.java:161)
    clojure.lang.Var.applyTo (Var.java:532)
    clojure.core$apply.invoke (core.clj:619)
    leiningen.core.main$resolve_task$fn__2160.doInvoke (main.clj:148)
    clojure.lang.RestFn.invoke (RestFn.java:410)
    clojure.lang.AFn.applyToHelper (AFn.java:161)
    clojure.lang.RestFn.applyTo (RestFn.java:132)
    clojure.lang.AFunction$1.doInvoke (AFunction.java:29)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    clojure.core$apply.invoke (core.clj:619)
    leiningen.core.main$apply_task.invoke (main.clj:188)
    leiningen.core.main$resolve_and_apply.invoke (main.clj:192)
    leiningen.core.main$_main$fn__2223.invoke (main.clj:256)
    leiningen.core.main$_main.doInvoke (main.clj:246)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    clojure.lang.Var.invoke (Var.java:415)
    clojure.lang.AFn.applyToHelper (AFn.java:161)
    clojure.lang.Var.applyTo (Var.java:532)
    clojure.core$apply.invoke (core.clj:617)
    clojure.main$main_opt.invoke (main.clj:335)
    clojure.main$main.doInvoke (main.clj:440)
    clojure.lang.RestFn.invoke (RestFn.java:436)
    clojure.lang.Var.invoke (Var.java:423)
    clojure.lang.AFn.applyToHelper (AFn.java:167)
    clojure.lang.Var.applyTo (Var.java:532)
    clojure.main.main (main.java:37)

The output of lein -version is:

Leiningen 2.2.0 on Java 1.7.0_04 Java HotSpot(TM) 64-Bit Server VM

html2cljs boot task: StackOverflowError

To reproduce:

lein new hoplon html2cljs-bug
cd html2cljs-bug
echo '<html><head></head><body></body></html>' > index.html
boot [html2cljs \"index.html\"] :v

You should get a StackOverflowError.

Support :attr= attribute key format

A common typo is writing

(div :id="my-div" ...)

in hoplon markup, especially when you're used to HTML syntax. Unfortunately, this comes out as

elem.setAttribute("id=", "my-div")

which is a runtime error (attribute names may not contain the = character). Hoplon should strip trailing = from attribute names.

Enable controlling precise timing of 3rd-party script loading

It can be necessary to include third-party script in a page, and control the timing of when it loads very precisely.

Google Analytics provides one example: It's recommended to include the Google Analytics snippet just before </head>, so that it has a chance of counting the pageview as early as possible, but to load it asynchronously, so that it doesn't block rendering of the rest of the page. The DOM element for this script should be included in the initial static html of the response to the top level page request, so that the browser does not have to wait for the Hoplon app to be initialized and then take control of the DOM to load the script.

It would be great if Hoplon supported this. (Often 3rd-party script doesn't have to integrate with the Hoplon app at all, in case that makes it easier for Hoplon to at least support that case.)

(when prerendering? ...) theoretically enables the Google Analytics snippet to be included in the precise way it's intended to be:

(head
  (when prerendering?
    (script :async "" :src "https://www.google-analytics.com/analytics.js")
    (script "window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;ga('create','UA-XXX','auto');ga('send','pageview');")))

However, the prerenderer currently ignores (script) elements, so as far as I know, there's no way to do this. 😢

Is it possible to fix this? This is such a common requirement, it'd be awesome if Hoplon had a good answer.

Thanks for your consideration, and thanks for the great work on hoplon!

HTML strings can't be rendered unescaped.

I ran into some issues rendering a string of HTML I'm getting from an JSON response without it being escaped. As mentioned in IRC, I don't need to parse or interpolate Hoplon data into the HTML string; I simply want to display it.

I dug into the Hoplon source at https://github.com/tailrecursion/hoplon/blob/master/src/tailrecursion/hoplon/compiler/tagsoup.clj#L82 and realized that there's no case where we can have a div that doesn't call html-escape on its contents.

Would that be the right spot to add the condition that you can, in fact, just force the render of a string of HTML without escaping it? I'm thinking that it'd use a function like text, but instead would render its contents without calling html-escape. If that is the right place to add such functionality, I could work up a PR. If not, let me know where it would be better implemented.

This is a pretty common use-case (issues of displaying potentially un-friendly HTML aside), for apps that receive things like formatted blog posts bodies or other long content that is already marked up and needn't be templated on the clientside.

How to include Hoplon for using with linters and other stuff that requires “java -jar ...” to execute

First of all, this is not a question about atom.io editor or anything else.

Of course linters doesn't know about external dependencies
and I'm trying to NOT treating hoplon stuff like errors. It requires 'clojureExecutablePath' which later becomes

 "java -jar" + "clojure.jar" + " -i" (although this command can be rewritten ). 

How to include hoplon stuff like (page "index.html") in namespace for treating them as safe and not like errors?

I discovered some code to start in defined namespace, but I'm not sure about that.

 java -cp .;clojure-1.6.0.jar; clojure.main -e \
"(ns hoplon) (clojure.main/repl) (in-ns 'hoplon) (clojure.core/use 'tailrecursion/hoplon)"  

this is code for linter:
https://github.com/AtomLinter/linter-clojure/blob/master/lib/linter-clojure.coffee#L30

loop-tpl doesn't seem to work on sets

It looks like loop-tpl doesn't work with sets or even cells that that return seqs derived from seqs. I've had to convert to a vector for loop-tpl to work.

Here's where I'm converting to a vector:

https://github.com/flyingmachine/magewars-deckbuilder/blob/3c7daaca2ca29269b4ad6aecd06f3000a0508276/src/browser/index.cljs.hl#L55

The cardsc cell is associated with a filtered set. The sets are at

https://github.com/flyingmachine/magewars-deckbuilder/blob/3c7daaca2ca29269b4ad6aecd06f3000a0508276/src/browser/magewars_deckbuilder/deck.cljs

This is counterintuitive to me; I'd expect loop-tpl to work on any seqable structure

And by the way - hoplon is AWESOME!

Basid demo doesn't work.

Hi,
Something is broken somwhere. I can't run basic demo:

mbspock:~/chmura/nauka$ lein new hoplon-castra lab mbspock:~/chmura/nauka$ cd lab mbspock:~/chmura/nauka/lab$ boot development java.io.FileNotFoundException: Could not locate tailrecursion/hoplon/boot__init.class or tailrecursion/hoplon/boot.clj on classpath: , compiling:(/Users/spock/chmura/nauka/lab/.boot/tmp/83793/_COLON_tailrecursion.boot_SLASH_bootscript/dir.tmp/tailrecursion/boot/user.clj:23:44) ↳ Caused by: Could not locate tailrecursion/hoplon/boot__init.class or tailrecursion/hoplon/boot.clj on classpath: mbspock:~/chmura/nauka/lab$

main.js is hardcoded

It would be nice to choose the file name and path. Absolute paths would be even nicer.

inclusion of compiled cljs into final artifact

As for now add-source is used over the result of hl compilation, because app does not need intermediate cljs files, only final js, but Hoplon-based libraries will need add-resource to provide cljs. I propose to add an option to switch that behavior.

Upgrading to clojurescript 0.0-2120 throws Assertion Error

boot.edn:

{:dependencies [[tailrecursion/boot.core "1.1.0"]
                [tailrecursion/boot.task "1.0.0"]
                [tailrecursion/hoplon    "4.0.7"]
                [org.clojure/clojurescript "0.0-2120"]]
 :require-tasks #{[tailrecursion.boot.task   :refer :all]
                  [tailrecursion.hoplon.boot :refer :all]}
 :public "resources/public"
 :src-paths #{"src"}}

Exception when running boot hoplon

Compiling ClojureScript...
java.lang.AssertionError: Assert failed: :output-dir #<File .boot/tmp/35185/_COLON_tailrecursion.boot.task_SLASH_output_dir/dir.tmp> must specify a directory
(string? output-dir)
    at cljs.closure$check_output_dir.invoke(closure.clj:1051)
    at cljs.closure$build.invoke(closure.clj:1109)
    at cljs.closure$build.invoke(closure.clj:1094)
    at tailrecursion.boot.task.util.cljs$compile_cljs.invoke(cljs.clj:51)
    at clojure.lang.AFn.applyToHelper(AFn.java:193)
    at clojure.lang.AFn.applyTo(AFn.java:151)
    at clojure.core$apply.invoke(core.clj:617)
    at tailrecursion.boot.task$pass_thru_wrap$fn__7344$fn__7345.invoke(task.clj:45)
    at tailrecursion.hoplon.boot$hoplon$fn__9212$fn__9213.invoke(boot.clj:104)
    at tailrecursion.boot$_main.doInvoke(boot.clj:83)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.lang.Var.invoke(Var.java:415)
    at clojure.lang.AFn.applyToHelper(AFn.java:161)
    at clojure.lang.Var.applyTo(Var.java:532)
    at clojure.core$apply.invoke(core.clj:617)
    at tailrecursion.boot.loader$_main$fn__375.invoke(loader.clj:67)
    at tailrecursion.boot.loader$_main.doInvoke(loader.clj:67)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at tailrecursion.boot.loader.main(Unknown Source)

Looks like this should be fixed in boot.task (?) - there the :output-dir is set to a dir instead of a string.

Upgrading to clojurescript 0.0-2197 throws NPE

Warnings and stacktrace below:

Installing ClojureScript dependencies...
Compiling Hoplon pages...
• src/ui/tabs.cljs.hl
• src/index.cljs.hl
Compiling ClojureScript...
WARNING: No such namespace: goog.string at line 9 file:/home/y/.m2/repository/org/clojure/clojurescript/0.0-2197/clojurescript-0.0-2197.jar!/cljs/core.cljs
WARNING: No such namespace: goog.array at line 9 file:/home/y/.m2/repository/org/clojure/clojurescript/0.0-2197/clojurescript-0.0-2197.jar!/cljs/core.cljs
WARNING: No such namespace: goog.object at line 9 file:/home/y/.m2/repository/org/clojure/clojurescript/0.0-2197/clojurescript-0.0-2197.jar!/cljs/core.cljs
WARNING: No such namespace: goog.string.StringBuffer at line 9 file:/home/y/.m2/repository/org/clojure/clojurescript/0.0-2197/clojurescript-0.0-2197.jar!/cljs/core.cljs
WARNING: No such namespace: goog.string at line 9 file:/home/y/.m2/repository/org/clojure/clojurescript/0.0-2197/clojurescript-0.0-2197.jar!/cljs/reader.cljs
WARNING: No such namespace: goog.string at line 9 file:/home/y/.m2/repository/org/clojure/clojurescript/0.0-2197/clojurescript-0.0-2197.jar!/clojure/string.cljs
WARNING: No such namespace: goog.string.StringBuffer at line 9 file:/home/y/.m2/repository/org/clojure/clojurescript/0.0-2197/clojurescript-0.0-2197.jar!/clojure/string.cljs

java.lang.NullPointerException: null
 at clojure.core$complement$fn__4048.invoke (core.clj:1357)
    clojure.core$filter$fn__4226.invoke (core.clj:2533)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$map$fn__4207.invoke (core.clj:2479)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$filter$fn__4226.invoke (core.clj:2523)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$set.invoke (core.clj:3712)
    cljs.closure$cljs_dependencies.invoke (closure.clj:464)
    cljs.closure$add_dependencies.doInvoke (closure.clj:490)
    clojure.lang.RestFn.applyTo (RestFn.java:139)
    clojure.core$apply.invoke (core.clj:619)
    cljs.closure$build.invoke (closure.clj:951)
    cljs.closure$build.invoke (closure.clj:909)
    tailrecursion.boot.task.util.cljs.compiler$compile$fn__5785.invoke (compiler.clj:29)
    tailrecursion.boot.task.util.cljs.compiler$compile.invoke (compiler.clj:28)
    clojure.lang.Var.invoke (Var.java:435)
    clojure.lang.AFn.applyToHelper (AFn.java:185)
    clojure.lang.Var.applyTo (Var.java:532)
    clojure.core$apply.invoke (core.clj:617)
    tailrecursion.boot.task.util.cljs$compile_cljs.doInvoke (cljs.clj:37)
    clojure.lang.RestFn.invoke (RestFn.java:512)
    tailrecursion.boot.task$cljs$fn__1547$fn__1548$fn__1549.invoke (task.clj:56)
    tailrecursion.boot.task$cljs$fn__1547$fn__1548.invoke (task.clj:53)
    tailrecursion.hoplon.boot$hoplon$fn__2360$fn__2361.invoke (boot.clj:123)
    tailrecursion.boot.core.task$files_changed_QMARK_$fn__1250$fn__1251.invoke (task.clj:224)
    tailrecursion.boot.core.task$auto$fn__1239$fn__1240.invoke (task.clj:201)
    tailrecursion.boot.user$eval2384.invoke (user.clj:42)
    clojure.lang.Compiler.eval (Compiler.java:6619)
    clojure.lang.Compiler.load (Compiler.java:7064)
    clojure.lang.Compiler.loadFile (Compiler.java:7020)
    clojure.lang.RT$3.invoke (RT.java:318)
    tailrecursion.boot$_main.doInvoke (boot.clj:117)
    clojure.lang.RestFn.invoke (RestFn.java:467)
    clojure.lang.Var.invoke (Var.java:427)
    clojure.lang.AFn.applyToHelper (AFn.java:172)
    clojure.lang.Var.applyTo (Var.java:532)
    clojure.core$apply.invoke (core.clj:623)
    tailrecursion.boot.loader$_main.doInvoke (loader.clj:179)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    tailrecursion.boot.loader.main (:-1)

html.hl→cljs.hl

Check this conversion works correctly in hoplon task.
Optionally make separate task to convert single file by name.

advanced compile does not work in 5.2.0

Hi,

5.2.0 breaks advanced compile in some way. To reproduce it, create a hello-world project using hoplon-template, then boot production using below build script. Click button in index.html does not work anymore. Dev build with prerender either true or false works fine. I also tried this same boot.build in hoplon-demos, got similar issue.

#!/usr/bin/env boot

#tailrecursion.boot.core/version "2.2.0"

(require '[tailrecursion.boot.core :refer :all])

(set-env!
  :project      'my-site
  :version      "0.1.0-SNAPSHOT"
  :dependencies '[[tailrecursion/boot.task   "2.0.1"]
                  [tailrecursion/hoplon      "5.2.0"]
                  [org.clojure/clojurescript "0.0-2156"]]
  :out-path     "resources/public"
  :src-paths    #{"src"})

;; Static resources (css, images, etc.):
(add-sync! (get-env :out-path) #{"assets"})

(require
  '[tailrecursion.hoplon.boot :refer :all]
  '[tailrecursion.boot.task :refer :all])

(deftask nrepl
  "Runs an nrepl server."
  [& [{:keys [port] :or {port 0}}]]
  (fn [continue]
    (fn [event]
      (set-env! :dependencies '[[org.clojure/tools.nrepl "0.2.3"]])
      (require '[clojure.tools.nrepl.server :refer [start-server]])
      (let [server ((resolve 'start-server) :port port)]
        (println "Started nREPL server on port" (:port server))
        (spit ".nrepl-port" (:port server))
        (.deleteOnExit (java.io.File. ".nrepl-port"))
        (continue event)
        @(promise)))))

(deftask development
  "Build my-site for development."
  []
  (comp (watch) (hoplon {:prerender true :pretty-print true})))

(deftask production
  "Build my-site for production."
  []
  (hoplon {:optimizations :advanced}))

Thanks!

Following hoplon Getting Started, fails on Step 2

Hi there,
I was really excited to try out hoplon, but ran into this snag:

 Task 2: Compile the project.

 $ boot development

However, this fails with:

java.lang.RuntimeException: No reader function for tag tailrecursion.boot.core/version

I tried upgrading boot:

Retrieving boot-2.0.0-rc4.jar from http://clojars.org/repo/
#https://github.com/boot-clj/boot
#Thu Jan 01 01:58:12 CET 2015
BOOT_CLOJURE_VERSION=1.6.0
BOOT_VERSION=2.0.0-rc4

But just received the same error.

I am stuck, and in need of sleep. :) If anyone can figure out what is going wrong here I would love to move onto exploring hoplon.

Thanks,

Rohni

hoplon compiler needs to append a carriage return after each imported file

this prevents javascript libs with single line comments and no CR on the last line of the file from breaking the opening multiline comments of the next file, eg this is bad:

//# sourceMappingURL=hammer.min.map/*!
 * Bootstrap v3.1.1 (http://getbootstrap.com)
 * Copyright 2011-2014 Twitter, Inc.
 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
 */

and produces this exception:

Uncaught SyntaxError: Unexpected token * 

Cannot seem to put head content in library

Hey folks, Hoplon is great stuff -- really enjoying it :-) I've got a couple projects at work that I'd like to use it on, and towards that end, I started porting a Bootstrap theme to use it:
https://github.com/oubiwann/hoplon-modern-business

I encountered a problem with splitting out some parts of the original page into sub parts, however.

When I tried to move this code:

  (head
    (meta :charset "utf-8")
    (meta :name "viewport" :content "width=device-width, initial-scale=1.0")
    (meta :name "description" :content "")
    (meta :name "author" :content "")
    (title "Modern Dark Business - Start Bootstrap Template")
    ;; Bootstrap core CSS
    (link :rel "stylesheet" :href "css/bootstrap-slate.css")
    ;; Add custom CSS here
    (link :rel "stylesheet" :href "css/modern-business.css")
    (link :rel "stylesheet" :href "font-awesome/css/font-awesome.min.css"))

into infra.cljs.hl like so:

(defelem load-meta []
  (meta :charset "utf-8")
  (meta :name "viewport" :content "width=device-width, initial-scale=1.0")
  (meta :name "description" :content "")
  (meta :name "author" :content ""))

(defelem load-styles []
  ;; Bootstrap core CSS
  (link :rel "stylesheet" :href "css/bootstrap-slate.css")
  ;; Add custom CSS here
  (link :rel "stylesheet" :href "css/modern-business.css")
  (link :rel "stylesheet" :href "font-awesome/css/font-awesome.min.css"))

(defelem load-head [& page-title]
  (head
    (load-meta)
    (title page-title)
    (load-styles)))

and then call it (after the appropriate :require ... :as ...):

(pre/load-head "a title!")

I get errors. There's the error of the meta namespace collision (what's the best way to solve that?), and then there's the HTML render weirdness:

  1. The entire head is swallowed as <head></head>
  2. More perplexing, the (script ...) calls at the end of the page get converted to this:
   <a shape="rect"><_></_><_></_><_></_><_></_><_></_><_></_><_></_></a>

I thought perhaps the html-meta function was what I should use in this case, but changing that didn't seem to have any effect.

I'm new to cljs and obviously Hoplon, so I'm not sure if there is a known pattern for doing this sort of thing, or if this represents a bug in Hoplon...

Thanks for any help/guidance you can provide!

fix vendors and contrib

vendors: migrate to cljsjs where possible, provide as :foreign-libs where impossible
contrib: do not forget to enable :lib flag

loop-tpl does not render nested loops properly

In other words, code like that:

(page "index.html")

(defc state {:size 15})

(defelem row
  [{:keys [size idx]}]
  )

(defelem field
  [{:keys [size]}]
  (table
   (loop-tpl
    :bindings [i (range size)] :size size
    (tr
     (loop-tpl
      :bindings [j (range size)] :size size
      (td (text "~{i}, ~{j}")))))))

(html
  (head
   (style "
td {height: 20px; width: 20px}
table {border: 1px solid blue;}
          "))
  (body
    (h1 "Hello, World!")
    (field :size 15)))

produces HTML like that:

<html><head><style>
td {height: 20px; width: 20px}
table {border: 1px solid blue;}
          </style></head><body><h1>Hello, World!</h1><table><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr><tr><span></span></tr></table></body></html>

tailrecursion.hoplon.util.query doesn't find key the first time it's called

There are a few bugs with the current query function. The last line (apply query args) references the function query not @qcache or m so initial lookups fail.

Also, name is not applied to the key on the first lookup which means that keyword keys fail the first time. Conversely, no default is applied once qcache is populated.

Here's a version that fixes these problems:

(let [qcache (atom ::none)]
  (defn query
    [& [k & [dfl] :as args]]
    (if-not (= ::none @qcache)
      (if k (@qcache (name k) dfl) @qcache)
      (let [s (-> js/window .-location .-search)]
        (if (not (string/blank? s))
          (let [v (-> s (string/replace #"^\?" "") (string/split #"[&]"))
                m (->> v
                    (mapv #(string/split % #"[=]"))
                    (mapv #(mapv js/decodeURIComponent %))
                    (remove #(or (= [""] %) (= 0 (count %)) (< 2 (count %))))
                    (mapv #(if (< (count %) 2) (conj % "") %))
                    (into {}))]
            (reset! qcache m)
            (apply m (name k) dfl)))))))

The getting started example doesn't seem to work.

$ boot1 development
java.io.FileNotFoundException: Could not locate tailrecursion/hoplon/boot__init.class or tailrecursion/hoplon/boot.clj on classpath: , compiling:(/Users/andychambers/Projects/woogle/.boot/tmp/26484/_COLON_tailrecursion.boot_SLASH_bootscript/dir.tmp/tailrecursion/boot/user.clj:23:44)
↳ Caused by: Could not locate tailrecursion/hoplon/boot__init.class or tailrecursion/hoplon/boot.clj on classpath: 

Doesn't work with clojurescript "0.0-2261"

It works with clojurescript "0.0-2234" but not with the latest.

Compiling Hoplon dependencies...
Compiling Hoplon pages...
• src/index.cljs.hl
Compiling ClojureScript...

clojure.lang.ExceptionInfo: 
 at clojure.core$ex_info.invoke (core.clj:4327)
    cljs.analyzer$error.invoke (analyzer.clj:268)
    cljs.analyzer$analyze.invoke (analyzer.clj:1522)
    cljs.analyzer$analyze.invoke (analyzer.clj:1519)
    cljs.compiler$parse_ns$fn__4936$fn__4937.invoke (compiler.clj:959)
    cljs.compiler$parse_ns$fn__4936.invoke (compiler.clj:959)
    cljs.compiler$parse_ns.invoke (compiler.clj:954)
    cljs.compiler$parse_ns.invoke (compiler.clj:949)
    cljs.compiler$to_target_file.invoke (compiler.clj:1037)
    cljs.compiler$compile_root.invoke (compiler.clj:1069)
    cljs.closure$compile_dir.invoke (closure.clj:341)
    cljs.closure$eval5473$fn__5474.invoke (closure.clj:381)
    cljs.closure$eval5410$fn__5411$G__5401__5418.invoke (closure.clj:292)
    cljs.closure$eval5460$fn__5461.invoke (closure.clj:395)
    cljs.closure$eval5410$fn__5411$G__5401__5418.invoke (closure.clj:292)
    tailrecursion.boot.task.util.cljs.compiler.CljsSourcePaths/fn (compiler.clj:11)
    clojure.core$map$fn__4207.invoke (core.clj:2487)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.Cons.next (Cons.java:39)
    clojure.lang.RT.boundedLength (RT.java:1654)
    clojure.lang.RestFn.applyTo (RestFn.java:130)
    clojure.core$apply.invoke (core.clj:617)
    clojure.core$mapcat.doInvoke (core.clj:2514)
    clojure.lang.RestFn.invoke (RestFn.java:423)
    tailrecursion.boot.task.util.cljs.compiler.CljsSourcePaths._compile (compiler.clj:11)
    cljs.closure$build.invoke (closure.clj:955)
    cljs.closure$build.invoke (closure.clj:923)
    tailrecursion.boot.task.util.cljs.compiler$compile$fn__5678.invoke (compiler.clj:23)
    tailrecursion.boot.task.util.cljs.compiler$compile.invoke (compiler.clj:22)
    clojure.lang.Var.invoke (Var.java:431)
    clojure.lang.AFn.applyToHelper (AFn.java:178)
    clojure.lang.Var.applyTo (Var.java:532)
    clojure.core$apply.invoke (core.clj:617)
    tailrecursion.boot.task.util.cljs$compile_cljs.doInvoke (cljs.clj:55)
    clojure.lang.RestFn.invoke (RestFn.java:482)
    tailrecursion.boot.task$cljs$fn__1564$fn__1565$fn__1566.invoke (task.clj:75)
    tailrecursion.boot.task$cljs$fn__1564$fn__1565.invoke (task.clj:66)
    tailrecursion.hoplon.boot$hoplon$fn__2296$fn__2297.invoke (boot.clj:194)
    tailrecursion.boot.core.task$files_changed_QMARK_$fn__1234$fn__1235.invoke (task.clj:250)
    tailrecursion.boot.core.task$auto$fn__1223$fn__1224.invoke (task.clj:223)
    tailrecursion.boot.user$eval2322.invoke (user.clj:42)
    clojure.lang.Compiler.eval (Compiler.java:6619)
    clojure.lang.Compiler.load (Compiler.java:7064)
    clojure.lang.Compiler.loadFile (Compiler.java:7020)
    clojure.lang.RT$3.invoke (RT.java:318)
    tailrecursion.boot$_main.doInvoke (boot.clj:117)
    clojure.lang.RestFn.invoke (RestFn.java:467)
    clojure.lang.Var.invoke (Var.java:427)
    clojure.lang.AFn.applyToHelper (AFn.java:172)
    clojure.lang.Var.applyTo (Var.java:532)
    clojure.core$apply.invoke (core.clj:623)
    tailrecursion.boot.loader$_main.doInvoke (loader.clj:190)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    tailrecursion.boot.loader.main (:-1)
Caused by: java.lang.NullPointerException: null
 at cljs.core$import_macros$fn__5702.invoke (core.clj:49)
    clojure.core$map$fn__4207.invoke (core.clj:2485)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$map$fn__4211.invoke (core.clj:2490)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:67)
    clojure.lang.RT.seq (RT.java:484)
    clojure.core$seq.invoke (core.clj:133)
    clojure.core$concat$cat__3925$fn__3926.invoke (core.clj:687)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.Cons.next (Cons.java:39)
    clojure.lang.RT.next (RT.java:598)
    clojure.lang.Compiler.eval (Compiler.java:6606)
    clojure.lang.Compiler.load (Compiler.java:7064)
    clojure.lang.RT.loadResourceScript (RT.java:370)
    clojure.lang.RT.loadResourceScript (RT.java:361)
    clojure.lang.RT.load (RT.java:440)
    clojure.lang.RT.load (RT.java:411)
    clojure.core$load$fn__5018.invoke (core.clj:5530)
    clojure.core$load.doInvoke (core.clj:5529)
    clojure.lang.RestFn.invoke (RestFn.java:408)
    cljs.analyzer$load_core.invoke (analyzer.clj:210)
    cljs.analyzer$analyze$fn__3951.invoke (analyzer.clj:1528)
    cljs.analyzer$analyze.invoke (analyzer.clj:1524)
    cljs.analyzer$analyze.invoke (analyzer.clj:1519)
    cljs.compiler$parse_ns$fn__4936$fn__4937.invoke (compiler.clj:959)
    cljs.compiler$parse_ns$fn__4936.invoke (compiler.clj:959)
    cljs.compiler$parse_ns.invoke (compiler.clj:954)
    cljs.compiler$parse_ns.invoke (compiler.clj:949)
    cljs.compiler$to_target_file.invoke (compiler.clj:1037)
    cljs.compiler$compile_root.invoke (compiler.clj:1069)
    cljs.closure$compile_dir.invoke (closure.clj:341)
    cljs.closure$eval5473$fn__5474.invoke (closure.clj:381)
    cljs.closure$eval5410$fn__5411$G__5401__5418.invoke (closure.clj:292)
    cljs.closure$eval5460$fn__5461.invoke (closure.clj:395)
    cljs.closure$eval5410$fn__5411$G__5401__5418.invoke (closure.clj:292)
    tailrecursion.boot.task.util.cljs.compiler.CljsSourcePaths/fn (compiler.clj:11)
    clojure.core$map$fn__4207.invoke (core.clj:2487)
    clojure.lang.LazySeq.sval (LazySeq.java:42)
    clojure.lang.LazySeq.seq (LazySeq.java:60)
    clojure.lang.Cons.next (Cons.java:39)
    clojure.lang.RT.boundedLength (RT.java:1654)
    clojure.lang.RestFn.applyTo (RestFn.java:130)
    clojure.core$apply.invoke (core.clj:617)
    clojure.core$mapcat.doInvoke (core.clj:2514)
    clojure.lang.RestFn.invoke (RestFn.java:423)
    tailrecursion.boot.task.util.cljs.compiler.CljsSourcePaths._compile (compiler.clj:11)
    cljs.closure$build.invoke (closure.clj:955)
    cljs.closure$build.invoke (closure.clj:923)
    tailrecursion.boot.task.util.cljs.compiler$compile$fn__5678.invoke (compiler.clj:23)
    tailrecursion.boot.task.util.cljs.compiler$compile.invoke (compiler.clj:22)
    clojure.lang.Var.invoke (Var.java:431)
    clojure.lang.AFn.applyToHelper (AFn.java:178)
    clojure.lang.Var.applyTo (Var.java:532)
    clojure.core$apply.invoke (core.clj:617)
    tailrecursion.boot.task.util.cljs$compile_cljs.doInvoke (cljs.clj:55)
    clojure.lang.RestFn.invoke (RestFn.java:482)
    tailrecursion.boot.task$cljs$fn__1564$fn__1565$fn__1566.invoke (task.clj:75)
    tailrecursion.boot.task$cljs$fn__1564$fn__1565.invoke (task.clj:66)
    tailrecursion.hoplon.boot$hoplon$fn__2296$fn__2297.invoke (boot.clj:194)
    tailrecursion.boot.core.task$files_changed_QMARK_$fn__1234$fn__1235.invoke (task.clj:250)
    tailrecursion.boot.core.task$auto$fn__1223$fn__1224.invoke (task.clj:223)
    tailrecursion.boot.user$eval2322.invoke (user.clj:42)
    clojure.lang.Compiler.eval (Compiler.java:6619)
    clojure.lang.Compiler.load (Compiler.java:7064)
    clojure.lang.Compiler.loadFile (Compiler.java:7020)
    clojure.lang.RT$3.invoke (RT.java:318)
    tailrecursion.boot$_main.doInvoke (boot.clj:117)
    clojure.lang.RestFn.invoke (RestFn.java:467)
    clojure.lang.Var.invoke (Var.java:427)
    clojure.lang.AFn.applyToHelper (AFn.java:172)
    clojure.lang.Var.applyTo (Var.java:532)
    clojure.core$apply.invoke (core.clj:623)
    tailrecursion.boot.loader$_main.doInvoke (loader.clj:190)
    clojure.lang.RestFn.applyTo (RestFn.java:137)
    tailrecursion.boot.loader.main (:-1)

Tutorial: don't understand anonymous tags

From reading the documentation about anonymous tags, I feel I'm either missing something, or that the snippet is incorrect.

((div :id "greet" :class "active")
 (h1 "Hello, world!")
 (p "I'm new here."))

I don't understand why the h1 and p elements are not nested inside the div; here they are peers of the div, and I don't get how Hoplon will know to nest them.

prerender task

Prerender functionality need to be ported from original code as separate task. It must consume htmls in fileset and prerender them.

“mount” feature

As for now pages generate cljs file with special hoploninit function which is called in bootstrap html file to replace its content completely. I propose to allow pages to provide not only the full page, but also only “widget”, which could be “mounted” in any part of existing DOM from any cljs code. Page as it is now will be a particular case of mounting to document root.

So, things to do:

  • page must declare namespace instead of html name (it is not generated by default now, see (details)[http://hoplon.discoursehosting.net/t/porting-hoplon-to-boot2/405] and #55)
  • page must not require its last form to be html, any element is allowed
  • page must provide mount function instead of hoploninit which takes a DOM node or selector and replaces its contents with hoplon-generated element.
  • may be rename page to smth. else to avoid confusion?

or, alternatively, we can abandon page concept at all and provide mount function which will mount any specified element into any DOM place. I think it is even better than to generate mount for every page

REPL development

Hi,

I'm trying to address the issue of setting up a REPL environment for working with Hoplon.

First I would like to say that I'm a newbie on Clojure, so, just let me know if I'm talking any non-sense here, hehe.

Ok, without using Hoplon, I'm able to get a browser REPL working by using https://github.com/james-henderson/simple-brepl

Them comes the first issue... Since Hoplon uses Boot, I wasn't able to find on how to add plugins to Boot in the same way as on Leiningen... So, to work around that I did boot lein to generate the project.clj, and them I added the plugin strait there (not the best option, but it's the only one that I could figure out...).

Well, after that I was able to launch my REPL from Lein, and start the (simple-brepl), but for my surprise, when I tried to require weasel (which is a simple-brepl dependency) it didn't worked, it could not find the namespace... I know this approach works on regular Leiningen projects, so, I have no idea what's missing...

I think REPL development is one the greatest things on Clojure, I like Hoplon a lot, but not being able to REPL development is really a big deal...

I would love to help on process to enable REPL with Hoplon, but like I said, I still new to Clojure and I just got stuck, so, what can I do in order to make this setup possible?

Thanks

SEO

The index page of http://hoplon.io states that "Hoplon does not perform any serverside HTML rendering; it is completely unnecessary, even for SEO purposes.".

However...

Search for the text "Build a Hoplon application from scratch." in Google, and no content from http://hoplon.io/#/getting-started/ will be listed.

It seems like a contradiction to me, but I may be looking at it with an incomplete understanding.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.