'use strict';
angular.module('mgcrea.ngStrap.collapse', [])
.provider('$collapse', function () {
var defaults = this.defaults = {
animation: 'am-collapse',
disallowToggle: false,
activeClass: 'in',
startCollapsed: false,
allowMultiple: false
};
var controller = this.controller = function ($scope, $element, $attrs) {
var self = this;
// Attributes options
self.$options = angular.copy(defaults);
angular.forEach(['animation', 'disallowToggle', 'activeClass', 'startCollapsed', 'allowMultiple'], function (key) {
if (angular.isDefined($attrs[key])) self.$options[key] = $attrs[key];
});
// use string regex match boolean attr falsy values, leave truthy values be
var falseValueRegExp = /^(false|0|)$/i;
angular.forEach(['disallowToggle', 'startCollapsed', 'allowMultiple'], function (key) {
if (angular.isDefined($attrs[key]) && falseValueRegExp.test($attrs[key])) {
self.$options[key] = false;
}
});
self.$toggles = [];//觸發(fā)panel存儲
self.$targets = [];//panel body存儲
self.$viewChangeListeners = [];//其中的函數(shù)會以流水線的形式在視圖中的值發(fā)生變化時被逐一調(diào)用旋膳。用來渲染view
self.$registerToggle = function (element) {//把element注冊到$toggles 中
self.$toggles.push(element);
};
self.$registerTarget = function (element) {//把element注冊到panel body存儲
self.$targets.push(element);
};
self.$unregisterToggle = function (element) {//在$toggles刪除對應(yīng)的element
var index = self.$toggles.indexOf(element);
// remove toggle from $toggles array
self.$toggles.splice(index, 1);
};
self.$unregisterTarget = function (element) {//在$targets 刪除對應(yīng)的element
var index = self.$targets.indexOf(element);
// remove element from $targets array
self.$targets.splice(index, 1);
if (self.$options.allowMultiple) {//如果允許同時打開多個panel
// remove target index from $active array values
deactivateItem(element);//就把這個active的元素刪除
}
// fix active item indexes
fixActiveItemIndexes(index);
self.$viewChangeListeners.forEach(function (fn) {//重新render
fn();
});
};
// use array to store all the currently open panels 存儲所有打開的項
self.$targets.$active = !self.$options.startCollapsed ? [0] : [];
//設(shè)置哪個element顯示
self.$setActive = $scope.$setActive = function (value) {
if (angular.isArray(value)) {
self.$targets.$active = value;
} else if (!self.$options.disallowToggle && isActive(value)) {
deactivateItem(value);
} else {
activateItem(value);
}
self.$viewChangeListeners.forEach(function (fn) {
fn();
});
};
//起始狀態(tài)
self.$activeIndexes = function () {
if (self.$options.allowMultiple) {
return self.$targets.$active;
}
return self.$targets.$active.length === 1 ? self.$targets.$active[0] : -1;
};
function fixActiveItemIndexes (index) {
// item with index was removed, so we
// need to adjust other items index values
var activeIndexes = self.$targets.$active;
for (var i = 0; i < activeIndexes.length; i++) {
if (index < activeIndexes[i]) {
activeIndexes[i] = activeIndexes[i] - 1;
}
// the last item is active, so we need to
// adjust its index
if (activeIndexes[i] === self.$targets.length) {
activeIndexes[i] = self.$targets.length - 1;
}
}
}
//判斷value是否是active
function isActive (value) {
var activeItems = self.$targets.$active;
return activeItems.indexOf(value) !== -1;
}
//刪除active的元素
function deactivateItem (value) {
var index = self.$targets.$active.indexOf(value);
if (index !== -1) {
self.$targets.$active.splice(index, 1);
}
}
//添加當(dāng)前點擊的element到$active
function activateItem (value) {
if (!self.$options.allowMultiple) {//不允許打開多個panel
// remove current selected item
self.$targets.$active.splice(0, 1);//關(guān)閉當(dāng)前的
}
if (self.$targets.$active.indexOf(value) === -1) {//如果當(dāng)前的value不在active里就加入
self.$targets.$active.push(value);
}
}
};
this.$get = function () {
var $collapse = {};
$collapse.defaults = defaults;
$collapse.controller = controller;
return $collapse;
};
})
.directive('bsCollapse', function ($window, $animate, $collapse) {
return {
require: ['?ngModel', 'bsCollapse'],
controller: ['$scope', '$element', '$attrs', $collapse.controller],
link: function postLink (scope, element, attrs, controllers) {
var ngModelCtrl = controllers[0];
var bsCollapseCtrl = controllers[1];
if (ngModelCtrl) {
// Update the modelValue following更新modelValue
bsCollapseCtrl.$viewChangeListeners.push(function () {
ngModelCtrl.$setViewValue(bsCollapseCtrl.$activeIndexes());
});
// modelValue -> $formatters -> viewValue
ngModelCtrl.$formatters.push(function (modelValue) {
// console.warn('$formatter("%s"): modelValue=%o (%o)', element.attr('ng-model'), modelValue, typeof modelValue);
if (angular.isArray(modelValue)) {
// model value is an array, so just replace
// the active items directly
bsCollapseCtrl.$setActive(modelValue);
} else {
var activeIndexes = bsCollapseCtrl.$activeIndexes();
if (angular.isArray(activeIndexes)) {
// we have an array of selected indexes
if (activeIndexes.indexOf(modelValue * 1) === -1) {
// item with modelValue index is not active
bsCollapseCtrl.$setActive(modelValue * 1);
}
} else if (activeIndexes !== modelValue * 1) {
bsCollapseCtrl.$setActive(modelValue * 1);
}
}
return modelValue;
});
}
}
};
})
.directive('bsCollapseToggle', function () {
return {
require: ['^?ngModel', '^bsCollapse'],
link: function postLink (scope, element, attrs, controllers) {
// var ngModelCtrl = controllers[0];
var bsCollapseCtrl = controllers[1];
// Add base attr
element.attr('data-toggle', 'collapse');
// Push pane to parent bsCollapse controller
bsCollapseCtrl.$registerToggle(element);
// remove toggle from collapse controller when toggle is destroyed
scope.$on('$destroy', function () {
bsCollapseCtrl.$unregisterToggle(element);
});
element.on('click', function () {
if (!attrs.disabled) {//判斷bs-collapse-toggle是否是指令
var index = attrs.bsCollapseToggle && attrs.bsCollapseToggle !== 'bs-collapse-toggle' ? attrs.bsCollapseToggle : bsCollapseCtrl.$toggles.indexOf(element);
bsCollapseCtrl.$setActive(index * 1);
scope.$apply();
}
});
}
};
})
.directive('bsCollapseTarget', function ($animate) {
return {
require: ['^?ngModel', '^bsCollapse'],
// scope: true,
link: function postLink (scope, element, attrs, controllers) {
// var ngModelCtrl = controllers[0];
var bsCollapseCtrl = controllers[1];
// Add base class
element.addClass('collapse');
// Add animation class
if (bsCollapseCtrl.$options.animation) {
element.addClass(bsCollapseCtrl.$options.animation);
}
// Push pane to parent bsCollapse controller 注冊panel容器
bsCollapseCtrl.$registerTarget(element);
// remove pane target from collapse controller when target is destroyed
scope.$on('$destroy', function () {
bsCollapseCtrl.$unregisterTarget(element);
});
//通過判斷當(dāng)前element在$targets的index,與$activeIndexes中的比較來確定
function render () {
var index = bsCollapseCtrl.$targets.indexOf(element);
var active = bsCollapseCtrl.$activeIndexes();
var action = 'removeClass';
if (angular.isArray(active)) {
if (active.indexOf(index) !== -1) {
action = 'addClass';
}
} else if (index === active) {
action = 'addClass';
}
$animate[action](element, bsCollapseCtrl.$options.activeClass);
}
bsCollapseCtrl.$viewChangeListeners.push(function () {
render();
});
render();
}
};
});
AngularStrap Directives Collapses 源碼解讀
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進(jìn)店門国裳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人全跨,你說我怎么就攤上這事缝左。” “怎么了螟蒸?”我有些...
- 文/不壞的土叔 我叫張陵盒使,是天一觀的道長。 經(jīng)常有香客問我七嫌,道長少办,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任诵原,我火速辦了婚禮英妓,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绍赛。我一直安慰自己蔓纠,他們只是感情好,可當(dāng)我...
- 文/花漫 我一把揭開白布吗蚌。 她就那樣靜靜地躺著腿倚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蚯妇。 梳的紋絲不亂的頭發(fā)上敷燎,一...
- 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼拄衰!你這毒婦竟也來了它褪?” 一聲冷哼從身側(cè)響起,我...
- 正文 年R本政府宣布,位于F島的核電站竭翠,受9級特大地震影響振坚,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜斋扰,卻給世界環(huán)境...
- 文/蒙蒙 一渡八、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧传货,春花似錦屎鳍、人聲如沸。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至粮宛,卻和暖如春窥淆,著一層夾襖步出監(jiān)牢的瞬間卖宠,已是汗流浹背。 一陣腳步聲響...
推薦閱讀更多精彩內(nèi)容
- 本篇文章是后續(xù)解讀Disruptor源碼的導(dǎo)讀作媚,適合對Disruptor還不了解的同學(xué)。如果有興趣帅刊,還可以看下我之...
- 前言 由于上一篇講的都是大致的流程赖瞒,所以這一篇我們抽取流程中的一步女揭,給大家介紹Authentication部分的源...
- Why underscore 最近開始看 underscore.js 源碼,并將 underscore.js 源碼...
- ? elasticjob是使用zk做分布式協(xié)調(diào)栏饮,包括分片參數(shù)配置吧兔,再分片,選主節(jié)點袍嬉,作業(yè)狀態(tài)等一系列...
- 1在線動態(tài)計算分類最熱門商品案例回顧與演示 我們用SparkStreaming+SparkSQL來實現(xiàn)分類最熱門商...