From 652d0db04325166a180377c738a376543b5f2357 Mon Sep 17 00:00:00 2001 From: Pasvaz Date: Tue, 21 Jan 2014 00:29:06 +0100 Subject: [PATCH] Create new directive: bo-switch Close #30 TODO: create documentation --- bindonce.js | 59 ++++++++++++++++++++++++++++++++++++++++--------- bindonce.min.js | 2 +- 2 files changed, 50 insertions(+), 11 deletions(-) diff --git a/bindonce.js b/bindonce.js index 0e0c885..41b71d1 100644 --- a/bindonce.js +++ b/bindonce.js @@ -8,9 +8,9 @@ * @license MIT License, http://www.opensource.org/licenses/MIT */ - angular.module('pasvaz.bindonce', []) + var bindonceModule = angular.module('pasvaz.bindonce', []); - .directive('bindonce', function () + bindonceModule.directive('bindonce', function () { var toBoolean = function (value) { @@ -110,7 +110,7 @@ var value = binder.scope.$eval((binder.interpolate) ? $interpolate(binder.value) : binder.value); switch (binder.attr) { - case 'if': + case 'boIf': if (toBoolean(value)) { binder.transclude(binder.scope.$new(), function (clone) @@ -126,6 +126,38 @@ }); } break; + case 'boSwitch': + var selectedTranscludes, switchCtrl = binder.controller[0]; + if ((selectedTranscludes = switchCtrl.cases['!' + value] || switchCtrl.cases['?'])) + { + binder.scope.$eval(binder.attrs.change); + angular.forEach(selectedTranscludes, function (selectedTransclude) + { + selectedTransclude.transclude(binder.scope.$new(), function (clone) + { + var parent = selectedTransclude.element.parent(); + var afterNode = selectedTransclude.element && selectedTransclude.element[selectedTransclude.element.length - 1]; + var parentNode = parent && parent[0] || afterNode && afterNode.parentNode; + var afterNextSibling = (afterNode && afterNode.nextSibling) || null; + angular.forEach(clone, function (node) + { + parentNode.insertBefore(node, afterNextSibling); + }); + + }); + }); + } + break; + case 'boSwitchWhen': + var ctrl = binder.controller[0]; + ctrl.cases['!' + binder.attrs.boSwitchWhen] = (ctrl.cases['!' + binder.attrs.boSwitchWhen] || []); + ctrl.cases['!' + binder.attrs.boSwitchWhen].push({ transclude: binder.transclude, element: binder.element }); + break; + case 'boSwitchDefault': + var ctrl = binder.controller[0]; + ctrl.cases['?'] = (ctrl.cases['?'] || []); + ctrl.cases['?'].push({ transclude: binder.transclude, element: binder.element }); + break; case 'hide': case 'show': showHideBinder(binder.element, binder.attr, value); @@ -195,7 +227,6 @@ angular.forEach( [ { directiveName: 'boShow', attribute: 'show' }, - { directiveName: 'boIf', attribute: 'if', transclude: 'element', terminal: true, priority: 1000 }, { directiveName: 'boHide', attribute: 'hide' }, { directiveName: 'boClass', attribute: 'class' }, { directiveName: 'boText', attribute: 'text' }, @@ -209,23 +240,30 @@ { directiveName: 'boId', attribute: 'id' }, { directiveName: 'boStyle', attribute: 'style' }, { directiveName: 'boValue', attribute: 'value' }, - { directiveName: 'boAttr', attribute: 'attr' } + { directiveName: 'boAttr', attribute: 'attr' }, + + { directiveName: 'boIf', transclude: 'element', terminal: true, priority: 1000 }, + { directiveName: 'boSwitch', require: 'boSwitch', controller: function () { this.cases = {}; } }, + { directiveName: 'boSwitchWhen', transclude: 'element', priority: 800, require: '^boSwitch', }, + { directiveName: 'boSwitchDefault', transclude: 'element', priority: 800, require: '^boSwitch', }, ], function (boDirective) { var childPriority = 200; - return angular.module('pasvaz.bindonce').directive(boDirective.directiveName, function () + return bindonceModule.directive(boDirective.directiveName, function () { var bindonceDirective = { priority: boDirective.priority || childPriority, transclude: boDirective.transclude || false, terminal: boDirective.terminal || false, - require: '^bindonce', + require: ['^bindonce'].concat(boDirective.require || []), + controller: boDirective.controller, compile: function (tElement, tAttrs, transclude) { - return function (scope, elm, attrs, bindonceController) + return function (scope, elm, attrs, controllers) { + var bindonceController = controllers[0]; var name = attrs.boParent; if (name && bindonceController.group !== name) { @@ -252,12 +290,13 @@ bindonceController.addBinder( { element: elm, - attr: boDirective.attribute, + attr: boDirective.attribute || boDirective.directiveName, attrs: attrs, value: attrs[boDirective.directiveName], interpolate: boDirective.interpolate, group: name, transclude: transclude, + controller: controllers.slice(1), scope: scope }); }; @@ -266,5 +305,5 @@ return bindonceDirective; }); - }); + }) })(); diff --git a/bindonce.min.js b/bindonce.min.js index fdb837e..2c26c0c 100644 --- a/bindonce.min.js +++ b/bindonce.min.js @@ -1 +1 @@ -(function(){"use strict";angular.module("pasvaz.bindonce",[]).directive("bindonce",function(){var toBoolean=function(value){if(value&&value.length!==0){var v=angular.lowercase(""+value);value=!(v==="f"||v==="0"||v==="false"||v==="no"||v==="n"||v==="[]")}else{value=false}return value};var msie=parseInt((/msie (\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10);if(isNaN(msie)){msie=parseInt((/trident\/.*; rv:(\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10)}var bindonceDirective={restrict:"AM",controller:["$scope","$element","$attrs","$interpolate",function($scope,$element,$attrs,$interpolate){var showHideBinder=function(elm,attr,value){var show=attr==="show"?"":"none";var hide=attr==="hide"?"":"none";elm.css("display",toBoolean(value)?show:hide)};var classBinder=function(elm,value){if(angular.isObject(value)&&!angular.isArray(value)){var results=[];angular.forEach(value,function(value,index){if(value)results.push(index)});value=results}if(value){elm.addClass(angular.isArray(value)?value.join(" "):value)}};var ctrl={watcherRemover:undefined,binders:[],group:$attrs.boName,element:$element,ran:false,addBinder:function(binder){this.binders.push(binder);if(this.ran){this.runBinders()}},setupWatcher:function(bindonceValue){var that=this;this.watcherRemover=$scope.$watch(bindonceValue,function(newValue){if(newValue===undefined)return;that.removeWatcher();that.runBinders()},true)},removeWatcher:function(){if(this.watcherRemover!==undefined){this.watcherRemover();this.watcherRemover=undefined}},runBinders:function(){while(this.binders.length>0){var binder=this.binders.shift();if(this.group&&this.group!=binder.group)continue;var value=binder.scope.$eval(binder.interpolate?$interpolate(binder.value):binder.value);switch(binder.attr){case"if":if(toBoolean(value)){binder.transclude(binder.scope.$new(),function(clone){var parent=binder.element.parent();var afterNode=binder.element&&binder.element[binder.element.length-1];var parentNode=parent&&parent[0]||afterNode&&afterNode.parentNode;var afterNextSibling=afterNode&&afterNode.nextSibling||null;angular.forEach(clone,function(node){parentNode.insertBefore(node,afterNextSibling)})})}break;case"hide":case"show":showHideBinder(binder.element,binder.attr,value);break;case"class":classBinder(binder.element,value);break;case"text":binder.element.text(value);break;case"html":binder.element.html(value);break;case"style":binder.element.css(value);break;case"src":binder.element.attr(binder.attr,value);if(msie)binder.element.prop("src",value);break;case"attr":angular.forEach(binder.attrs,function(attrValue,attrKey){var newAttr,newValue;if(attrKey.match(/^boAttr./)&&binder.attrs[attrKey]){newAttr=attrKey.replace(/^boAttr/,"").replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();newValue=binder.scope.$eval(binder.attrs[attrKey]);binder.element.attr(newAttr,newValue)}});break;case"href":case"alt":case"title":case"id":case"value":binder.element.attr(binder.attr,value);break}}this.ran=true}};return ctrl}],link:function(scope,elm,attrs,bindonceController){var value=attrs.bindonce?scope.$eval(attrs.bindonce):true;if(value!==undefined){bindonceController.runBinders()}else{bindonceController.setupWatcher(attrs.bindonce);elm.bind("$destroy",bindonceController.removeWatcher)}}};return bindonceDirective});angular.forEach([{directiveName:"boShow",attribute:"show"},{directiveName:"boIf",attribute:"if",transclude:"element",terminal:true,priority:1e3},{directiveName:"boHide",attribute:"hide"},{directiveName:"boClass",attribute:"class"},{directiveName:"boText",attribute:"text"},{directiveName:"boHtml",attribute:"html"},{directiveName:"boSrcI",attribute:"src",interpolate:true},{directiveName:"boSrc",attribute:"src"},{directiveName:"boHrefI",attribute:"href",interpolate:true},{directiveName:"boHref",attribute:"href"},{directiveName:"boAlt",attribute:"alt"},{directiveName:"boTitle",attribute:"title"},{directiveName:"boId",attribute:"id"},{directiveName:"boStyle",attribute:"style"},{directiveName:"boValue",attribute:"value"},{directiveName:"boAttr",attribute:"attr"}],function(boDirective){var childPriority=200;return angular.module("pasvaz.bindonce").directive(boDirective.directiveName,function(){var bindonceDirective={priority:boDirective.priority||childPriority,transclude:boDirective.transclude||false,terminal:boDirective.terminal||false,require:"^bindonce",compile:function(tElement,tAttrs,transclude){return function(scope,elm,attrs,bindonceController){var name=attrs.boParent;if(name&&bindonceController.group!==name){var element=bindonceController.element.parent();bindonceController=undefined;var parentValue;while(element[0].nodeType!==9&&element.length){if((parentValue=element.data("$bindonceController"))&&parentValue.group===name){bindonceController=parentValue;break}element=element.parent()}if(!bindonceController){throw new Error("No bindonce controller: "+name)}}bindonceController.addBinder({element:elm,attr:boDirective.attribute,attrs:attrs,value:attrs[boDirective.directiveName],interpolate:boDirective.interpolate,group:name,transclude:transclude,scope:scope})}}};return bindonceDirective})})})(); \ No newline at end of file +(function(){"use strict";var bindonceModule=angular.module("pasvaz.bindonce",[]);bindonceModule.directive("bindonce",function(){var toBoolean=function(value){if(value&&value.length!==0){var v=angular.lowercase(""+value);value=!(v==="f"||v==="0"||v==="false"||v==="no"||v==="n"||v==="[]")}else{value=false}return value};var msie=parseInt((/msie (\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10);if(isNaN(msie)){msie=parseInt((/trident\/.*; rv:(\d+)/.exec(angular.lowercase(navigator.userAgent))||[])[1],10)}var bindonceDirective={restrict:"AM",controller:["$scope","$element","$attrs","$interpolate",function($scope,$element,$attrs,$interpolate){var showHideBinder=function(elm,attr,value){var show=attr==="show"?"":"none";var hide=attr==="hide"?"":"none";elm.css("display",toBoolean(value)?show:hide)};var classBinder=function(elm,value){if(angular.isObject(value)&&!angular.isArray(value)){var results=[];angular.forEach(value,function(value,index){if(value)results.push(index)});value=results}if(value){elm.addClass(angular.isArray(value)?value.join(" "):value)}};var ctrl={watcherRemover:undefined,binders:[],group:$attrs.boName,element:$element,ran:false,addBinder:function(binder){this.binders.push(binder);if(this.ran){this.runBinders()}},setupWatcher:function(bindonceValue){var that=this;this.watcherRemover=$scope.$watch(bindonceValue,function(newValue){if(newValue===undefined)return;that.removeWatcher();that.runBinders()},true)},removeWatcher:function(){if(this.watcherRemover!==undefined){this.watcherRemover();this.watcherRemover=undefined}},runBinders:function(){while(this.binders.length>0){var binder=this.binders.shift();if(this.group&&this.group!=binder.group)continue;var value=binder.scope.$eval(binder.interpolate?$interpolate(binder.value):binder.value);switch(binder.attr){case"boIf":if(toBoolean(value)){binder.transclude(binder.scope.$new(),function(clone){var parent=binder.element.parent();var afterNode=binder.element&&binder.element[binder.element.length-1];var parentNode=parent&&parent[0]||afterNode&&afterNode.parentNode;var afterNextSibling=afterNode&&afterNode.nextSibling||null;angular.forEach(clone,function(node){parentNode.insertBefore(node,afterNextSibling)})})}break;case"boSwitch":var selectedTranscludes,switchCtrl=binder.controller[0];if(selectedTranscludes=switchCtrl.cases["!"+value]||switchCtrl.cases["?"]){binder.scope.$eval(binder.attrs.change);angular.forEach(selectedTranscludes,function(selectedTransclude){selectedTransclude.transclude(binder.scope.$new(),function(clone){var parent=selectedTransclude.element.parent();var afterNode=selectedTransclude.element&&selectedTransclude.element[selectedTransclude.element.length-1];var parentNode=parent&&parent[0]||afterNode&&afterNode.parentNode;var afterNextSibling=afterNode&&afterNode.nextSibling||null;angular.forEach(clone,function(node){parentNode.insertBefore(node,afterNextSibling)})})})}break;case"boSwitchWhen":var ctrl=binder.controller[0];ctrl.cases["!"+binder.attrs.boSwitchWhen]=ctrl.cases["!"+binder.attrs.boSwitchWhen]||[];ctrl.cases["!"+binder.attrs.boSwitchWhen].push({transclude:binder.transclude,element:binder.element});break;case"boSwitchDefault":var ctrl=binder.controller[0];ctrl.cases["?"]=ctrl.cases["?"]||[];ctrl.cases["?"].push({transclude:binder.transclude,element:binder.element});break;case"hide":case"show":showHideBinder(binder.element,binder.attr,value);break;case"class":classBinder(binder.element,value);break;case"text":binder.element.text(value);break;case"html":binder.element.html(value);break;case"style":binder.element.css(value);break;case"src":binder.element.attr(binder.attr,value);if(msie)binder.element.prop("src",value);break;case"attr":angular.forEach(binder.attrs,function(attrValue,attrKey){var newAttr,newValue;if(attrKey.match(/^boAttr./)&&binder.attrs[attrKey]){newAttr=attrKey.replace(/^boAttr/,"").replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();newValue=binder.scope.$eval(binder.attrs[attrKey]);binder.element.attr(newAttr,newValue)}});break;case"href":case"alt":case"title":case"id":case"value":binder.element.attr(binder.attr,value);break}}this.ran=true}};return ctrl}],link:function(scope,elm,attrs,bindonceController){var value=attrs.bindonce?scope.$eval(attrs.bindonce):true;if(value!==undefined){bindonceController.runBinders()}else{bindonceController.setupWatcher(attrs.bindonce);elm.bind("$destroy",bindonceController.removeWatcher)}}};return bindonceDirective});angular.forEach([{directiveName:"boShow",attribute:"show"},{directiveName:"boHide",attribute:"hide"},{directiveName:"boClass",attribute:"class"},{directiveName:"boText",attribute:"text"},{directiveName:"boHtml",attribute:"html"},{directiveName:"boSrcI",attribute:"src",interpolate:true},{directiveName:"boSrc",attribute:"src"},{directiveName:"boHrefI",attribute:"href",interpolate:true},{directiveName:"boHref",attribute:"href"},{directiveName:"boAlt",attribute:"alt"},{directiveName:"boTitle",attribute:"title"},{directiveName:"boId",attribute:"id"},{directiveName:"boStyle",attribute:"style"},{directiveName:"boValue",attribute:"value"},{directiveName:"boAttr",attribute:"attr"},{directiveName:"boIf",transclude:"element",terminal:true,priority:1e3},{directiveName:"boSwitch",require:"boSwitch",controller:function(){this.cases={}}},{directiveName:"boSwitchWhen",transclude:"element",priority:800,require:"^boSwitch"},{directiveName:"boSwitchDefault",transclude:"element",priority:800,require:"^boSwitch"}],function(boDirective){var childPriority=200;return bindonceModule.directive(boDirective.directiveName,function(){var bindonceDirective={priority:boDirective.priority||childPriority,transclude:boDirective.transclude||false,terminal:boDirective.terminal||false,require:["^bindonce"].concat(boDirective.require||[]),controller:boDirective.controller,compile:function(tElement,tAttrs,transclude){return function(scope,elm,attrs,controllers){var bindonceController=controllers[0];var name=attrs.boParent;if(name&&bindonceController.group!==name){var element=bindonceController.element.parent();bindonceController=undefined;var parentValue;while(element[0].nodeType!==9&&element.length){if((parentValue=element.data("$bindonceController"))&&parentValue.group===name){bindonceController=parentValue;break}element=element.parent()}if(!bindonceController){throw new Error("No bindonce controller: "+name)}}bindonceController.addBinder({element:elm,attr:boDirective.attribute||boDirective.directiveName,attrs:attrs,value:attrs[boDirective.directiveName],interpolate:boDirective.interpolate,group:name,transclude:transclude,controller:controllers.slice(1),scope:scope})}}};return bindonceDirective})})})(); \ No newline at end of file