Skip to content
This repository has been archived by the owner on Sep 15, 2024. It is now read-only.

Commit

Permalink
#10: Provide annotation/macro to inject dependencies
Browse files Browse the repository at this point in the history
- Replace *Aware traits with @Inject
- Package structure cleanup
  • Loading branch information
mysticfall committed Oct 25, 2014
1 parent 0c94a4f commit 1a093e2
Show file tree
Hide file tree
Showing 94 changed files with 1,071 additions and 1,472 deletions.
4 changes: 3 additions & 1 deletion build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@ scalacOptions ++= Seq("-feature","-deprecation")
homepage := Some(url("http://github.com/greencatsoft/scalajs-angular"))

libraryDependencies ++= Seq(
"org.scala-lang.modules.scalajs" %%% "scalajs-dom" % "0.6")
"org.scala-lang.modules.scalajs" %%% "scalajs-dom" % "0.6",
"org.scala-lang" % "scala-reflect" % scalaVersion.value % "compile"
)

publishTo := {
val nexus = "https://oss.sonatype.org/"
Expand Down
14 changes: 9 additions & 5 deletions src/main/scala/com/greencatsoft/angularjs/Angular.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
package com.greencatsoft.angularjs

import scala.language.implicitConversions
import scala.scalajs.js
import scala.scalajs.js.JSConverters.genTravConvertible2JSRichGenTrav

import org.scalajs.dom.Element

import com.greencatsoft.angularjs.element.AngularElement
object Angular {

trait Angular extends js.Object {
import internal.angular

def module(name: String, require: js.Array[String]): Module = ???
def apply(name: String): Option[Module] =
angular.module(name).toOption.map(new Module(_))

implicit def element(elem: Element): AngularElement
def module(name: String, dependencies: Seq[String] = Nil): Module =
new Module(angular.module(name, dependencies.toJSArray))

implicit def element(elem: Element): AngularElement = angular.element(elem)
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package com.greencatsoft.angularjs.element
package com.greencatsoft.angularjs

import scala.language.implicitConversions
import scala.scalajs.js
Expand Down
7 changes: 7 additions & 0 deletions src/main/scala/com/greencatsoft/angularjs/Annotations.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.greencatsoft.angularjs

import scala.annotation.StaticAnnotation

class inject extends StaticAnnotation

class injectable(name: String) extends StaticAnnotation
3 changes: 3 additions & 0 deletions src/main/scala/com/greencatsoft/angularjs/Config.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.greencatsoft.angularjs

trait Config extends Service with Initializable
8 changes: 0 additions & 8 deletions src/main/scala/com/greencatsoft/angularjs/ConfigBuilder.scala

This file was deleted.

17 changes: 17 additions & 0 deletions src/main/scala/com/greencatsoft/angularjs/Controller.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.greencatsoft.angularjs

import scala.scalajs.js

import com.greencatsoft.angularjs.core.ScopeAware

trait Controller extends NamedService with Initializable with ScopeAware {

abstract override def initialize() {
super.initialize()
scope.dynamic.controller = this.asInstanceOf[js.Object]
}
}

trait PageController extends Controller with Templated

trait TitledPageController extends PageController with Titled
233 changes: 233 additions & 0 deletions src/main/scala/com/greencatsoft/angularjs/Directive.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
package com.greencatsoft.angularjs

import scala.language.experimental.macros
import scala.language.implicitConversions
import scala.scalajs.js
import scala.scalajs.js.Any.{ fromBoolean, fromFunction2, fromFunction4, fromString, wrapArray }
import scala.scalajs.js.UndefOr
import scala.scalajs.js.UndefOr.undefOr2ops
import scala.scalajs.js.annotation.JSBracketAccess

import org.scalajs.dom.Element

import com.greencatsoft.angularjs.core.Scoped
import com.greencatsoft.angularjs.internal.{ ConfigBuilder, Configuration, ServiceProxy }

trait Directive extends NamedService with Function0[Configuration] with Scoped with ConfigBuilder {

import internal.{ Angular => angular }

override def apply(): Configuration = buildConfig()

override def buildConfig(config: Configuration): Configuration = {
def bind(scope: ScopeType): ScopeType = {
scope.dynamic.directive = this.asInstanceOf[js.Object]
scope
}

config("link") = (scope: ScopeType, elems: js.Array[Element], attrs: Attributes, controllers: UndefOr[js.Any]) => {
controllers.toOption match {
case Some(arr) if js.Array.isArray(arr) =>
val args = arr.asInstanceOf[js.Array[js.Any]].toSeq.map(ServiceProxy.unbind[Controller](_)).flatten
link(bind(scope), elems, attrs, args: _*)
case Some(c) =>
ServiceProxy.unbind[Controller](c) match {
case Some(arg) => link(bind(scope), elems, attrs, arg)
case _ => link(bind(scope), elems, attrs)
}
case None => link(bind(scope), elems, attrs)
}
}

controller.foreach(config("controller") = _)

super.buildConfig(config)
}

def controller(): Option[js.Any] = None

protected def proxy[A <: Controller](target: A): js.Any = macro ServiceProxy.newInstance[A]

def link(scope: ScopeType, elems: Seq[Element], attrs: Attributes, controller: Controller*): Unit = Unit
}

trait Attributes extends js.Object {

val $attr: js.Dictionary[String] = ???

def $addClass(classVal: String): Unit = ???

def $removeClass(classVal: String): Unit = ???

def $updateClass(newClasses: String, oldClasses: String): Unit = ???

@JSBracketAccess
def apply(name: String): UndefOr[String] = ???

@JSBracketAccess
def update(name: String, value: String): Unit = ???

def $get(name: String): UndefOr[String] = ???

def $set(name: String, value: String): Unit = ???

def $observe(key: String, fn: js.Function1[String, Unit]): Unit = ???
}

trait Requires extends ConfigBuilder {
this: Directive =>

var requirements = Set.empty[Requirement]

abstract override def buildConfig(config: Configuration): Configuration = {
config("require") = js.Array[String](requirements.toSeq.map(_.toString): _*)

super.buildConfig(config)
}

case class Requirement(name: String, lookup: Boolean, optional: Boolean = false) {

override def toString = (if (lookup) "^" else "") + (if (optional) "?" else "") + name
}

def ^(requirement: NamedService) = new Requirement(requirement.name, true)

def ^?(requirement: NamedService) = new Requirement(requirement.name, true, true)

def ?(requirement: NamedService) = new Requirement(requirement.name, false, true)

implicit def ~(requirement: NamedService) = new Requirement(requirement.name, false)
}

trait RestrictedDirective extends Directive with ConfigBuilder {

def restrict: Set[String] = Set.empty

abstract override def buildConfig(config: Configuration): Configuration = {
config("restrict") = restrict.mkString

super.buildConfig(config)
}
}

trait ElementDirective extends RestrictedDirective {

override def restrict = super.restrict + "E"

var transclude = false

var replace = false

abstract override def buildConfig(config: Configuration): Configuration = {
config("transclude") = transclude
config("replace") = replace

super.buildConfig(config)
}
}

trait AttributeDirective extends RestrictedDirective {

override def restrict = super.restrict + "A"
}

trait ClassDirective extends RestrictedDirective {

override def restrict = super.restrict + "C"
}

trait CommentDirective extends RestrictedDirective {

override def restrict = super.restrict + "M"
}

trait ScopeStrategy extends ConfigBuilder {
this: Directive =>
}

trait InheritParentScope extends ScopeStrategy {
this: Directive =>

override def buildConfig(config: Configuration): Configuration = {
config("scope") = true

super.buildConfig(config)
}
}

trait UseParentScope extends ScopeStrategy {
this: Directive =>

override def buildConfig(config: Configuration): Configuration = {
config("scope") = false

super.buildConfig(config)
}
}

trait IsolatedScope extends ScopeStrategy {
this: Directive =>

var bindings = Seq.empty[ScopeBinding]

override def buildConfig(config: Configuration): Configuration = {
val dict = js.Dictionary.empty[String]

bindings foreach { b =>
dict(b.name) = s"${b.prefix}${b.attribute}"
}

config("scope") = dict

super.buildConfig(config)
}

abstract class ScopeBinding(val prefix: String) {

val name: String

val attribute: String
}

case class UnidirectionalBinding(name: String, attribute: String = "") extends ScopeBinding("=")

case class BidirectionalBinding(name: String, attribute: String = "") extends ScopeBinding("@")

case class BehavioralBinding(name: String, attribute: String = "") extends ScopeBinding("&")

implicit class BindingBuilder(name: String) {

def :=(attribute: String = ""): ScopeBinding = UnidirectionalBinding(name, attribute)

def :@(attribute: String = ""): ScopeBinding = BidirectionalBinding(name, attribute)

def :&(attribute: String = ""): ScopeBinding = BehavioralBinding(name, attribute)
}
}

trait TemplatedDirective extends ConfigBuilder with Templated {
this: Directive =>

def getTemplateUrl(elems: Seq[AngularElement], attrs: Attributes): String = templateUrl

abstract override def buildConfig(config: Configuration): Configuration = {
config("templateUrl") = (elems: js.Array[AngularElement], attrs: Attributes) => getTemplateUrl(elems, attrs)

super.buildConfig(config)
}
}

trait TemplateSourceDirective extends ConfigBuilder with TemplateSource {
this: Directive =>

val template: String

def getTemplate(elems: Seq[AngularElement], attrs: Attributes): String = template

abstract override def buildConfig(config: Configuration): Configuration = {
config("template") = (elems: js.Array[AngularElement], attrs: Attributes) => getTemplate(elems, attrs)

super.buildConfig(config)
}
}

5 changes: 1 addition & 4 deletions src/main/scala/com/greencatsoft/angularjs/Factory.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
package com.greencatsoft.angularjs

trait Factory[A] extends NamedTarget with Function0[A] {

override def initialize(): Unit = Unit
}
trait Factory[A] extends NamedService with Function0[A]
6 changes: 6 additions & 0 deletions src/main/scala/com/greencatsoft/angularjs/Initializable.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.greencatsoft.angularjs

trait Initializable {

def initialize(): Unit = Unit
}
5 changes: 0 additions & 5 deletions src/main/scala/com/greencatsoft/angularjs/Injectable.scala

This file was deleted.

12 changes: 0 additions & 12 deletions src/main/scala/com/greencatsoft/angularjs/InjectionTarget.scala

This file was deleted.

Loading

0 comments on commit 1a093e2

Please sign in to comment.