AngularJSのcompile.jsを読んだ際のメモ
priorityは高いものから順番に実行されれる。
terminalがtrueだとそのpriorityで終わり。
$CompileProvider($provide, $$sanitizeUriProvider)
function registerDirective(name, directiveFactory)
$compileProvider.directive(name, directiveFactory)の実体である。
nameはcamel case化したものである。
providerCacheにdirectiveを生成する関数をname + “Directive”というキー名で登録する。
hasDirectives[name]が存在していない場合、directiveFactoryをhasDirectives[name]に登録する。
-
aHrefSanitizationWhitelist(regexp)
aタグのhrefのサニタイズに利用する正規表現を変更する。 -
imgSrcSanitizationWhitelist(regexp)
imgタグのsrcのサニタイズに利用する正規表現を変更する。
$CompileProvider::$get()
function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext)を返す。
Attributes(element, attr)
Attributes::$normalize(name)
nameをcamel caseに変換する。
Attributes::$addClass(classVal)
コンストラクタの引数のelementのclass属性にclassValを追加する。
Attributes::$removeClass(classVal)
コンストラクタの引数のelementのclass属性にclassValを削除する。
Attributes::$updateClass(newClasses, oldClasses)
コンストラクタの引数のelementのclass属性にnewClassesとoldClassesの差分を反映する。
Attributes::$set(key, value, writeAttr, attrName)
key: directive(\(element)にある属性型のdirectiveのcamel case化した名前や
directiveのscopeに存在しているモデル名 (ex: ngIf)
value: keyの値 (ex: "foo_id != 0")
writeAttr: directive(\)element)にattrName=valueを属性として書き込むか (デフォルトはtrue)
attrName: directive($$element)に書き込まれる属性名 (デフォルトはkeyをsnake caseに変換したもの)
Attributes::$observe(key, fn)
key: directive(\(element)にある属性型のdirectiveのcamel case化した名前や
directiveのscopeに存在しているモデル名 (ex: ngIf)
fn:\)observersに格納される関数です。keyの値が変更されるたびに実行される。
\(observersにfnを格納する。\)observersからfnを削除する関数を返す。
compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext)
$compile.$get()の戻り値
$compileNodesをjqLiteオブジェクトにする。
$compileNodesの要素の中で空文字でないTextNodeはでwrappする。
$compileNodesのclass属性にng-scopeを追加する。
これを返すfunction publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn)
compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective, previousCompileContext)
compileで利用されるcompositeLinkFnを返す。
nodeListのnodeごとにAttributesインスタンスを生成する。
nodeListのnodeごとにcollectDirectives()を実行する。
nodeListのnodeごとにaddDirectivesToNode()を実行する。
nodeLinkFn.scopeがtrue(directive.scope === true)なら対象の要素のclassに’ng-scope’を加える。
collectDirectives(node, directives, attrs, maxPriority, ignoreDirective)
compileNodes()で利用されている。
nodeに存在しているdirectiveを見つける。
そのdirectiveのデータを生成する。
directiveのデータをdirectivesに格納する。
directivesを返す。
nodeのnodeTypeがElement(1)の場合
以下をチェックして該当した場合、 directivesに加える。
- node自身がdirective
- nodeの属性がdirective
- nodeのclassがdirective
要素の属性データを登録する。
nodeのnodeTypeがText Node(3)の場合
addTextInterpolateDirective(directives, text)を実行する
nodeのnodeTypeがComment(8)の場合
COMMENT_DIRECTIVE_REGEXPにマッチした場合、addDirective()を実行する
byPriorityでpriorityを降順にソートする。
addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName, endAttrName)
collectDirectives()内で呼ばれる。
tDirectivesにdirectiveのデータを格納する。
hasDirectives($compileProvider.directiveで登録)にnameキーが存在した場合、
directives = $injector.get(name + Suffix)
directivesの各データごとにdirectiveがAでstart属性とend属性が設定されていた場合、それらをdirective.\(startとdirective.\)endに付与する。
tDirectivesにdirectiveのデータを格納する。
applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn, jqCollection, originalReplaceDirective, preLinkFns, postLinkFns, previousCompileContext)
jqCollectionはroot of compile tree
nodeLinkFnを返す。
compileNodes()内で利用しています。
要素に存在しているdirectiveごとに以下の処理をする。
directiveValueには一時的に使用する値を代入する。
- directive.$$startがある場合は範囲内にあるnodeを取得して$compileNodeに格納する。
- terminalPriority > directive.priorityならループを抜ける。
- directive.scopeに対する処理
1.directive.templateUrlが設定されていない状態でdirective.scopeがobjectの場合
newIsolateScopeDirective = directiveとする。
2.newScopeDirective = newScopeDirective || directive; - directiveName = directive.name;
- !directive.templateUrl && directive.controllerに対する処理
1.controllerDirectives = controllerDirectives || {};
2.controllerDirectives[directiveName] = directive; - directive.transcludeに対する処理
1.directive.transclude === “element”
hasElementTranscludeDirective = true; 後で書く
2.directive.transclude == trueのとき
$template = jqLite(jqLiteClone(compileNode)).contents();
$compileNode.empty(); // clear contents
childTranscludeFn = compile($template, transcludeFn); - directive.templateに対する処理
1.directive.templateが関数の場合はdirective.template($compileNode, templateAttrs)を実行する。 その戻り値をテンプレートとする。文字列の場合はdirective.templateをテンプレートとする。 2.denormalizeTemplate(テンプレート) テンプレートの”{{” “}}“が別の文字列に設定されていた場合、”{{” “}}“をそれらと変換する。
3.directive.replaceが存在しない場合、$compileNodeにテンプレートを挿入する。 - directive.replaceに対する処理
このreplaceの処理はdirective.templateに対する処理で、directive.templateUrlに対応する処理はcompileTemplateUrlで実行される。
テンプレートをjqLiteオブジェクトに変換したものを$templateに代入する。
$compileNodeを$template[0]で置き換える。
$template[0]内にあるdirectiveをcollectDirectivesで取得する。
directivesで処理を行っているdirectiveの直後に$template[0]内にあるdirectiveを格納する。
$template[0]内の各Nodeの属性を現在処理中のdirectiveの属性データに統合する。 - directive.templateUrlに対する処理
compileTemplateUrl()を実行してnodeLinkFnを上書きする。 - directive.compileに対する処理
terminalUrlがある場合はそれに対応した後にこの処理が実行される。
linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
compileTemplateUrl(directives, $compileNode, tAttrs, $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext)
applyDirectivesToNode()内で利用されている。
nodeLinkFn上書きするdelayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn)を生成して返す。
$compileNodeの子要素を削除する。
$http.get(templateUrl)でテンプレートを取得する。
現在処理中のdirectiveに対してreplaceが設定されている場合、それに対応した処理をする。
directive.templateとと処理内容はほぼ同じだが、applyDirectivesToNode(), compileNode()を実行する。
delayedNodeLinkFnと$http.get()のコールバック関数のどちらが先に実行されるかで処理の内容が異なる。
それは、linkQueueに要素数があるかどうかで決まる。
delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn)
templateUrlが指定されていた場合のnodeLinkFnの実体
applyDirectivesToNode()の戻り値