├── .bowerrc ├── .gitignore ├── .travis.yml ├── Changelog.md ├── Contributors.md ├── Gruntfile.js ├── LICENSE.md ├── README.md ├── bower.json ├── dist ├── .gitkeep ├── angular-semantic-ui.js └── angular-semantic-ui.min.js ├── karma.conf.js ├── package.json └── src ├── accordion ├── README.md ├── accordion.js ├── docs │ ├── .gitkeep │ ├── controllers.js │ └── demo.html └── test │ ├── .gitkeep │ └── accordion.spec.js ├── angularify.semantic.js ├── checkbox ├── README.md ├── checkbox.js ├── docs │ ├── controllers.js │ └── demo.html └── test │ ├── .gitkeep │ └── checkbox.spec.js ├── dimmer ├── README.md ├── dimmer.js ├── docs │ ├── controllers.js │ └── demo.html └── test │ └── .gitkeep ├── dropdown ├── README.md ├── docs │ ├── controllers.js │ └── demo.html ├── dropdown.js └── test │ └── dropdown.spec.js ├── modal ├── README.md ├── docs │ ├── controllers.js │ └── demo.html ├── modal.js └── test │ └── modal.spec.js ├── popup ├── README.md ├── docs │ ├── controllers.js │ └── demo.html ├── popup.js └── test │ └── popup.spec.js ├── rating ├── README.md ├── docs │ ├── controllers.js │ └── demo.html ├── rating.js └── test │ └── rating.spec.js ├── sidebar ├── README.md ├── docs │ ├── controllers.js │ └── demo.html ├── sidebar.js └── test │ └── sidebar.spec.js └── wizard ├── README.md ├── doc ├── controllers.js └── demo.html ├── test └── wizard.spec.js └── wizard.js /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "bower_components" 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .dev/ 2 | .tmp/ 3 | .DS_Store 4 | *.sublime-project 5 | *.sublime-workspace 6 | bower_components/ 7 | node_modules/ 8 | /pages/ 9 | /docs/ 10 | /test/coverage/ 11 | !.gitignore 12 | css/ 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.8" 4 | 5 | before_script: 6 | - npm install --quiet -g grunt-cli karma 7 | - npm install 8 | 9 | script: grunt test && grunt build 10 | -------------------------------------------------------------------------------- /Changelog.md: -------------------------------------------------------------------------------- 1 | 0.0.3 [Released] 2 | ============================= 3 | 4 | * Animated modal 5 | * Destroy listener was being called to destroy an accordion in the dropdown module 6 | * Corrected spelling in accordion README.md 7 | * Use semantic ui classes instead of inline style in the sidebar module 8 | 9 | 10 | 0.0.2 [Released] 11 | ============================= 12 | 13 | * Added wizard directive 14 | * Fixes to dropdown to update model, and allow for {{variables}} as title 15 | * Code clean up and grunt task optimization 16 | * Fixed scope issue with accordion 17 | * Updated modal to use ng-class 18 | * Updated accordion to use ng-class 19 | * Updated sidebar to use semantic-ui javascript functions 20 | * Updated README.md 21 | * Corrected spelling in rating module 22 | * Corrected opening problem for the dropdown 23 | 24 | 25 | 0.0.1 [Released] 26 | ============================= 27 | 28 | * Initial release; 29 | * Added `grunt build` task; 30 | * Added `grunt test` task; 31 | * Added `karma` for testing; 32 | * `accordion` - initial release; 33 | * `checkbox` - initial release; 34 | * `dimmer` - initial release; 35 | * `dropdown` - initial release; 36 | * `modal` - initial release; 37 | * `popup` - initial release; 38 | * `rating` - initial release; 39 | * `sidebar` - initial release. -------------------------------------------------------------------------------- /Contributors.md: -------------------------------------------------------------------------------- 1 | Author: 2 | 3 | * [0xAX](https://twitter.com/0xAX) 4 | 5 | Maintainer: 6 | * [jspdown](https://github.com/jspdown) 7 | 8 | Contributors: 9 | 10 | * [Nikita K.](https://github.com/Mendor) 11 | * [StudioThree10](https://github.com/studiothree10) 12 | * [cgroner](https://github.com/cgroner) 13 | * [solcates](https://github.com/solcates) 14 | * [xblaster](https://github.com/xblaster) 15 | * [frankt117](https://github.com/frankt117) 16 | * [tombee](https://github.com/tombee) 17 | * [dszczyt](https://github.com/dszczyt) 18 | * [RomainLanz](https://github.com/RomainLanz) 19 | * [KapuzenSohn](https://github.com/KapuzenSohn) 20 | * [Kurmaev](https://github.com/Kurmaev) 21 | * [rex](https://github.com/rex) 22 | * [kevspadilla](https://github.com/kevspadilla) 23 | * [Virviil](https://github.com/Virviil) 24 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | module.exports = function(grunt) { 3 | 4 | grunt.loadNpmTasks('grunt-contrib-watch'); 5 | grunt.loadNpmTasks('grunt-contrib-concat'); 6 | grunt.loadNpmTasks('grunt-contrib-copy'); 7 | grunt.loadNpmTasks('grunt-contrib-jshint'); 8 | grunt.loadNpmTasks('grunt-contrib-uglify'); 9 | grunt.loadNpmTasks('grunt-html2js'); 10 | grunt.loadNpmTasks('grunt-karma'); 11 | grunt.loadNpmTasks('grunt-conventional-changelog'); 12 | grunt.loadNpmTasks('grunt-ngdocs'); 13 | 14 | grunt.initConfig({ 15 | dist: 'dist', 16 | filename: 'angular-semantic-ui', 17 | pkg: grunt.file.readJSON('package.json'), 18 | concat: { 19 | js: { 20 | src: ['src/angularify.semantic.js', 21 | 'src/accordion/accordion.js', 22 | 'src/checkbox/checkbox.js', 23 | 'src/dimmer/dimmer.js', 24 | 'src/dropdown/dropdown.js', 25 | 'src/modal/modal.js', 26 | 'src/popup/popup.js', 27 | 'src/sidebar/sidebar.js', 28 | 'src/rating/rating.js', 29 | 'src/wizard/wizard.js', 30 | ], 31 | dest: '<%= dist %>/<%= filename %>.js' 32 | } 33 | }, 34 | uglify: { 35 | dist: { 36 | src: ['<%= dist %>/<%= filename %>.js'], 37 | dest: '<%= dist %>/<%= filename %>.min.js' 38 | } 39 | }, 40 | karma: { 41 | options: { 42 | configFile: 'karma.conf.js' 43 | }, 44 | watch: { 45 | background: true 46 | }, 47 | continuous: { 48 | singleRun: true 49 | }, 50 | }, 51 | watch: { 52 | javascript: { 53 | files: ['src/**/*.js'], 54 | tasks: ['concat:js', 'uglify'] 55 | } 56 | 57 | } 58 | }); 59 | 60 | grunt.registerTask('build', ['concat:js', 'uglify']); 61 | grunt.registerTask('test', ['karma']); 62 | grunt.registerTask('default', ['concat:js', 'uglify', 'watch:javascript']); 63 | }; 64 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2014 0xAX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | angular-semantic-ui 2 | ====================== 3 | 4 | `angular-semantic-ui` - is a set of `angular.js` directives for [semantic-ui](http://semantic-ui.com/). 5 | 6 | Directives 7 | ---------------------- 8 | 9 | * [accordion](https://github.com/angularify/angular-semantic-ui/tree/master/src/accordion) 10 | * [checkbox](https://github.com/angularify/angular-semantic-ui/tree/master/src/checkbox) 11 | * [dimmer](https://github.com/angularify/angular-semantic-ui/tree/master/src/dimmer) 12 | * [dropdown](https://github.com/angularify/angular-semantic-ui/tree/master/src/dropdown) 13 | * [modal](https://github.com/angularify/angular-semantic-ui/tree/master/src/modal) 14 | * [popup](https://github.com/angularify/angular-semantic-ui/tree/master/src/popup) 15 | * [rating](https://github.com/angularify/angular-semantic-ui/tree/master/src/rating) 16 | * [sidebar](https://github.com/angularify/angular-semantic-ui/tree/master/src/sidebar) 17 | * [wizard](https://github.com/angularify/angular-semantic-ui/tree/master/src/wizard) 18 | 19 | **IMPORTANT** angular-semantic-ui is only 0.0.2, and **NOT PRODUCTION READY**. 20 | 21 | Installation 22 | ---------------------- 23 | 24 | ``` 25 | $ bower install angular-semantic-ui 26 | ``` 27 | 28 | 29 | Building 30 | ---------------------- 31 | 32 | Get main [repo](https://github.com/angularify/angular-semantic-ui) with: 33 | 34 | ``` 35 | $ git clone https://github.com/angularify/angular-semantic-ui.git 36 | ``` 37 | 38 | Than go to the `angular-semantic-ui` directory and install dependencies: 39 | 40 | ``` 41 | $ npm install && bower install 42 | ``` 43 | 44 | Then execute: 45 | 46 | ``` 47 | $ grunt build && grunt test 48 | ``` 49 | 50 | There will be: `dist/angular-semantic-ui.js`. 51 | 52 | Contribution 53 | ---------------------- 54 | 55 | 1. Fork main [repo](https://github.com/angularify/angular-semantic-ui) 56 | 2. Make changes. 57 | 3. Add tests. 58 | 4. Send pull request. 59 | 5. Thank you. 60 | 61 | Author 62 | ---------------------- 63 | 64 | [@0xAX](https://twitter.com/0xAX) 65 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-semantic-ui", 3 | "description": "Angular - AngularJS directives for Semantic UI.", 4 | "version": "0.0.3", 5 | "keywords": [ 6 | "angular", 7 | "ui" 8 | ], 9 | "homepage": "http://solcates.github.io/angular-semantic-ui", 10 | "bugs": "https://github.com/solcates/angular-semantic-ui", 11 | "author": { 12 | "name": "Alex Kuleshov", 13 | "url": "https://github.com/0xAX" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/solcates/angular-semantic-ui.git" 18 | }, 19 | "licenses": [ 20 | { 21 | "type": "MIT", 22 | "url": "https://github.com/solcates/angular-semantic-ui/blob/master/LICENSE.md" 23 | } 24 | ], 25 | "main": [ 26 | "dist/angular-semantic-ui.js" 27 | ], 28 | "ignore": [ 29 | "docs", 30 | "test", 31 | "CONTRIBUTING.md" 32 | ], 33 | "dependencies": { 34 | "angular": "latest", 35 | "semantic": "latest" 36 | }, 37 | "devDependencies": { 38 | "angular-mocks" : "latest" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /dist/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularify/angular-semantic-ui/6ac38e0bc5c91b084fae8defecb9e3e9ed74c3a8/dist/.gitkeep -------------------------------------------------------------------------------- /dist/angular-semantic-ui.js: -------------------------------------------------------------------------------- 1 | angular.module('angularify.semantic', ['angularify.semantic.accordion', 2 | 'angularify.semantic.checkbox', 3 | 'angularify.semantic.dimmer', 4 | 'angularify.semantic.dropdown', 5 | 'angularify.semantic.modal', 6 | 'angularify.semantic.popup', 7 | 'angularify.semantic.rating', 8 | 'angularify.semantic.sidebar', 9 | 'angularify.semantic.wizard']); 10 | 11 | 'use strict'; 12 | 13 | angular.module('angularify.semantic.accordion', []) 14 | 15 | .controller('AccordionController', ['$scope', function($scope){ 16 | $scope.accordions = []; 17 | 18 | this.add_accordion = function(scope) { 19 | $scope.accordions.push(scope); 20 | 21 | var _this = this; 22 | scope.$on('$destroy', function (event) { 23 | _this.remove_accordion(scope); 24 | }); 25 | 26 | return $scope.accordions; 27 | } 28 | 29 | this.closeAll = function(scope) { 30 | var i = 0; 31 | var isCloseAll = false; 32 | 33 | var index = $scope.accordions.indexOf(scope); 34 | 35 | for (i in $scope.accordions){ 36 | if ($scope.accordions[i].close) 37 | isCloseAll = true; 38 | } 39 | 40 | if (isCloseAll == true){ 41 | for (i in $scope.accordions){ 42 | if (i !== index) { 43 | $scope.accordions[i].active = false; 44 | } 45 | } 46 | 47 | return true; 48 | } 49 | 50 | return false; 51 | 52 | } 53 | 54 | this.remove_accordion = function(scope) { 55 | var index = $scope.accordions.indexOf(scope); 56 | if ( index !== -1 ) { 57 | $scope.accordions.splice(index, 1); 58 | } 59 | } 60 | 61 | this.is_close_all = function() { 62 | var i = 0; 63 | 64 | for (i in $scope.accordions){ 65 | if ($scope.accordions[i].close == 'true') 66 | return true; 67 | } 68 | return false; 69 | } 70 | }]) 71 | 72 | .directive('accordion', function () { 73 | return { 74 | restrict: 'E', 75 | replace: true, 76 | transclude: true, 77 | controller: 'AccordionController', 78 | scope: { 79 | 'close': '@' 80 | }, 81 | template: "
", 82 | link: function(scope, element, attrs, AccordionController) { 83 | 84 | if(typeof attrs.styled !== 'undefined') { 85 | element.addClass('styled'); 86 | } 87 | 88 | AccordionController.add_accordion(scope); 89 | } 90 | } 91 | }) 92 | 93 | .directive('accordionGroup', function() { 94 | return { 95 | restrict: 'E', 96 | replace: true, 97 | transclude: true, 98 | scope : { 99 | title: '@', 100 | open: '@' 101 | }, 102 | require:'^accordion', 103 | template: "
\ 104 |
\ 105 | \ 106 | {{ title }} \ 107 |
\ 108 |
\ 109 |
\ 110 |
", 111 | 112 | link: function(scope, element, attrs, AccordionController) { 113 | 114 | // set up active 115 | scope.active = attrs.open === 'true'; 116 | 117 | // Add the accordion to the controller 118 | AccordionController.add_accordion(scope); 119 | 120 | // Click handler 121 | scope.click_on_accordion_tab = function(){ 122 | 123 | // class all first of all 124 | AccordionController.closeAll(scope); 125 | 126 | // Swap the active state 127 | scope.active = !scope.active; 128 | 129 | // Add animation to the accordion group content 130 | element.children().last().slideToggle(); 131 | }; 132 | } 133 | }; 134 | }); 135 | 'use strict'; 136 | 137 | angular.module('angularify.semantic.checkbox', []) 138 | .directive('checkbox', function() { 139 | return { 140 | restrict: 'E', 141 | replace: true, 142 | transclude: true, 143 | scope: { 144 | checked: '&?', 145 | disabled: '&?', 146 | ngModel: '=ngModel' 147 | }, 148 | controller: function() { 149 | var vm = this; 150 | 151 | // TODO: assert this is usefull ? 152 | // if(angular.isUndefined(vm.ngModel)) { vm.ngModel = !!vm.ngModel; } 153 | 154 | if(angular.isFunction(vm.checked)) { vm.ngModel = !!vm.checked(); } 155 | 156 | vm.toggle = function() { 157 | if(angular.isFunction(vm.disabled) && vm.disabled()) return; 158 | vm.ngModel = !vm.ngModel; 159 | } 160 | }, 161 | controllerAs: 'vm', 162 | bindToController: true, 163 | require: 'ngModel', 164 | template: '
' + 165 | '' + 166 | '' + 167 | '
', 168 | link: function() { } 169 | }; 170 | }); 171 | 172 | 'use strict'; 173 | 174 | angular.module('angularify.semantic.dimmer', []) 175 | 176 | .directive("pageDimmer", function () { 177 | return { 178 | restrict: 'E', 179 | replace: true, 180 | transclude: true, 181 | scope : { 182 | show : "=?", 183 | model: '=ngModel' 184 | }, 185 | template: "
" + 186 | "
" + 187 | "
" + 188 | "
" + 189 | "
", 190 | link : function(scope, element, attrs, ngModel) { 191 | 192 | if (scope.show == true) { 193 | scope.dimmer_class = 'ui page active dimmer'; 194 | } 195 | else { 196 | scope.show = false; 197 | scope.dimmer_class = 'ui page disable dimmer'; 198 | } 199 | 200 | // 201 | // Click on dimmer handler 202 | // 203 | scope.click_on_dimmer = function(){ 204 | scope.model = false; 205 | scope.dimmer_class = 'ui page dimmer'; 206 | } 207 | 208 | // 209 | // Watch for the ng-model changing 210 | // 211 | scope.$watch('model', function(val){ 212 | if (val == false || val == undefined) 213 | return; 214 | else 215 | scope.dimmer_class = 'ui page active dimmer'; 216 | }); 217 | } 218 | }; 219 | }); 220 | 221 | 'use strict'; 222 | 223 | angular.module('angularify.semantic.dropdown', []) 224 | .controller('DropDownController', ['$scope', 225 | function($scope) { 226 | $scope.options = []; 227 | 228 | this.add_option = function(title, value){ 229 | $scope.options.push({'title': title, 'value': value}); 230 | if (value == $scope.model){ 231 | this.update_title(value) 232 | }; 233 | }; 234 | 235 | this.remove_option = function(title, value){ 236 | for (var index in $scope.options) 237 | if ($scope.options[index].value == value && 238 | $scope.options[index].title == title){ 239 | 240 | $scope.options.splice(index, 1); 241 | // Remove only one item 242 | break; 243 | }; 244 | }; 245 | 246 | this.update_model = function (title, value) { 247 | if ($scope.model !== value) 248 | $scope.model = value; 249 | }; 250 | 251 | this.update_title = function (value) { 252 | var changed = false; 253 | 254 | for (var index in $scope.options) 255 | if ($scope.options[index].value == value){ 256 | $scope.title = $scope.options[index].title; 257 | changed = true; 258 | } 259 | 260 | if (changed){ 261 | $scope.text_class = 'text'; 262 | } else{ 263 | $scope.title = $scope.original_title; 264 | $scope.text_class = 'default text'; 265 | } 266 | }; 267 | 268 | } 269 | ]) 270 | 271 | .directive('dropdown', function() { 272 | return { 273 | restrict: 'E', 274 | replace: true, 275 | transclude: true, 276 | controller: 'DropDownController', 277 | scope: { 278 | title: '@', 279 | open: '@', 280 | model: '=ngModel' 281 | }, 282 | template: '', 288 | link: function(scope, element, attrs, DropDownController) { 289 | scope.dropdown_class = 'ui selection dropdown'; 290 | scope.menu_class = 'menu transition hidden'; 291 | scope.text_class = 'default text'; 292 | scope.original_title = scope.title; 293 | 294 | if (scope.open === 'true') { 295 | scope.is_open = true; 296 | scope.dropdown_class = scope.dropdown_class + ' active visible'; 297 | scope.menu_class = scope.menu_class + ' visible'; 298 | } else { 299 | scope.is_open = false; 300 | } 301 | 302 | /* 303 | * Watch for ng-model changing 304 | */ 305 | scope.element = element; 306 | scope.$watch('model', function (value) { 307 | // update title or reset the original title if its empty 308 | DropDownController.update_title(value); 309 | }); 310 | 311 | /* 312 | * Click handler 313 | */ 314 | element.bind('click', function() { 315 | if (scope.is_open === false) { 316 | scope.$apply(function() { 317 | scope.dropdown_class = 'ui selection dropdown active visible'; 318 | scope.menu_class = 'menu transition visible'; 319 | }); 320 | } else { 321 | scope.$apply(function() { 322 | scope.dropdown_class = 'ui selection dropdown'; 323 | scope.menu_class = 'menu transition hidden'; 324 | }); 325 | } 326 | scope.is_open = !scope.is_open; 327 | }); 328 | } 329 | }; 330 | }) 331 | 332 | .directive('dropdownGroup', function() { 333 | return { 334 | restrict: 'AE', 335 | replace: true, 336 | transclude: true, 337 | require: '^dropdown', 338 | scope: { 339 | title: '=title', 340 | value: '=value' 341 | }, 342 | template: '
{{ item_title }}
', 343 | link: function(scope, element, attrs, DropDownController) { 344 | 345 | // Check if title= was set... if not take the contents of the dropdown-group tag 346 | // title= is for dynamic variables from something like ng-repeat {{variable}} 347 | if (scope.title === undefined) { 348 | scope.item_title = attrs.title || element.children()[0].innerHTML; 349 | } else { 350 | scope.item_title = scope.title; 351 | } 352 | if (scope.value === undefined) { 353 | scope.item_value = attrs.value || scope.item_title; 354 | } else { 355 | scope.item_value = scope.value; 356 | } 357 | 358 | // Keep this option 359 | DropDownController.add_option(scope.item_title, scope.item_value); 360 | 361 | // 362 | // Menu item click handler 363 | // 364 | element.bind('click', function() { 365 | DropDownController.update_model(scope.item_title, scope.item_value); 366 | }); 367 | 368 | scope.$on('$destroy', function(){ 369 | DropDownController.remove_option(scope.item_title, scope.item_value); 370 | }); 371 | 372 | } 373 | }; 374 | }); 375 | 'use strict'; 376 | 377 | angular.module('angularify.semantic.modal', []) 378 | 379 | .directive('modal', function () { 380 | return { 381 | restrict: 'E', 382 | replace: true, 383 | transclude: true, 384 | require: 'ngModel', 385 | template: '', 386 | link: function (scope, element, attrs, ngModel) { 387 | element.modal({ 388 | onHide: function () { 389 | ngModel.$setViewValue(false); 390 | } 391 | }); 392 | scope.$watch(function () { 393 | return ngModel.$modelValue; 394 | }, function (modelValue){ 395 | element.modal(modelValue ? 'show' : 'hide'); 396 | }); 397 | } 398 | } 399 | }); 400 | 401 | 'use strict'; 402 | 403 | angular.module('angularify.semantic.popup', []) 404 | 405 | .directive('popup', function ($document) { 406 | return { 407 | restrict: "A", 408 | scope : { 409 | popup : "@" 410 | }, 411 | link: function(scope, element, attrs) { 412 | var class_name = ''; 413 | // convert to json 414 | var popup_meta_data = eval('(' + scope.popup + ')'); 415 | 416 | var title = popup_meta_data['title']; 417 | if (title == undefined) 418 | title = ''; 419 | 420 | var content = popup_meta_data['content']; 421 | if (content == undefined) 422 | content = ''; 423 | 424 | var position = popup_meta_data['position']; 425 | if (position == undefined) 426 | position = 'top'; 427 | 428 | var size = popup_meta_data['size']; 429 | if (size == undefined) 430 | size = 'small'; 431 | 432 | if (position == 'left') { 433 | class_name = 'ui popup left center transition visible ' + size; 434 | } else if (position == 'right') { 435 | class_name = 'ui popup right center transition visible ' + size; 436 | } else if (position == 'bottom') { 437 | class_name = 'ui popup bottom center transition visible ' + size; 438 | } else { 439 | class_name = 'ui popup top center transition visible ' + size; 440 | } 441 | 442 | // 443 | // Get element X/Y of left corner 444 | // 445 | function getPos(ele){ 446 | var x = 0; 447 | var y = 0; 448 | while(true){ 449 | x += ele.offsetLeft; 450 | y += ele.offsetTop; 451 | if(ele.offsetParent === null) 452 | break; 453 | ele = ele.offsetParent; 454 | } 455 | return [x, y]; 456 | } 457 | 458 | var current_element_position_top_left = getPos(element[0]); 459 | var current_element_height = element[0].offsetHeight; 460 | var current_element_width = element[0].offsetWidth; 461 | 462 | // 463 | // Remove element by class name 464 | // 465 | NodeList.prototype.remove = HTMLCollection.prototype.remove = function() { 466 | for(var i = 0, len = this.length; i < len; i++) { 467 | if(this[i] && this[i].parentElement) { 468 | this[i].parentElement.removeChild(this[i]); 469 | } 470 | } 471 | } 472 | 473 | // 474 | // Handle mouse over 475 | // 476 | element.bind('mouseenter', function(){ 477 | var html = '
' + title +'
' + content + '
'; 478 | 479 | angular.element(element[0]).append(html); 480 | 481 | var popupHeight = document.getElementById('my-popup').clientHeight; 482 | var popupWidth = document.getElementById('my-popup').clientWidth; 483 | 484 | if (position == 'left') { 485 | document.getElementById('my-popup').style.top = current_element_position_top_left[1] + (current_element_height / 2) - (popupHeight / 2) + 'px'; 486 | document.getElementById('my-popup').style.right = 'auto'; 487 | document.getElementById('my-popup').style.left = current_element_position_top_left[0] - popupWidth - 10 + 'px'; 488 | document.getElementById('my-popup').style.bottom = 'auto'; 489 | document.getElementById('my-popup').style.display = 'inline-block'; 490 | } else if (position == 'right') { 491 | document.getElementById('my-popup').style.top = current_element_position_top_left[1] + (current_element_height / 2) - (popupHeight / 2) + 'px'; 492 | document.getElementById('my-popup').style.right = 'auto'; 493 | document.getElementById('my-popup').style.left = current_element_position_top_left[0] + current_element_width + 'px'; 494 | document.getElementById('my-popup').style.bottom = 'auto'; 495 | document.getElementById('my-popup').style.display = 'inline-block'; 496 | } else if (position == 'bottom') { 497 | document.getElementById('my-popup').style.top = current_element_position_top_left[1] + current_element_height + 'px'; 498 | document.getElementById('my-popup').style.left = current_element_position_top_left[0] + (current_element_width / 2) - (popupWidth / 2) + 15 + 'px'; 499 | document.getElementById('my-popup').style.right = 'auto'; 500 | document.getElementById('my-popup').style.bottom = 'auto'; 501 | document.getElementById('my-popup').style.display = 'inline-block'; 502 | } else { 503 | document.getElementById('my-popup').style.top = current_element_position_top_left[1] - popupHeight - 10 + 'px'; 504 | document.getElementById('my-popup').style.left = current_element_position_top_left[0] + (current_element_width / 2) - (popupWidth / 2) + 18 + 'px'; 505 | document.getElementById('my-popup').style.right = 'auto'; 506 | document.getElementById('my-popup').style.bottom = 'auto'; 507 | document.getElementById('my-popup').style.display = 'inline-block'; 508 | } 509 | }); 510 | 511 | // 512 | // Handle mouse leave 513 | // 514 | element.bind('mouseleave', function(){ 515 | document.getElementsByClassName("ui popup bottom center transition visible").remove(); 516 | if (document.getElementById('my-popup') !== null) 517 | document.getElementById('my-popup').remove(); 518 | }); 519 | } 520 | } 521 | }); 522 | 'use strict'; 523 | 524 | angular 525 | .module('angularify.semantic.sidebar', []) 526 | .directive('sidebar', sidebar) 527 | .directive('sidebarLink', sidebarLink) 528 | .directive('sidebarItem', sidebarItem) 529 | .directive('sidebarItemGroup', sidebarItemGroup); 530 | 531 | function sidebar() { 532 | return { 533 | restrict: 'E', 534 | replace: true, 535 | transclude: true, 536 | template: '', 538 | scope: { 539 | buttonClass: '@' 540 | }, 541 | link: function (scope, element, attrs) { 542 | element.sidebar('attach events', scope.buttonClass, 'show'); 543 | } 544 | }; 545 | } 546 | 547 | function sidebarItemGroup() { 548 | return { 549 | restrict: 'E', 550 | replace: true, 551 | transclude: true, 552 | template: '
' + 553 | '
{{ title }}
' + 554 | '' + 555 | '
', 556 | scope: { 557 | title: '@' 558 | } 559 | }; 560 | } 561 | 562 | function sidebarItem() { 563 | return { 564 | restrict: 'E', 565 | replace: true, 566 | transclude: true, 567 | template: '
' 568 | }; 569 | } 570 | 571 | function sidebarLink() { 572 | return { 573 | restrict: 'E', 574 | replace: true, 575 | template: '' + 576 | '' + 577 | '{{ title }}' + 578 | '', 579 | scope: { 580 | title: '@', 581 | icon: '@', 582 | href: '@' 583 | } 584 | }; 585 | } 586 | 'use strict'; 587 | 588 | angular.module('angularify.semantic.rating', []) 589 | 590 | .directive('rating', function(){ 591 | return { 592 | restrict: "E", 593 | replace: true, 594 | transclude: true, 595 | scope: { 596 | id: "@", 597 | size: "@", 598 | type: "@", 599 | model : '=ngModel' 600 | }, 601 | template: '
' + 602 | '' + 603 | '' + 604 | '' + 605 | '' + 606 | '' + 607 | '
', 608 | link: function(scope, element, attrs){ 609 | if (scope.model == undefined) 610 | scope.model = 0; 611 | 612 | if (scope.model < 1 && scope.model > 5) 613 | scope.model = 0; 614 | 615 | // is rating already checked 616 | var checked = false; 617 | 618 | // 619 | // Set up icon type 620 | // 621 | if (scope.type == undefined) 622 | scope.type = 'star'; 623 | 624 | // 625 | // Set up size 626 | // 627 | if (scope.size == undefined) 628 | scope.div_class = 'ui rating ' + scope.type; 629 | else if (scope.size == 'small') 630 | scope.div_class = 'ui small ' + scope.type + ' rating'; 631 | else if (scope.size == 'large') 632 | scope.div_class = 'ui large ' + scope.type + ' rating'; 633 | else if (scope.size == 'huge') 634 | scope.div_class = 'ui huge ' + scope.type + ' rating'; 635 | 636 | // 637 | // set up icon class 638 | // 639 | scope.icon_class = 'icon'; 640 | 641 | // 642 | // Handle mouse enter 643 | // 644 | scope.mouse_enter = function(icon_index){ 645 | if (checked == true) 646 | return; 647 | 648 | var i = 1; 649 | for (i; i <= icon_index; i++){ 650 | document.getElementById(scope.id + i).className = 'icon active'; 651 | } 652 | 653 | return; 654 | }; 655 | 656 | // 657 | // Handle mouse leave 658 | // 659 | scope.mouse_leave = function(icon_index){ 660 | if (checked == true) 661 | return; 662 | 663 | var i = 1; 664 | for (i; i <= 5; i++){ 665 | document.getElementById(scope.id + i).className = 'icon'; 666 | } 667 | 668 | return; 669 | }; 670 | 671 | // 672 | // Handle click 673 | // 674 | scope.click = function(icon_index, mode){ 675 | var i = 1; 676 | for (i; i <= icon_index; i++){ 677 | document.getElementById(scope.id + i).className = 'icon active'; 678 | } 679 | 680 | if (icon_index !== 0) 681 | checked = true; 682 | 683 | return; 684 | }; 685 | 686 | // 687 | // Watch for model 688 | // 689 | scope.$watch('model', function(val){ 690 | scope.click(val); 691 | }); 692 | } 693 | }; 694 | }); 695 | 696 | /* globals _:false */ 697 | 'use strict'; 698 | angular.module('angularify.semantic.wizard', []) 699 | 700 | .controller('WizardController', ['$scope', 701 | function($scope) { 702 | $scope.steps = []; 703 | $scope.currentStep = null; 704 | $scope.stepsLength = ''; 705 | 706 | $scope.$watch('currentStep', function (step) { 707 | if (!step) return; 708 | var stepTitle = $scope.selectedStep.title; 709 | if ($scope.selectedStep && stepTitle !== $scope.currentStep) { 710 | $scope.goTo($scope.steps.filter(function (step) { 711 | return step.title ==- $scope.currentStep; 712 | })[0]); 713 | } 714 | }); 715 | 716 | $scope.$watch('[editMode, steps.length]', function () { 717 | var editMode = $scope.editMode; 718 | if (editMode === undefined || editMode === null) return; 719 | 720 | if (editMode) { 721 | $scope.steps.forEach(function (step) { 722 | step.completed = true; 723 | }); 724 | } 725 | }, true); 726 | 727 | this.addStep = function (step) { 728 | $scope.steps.push(step); 729 | if ($scope.steps.length === 1) { 730 | $scope.goTo($scope.steps[0]); 731 | } 732 | }; 733 | 734 | $scope.goTo = function (step) { 735 | unselectAll(); 736 | $scope.selectedStep = step; 737 | 738 | if ($scope.currentStep !== undefined) { 739 | $scope.currentStep = step.title; 740 | } 741 | 742 | step.selected = true; 743 | $scope.$emit('wizard:stepChanged', { 744 | step: step, 745 | index: $scope.steps.indexOf(step) 746 | }); 747 | }; 748 | 749 | function unselectAll() { 750 | $scope.steps.forEach(function (step) { 751 | step.selected = false; 752 | }); 753 | $scope.selectedStep = null; 754 | } 755 | 756 | this.next = function () { 757 | var index = $scope.steps.indexOf($scope.selectedStep); 758 | $scope.selectedStep.completed = true; 759 | if (index === $scope.steps.length - 1) { 760 | this.finish(); 761 | } else { 762 | $scope.goTo($scope.steps[index + 1]); 763 | } 764 | }; 765 | 766 | this.goTo = function (step) { 767 | var stepTo; 768 | 769 | if (angular.isNumber(step)) { 770 | stepTo = $scope.steps[step]; 771 | } else { 772 | stepTo = $scope.steps.filter(function (step) { 773 | return step.title === step; 774 | })[0]; 775 | } 776 | $scope.goTo(stepTo); 777 | }; 778 | 779 | this.finish = function() { 780 | if ($scope.onFinish) { 781 | $scope.selectedStep.completed = true; 782 | $scope.onFinish(); 783 | } 784 | }; 785 | 786 | this.cancel = this.previous = function() { 787 | var index = $scope.steps.indexOf($scope.selectedStep); 788 | if (index === 0) { 789 | throw new Error('Cant go back. Its already in step 0'); 790 | } else { 791 | $scope.goTo($scope.steps[index - 1]); 792 | } 793 | }; 794 | 795 | $scope.getStatus = function (step) { 796 | var statusClass = []; 797 | 798 | if (step.selected) 799 | statusClass.push('active'); 800 | if (!step.selected && !step.completed) 801 | statusClass.push('disabled'); 802 | if (step.completed) 803 | statusClass.push('completed'); 804 | 805 | return statusClass; 806 | }; 807 | } 808 | ]) 809 | .directive('wizard', function() { 810 | return { 811 | restrict: 'EA', 812 | replace: true, 813 | transclude: true, 814 | scope: { 815 | fullwidth: "@", 816 | currentStep: '=?', 817 | onFinish: '&', 818 | editMode: '=', 819 | name: '@' 820 | }, 821 | controller: 'WizardController', 822 | template: '
' + 823 | '
' + 824 | '
' + 825 | '{{step.title}}' + 826 | '
' + 827 | '
' + 828 | '' + 829 | '
' + 830 | '
', 831 | link: function(scope, element, attrs, WizardController) { 832 | if (scope.fullwidth === 'true') { 833 | var widthmatrix = { 834 | 0: '', 835 | 1: 'one', 836 | 2: 'two', 837 | 3: 'three', 838 | 4: 'four', 839 | 5: 'five', 840 | 6: 'six', 841 | 7: 'seven', 842 | 8: 'eight', 843 | 9: 'nine', 844 | 10: 'ten' 845 | }; 846 | scope.stepsLength = widthmatrix[scope.steps.length]; 847 | } 848 | 849 | } 850 | }; 851 | }) 852 | .directive('wizardPane', function() { 853 | return { 854 | restrict: 'EA', 855 | replace: true, 856 | transclude: true, 857 | require: '^wizard', 858 | controller: 'WizardController', 859 | scope: { 860 | title: '@' 861 | }, 862 | template: '
', 863 | link: function(scope, element, attrs, WizardController) { 864 | WizardController.addStep(scope); 865 | } 866 | }; 867 | }); 868 | 869 | function wizardButtonDirective(action) { 870 | angular.module('angularify.semantic.wizard') 871 | .directive(action, function () { 872 | return { 873 | restrict: 'A', 874 | replace: false, 875 | require: '^wizard', 876 | link: function ($scope, $element, $attrs, wizard) { 877 | $scope.noMargin = { margin: 0 }; 878 | $element.on('click', function (e) { 879 | e.preventDefault(); 880 | $scope.$apply(function () { 881 | $scope.$eval($attrs[action]); 882 | wizard[action.replace('wz', '').toLowerCase()](); 883 | }); 884 | }); 885 | } 886 | }; 887 | }); 888 | } 889 | 890 | wizardButtonDirective('wzNext'); 891 | wizardButtonDirective('wzPrevious'); 892 | wizardButtonDirective('wzFinish'); 893 | wizardButtonDirective('wzCancel'); 894 | -------------------------------------------------------------------------------- /dist/angular-semantic-ui.min.js: -------------------------------------------------------------------------------- 1 | function sidebar(){return{restrict:"E",replace:!0,transclude:!0,template:'',scope:{buttonClass:"@"},link:function(a,b,c){b.sidebar("attach events",a.buttonClass,"show")}}}function sidebarItemGroup(){return{restrict:"E",replace:!0,transclude:!0,template:'
{{ title }}
',scope:{title:"@"}}}function sidebarItem(){return{restrict:"E",replace:!0,transclude:!0,template:'
'}}function sidebarLink(){return{restrict:"E",replace:!0,template:'{{ title }}',scope:{title:"@",icon:"@",href:"@"}}}function wizardButtonDirective(a){angular.module("angularify.semantic.wizard").directive(a,function(){return{restrict:"A",replace:!1,require:"^wizard",link:function(b,c,d,e){b.noMargin={margin:0},c.on("click",function(c){c.preventDefault(),b.$apply(function(){b.$eval(d[a]),e[a.replace("wz","").toLowerCase()]()})})}}})}angular.module("angularify.semantic",["angularify.semantic.accordion","angularify.semantic.checkbox","angularify.semantic.dimmer","angularify.semantic.dropdown","angularify.semantic.modal","angularify.semantic.popup","angularify.semantic.rating","angularify.semantic.sidebar","angularify.semantic.wizard"]),angular.module("angularify.semantic.accordion",[]).controller("AccordionController",["$scope",function(a){a.accordions=[],this.add_accordion=function(b){a.accordions.push(b);var c=this;return b.$on("$destroy",function(a){c.remove_accordion(b)}),a.accordions},this.closeAll=function(b){var c=0,d=!1,e=a.accordions.indexOf(b);for(c in a.accordions)a.accordions[c].close&&(d=!0);if(1==d){for(c in a.accordions)c!==e&&(a.accordions[c].active=!1);return!0}return!1},this.remove_accordion=function(b){var c=a.accordions.indexOf(b);-1!==c&&a.accordions.splice(c,1)},this.is_close_all=function(){var b=0;for(b in a.accordions)if("true"==a.accordions[b].close)return!0;return!1}}]).directive("accordion",function(){return{restrict:"E",replace:!0,transclude:!0,controller:"AccordionController",scope:{close:"@"},template:'
',link:function(a,b,c,d){"undefined"!=typeof c.styled&&b.addClass("styled"),d.add_accordion(a)}}}).directive("accordionGroup",function(){return{restrict:"E",replace:!0,transclude:!0,scope:{title:"@",open:"@"},require:"^accordion",template:'
{{ title }}
',link:function(a,b,c,d){a.active="true"===c.open,d.add_accordion(a),a.click_on_accordion_tab=function(){d.closeAll(a),a.active=!a.active,b.children().last().slideToggle()}}}}),angular.module("angularify.semantic.checkbox",[]).directive("checkbox",function(){return{restrict:"E",replace:!0,transclude:!0,scope:{checked:"&?",disabled:"&?",ngModel:"=ngModel"},controller:function(){var a=this;angular.isFunction(a.checked)&&(a.ngModel=!!a.checked()),a.toggle=function(){angular.isFunction(a.disabled)&&a.disabled()||(a.ngModel=!a.ngModel)}},controllerAs:"vm",bindToController:!0,require:"ngModel",template:'
',link:function(){}}}),angular.module("angularify.semantic.dimmer",[]).directive("pageDimmer",function(){return{restrict:"E",replace:!0,transclude:!0,scope:{show:"=?",model:"=ngModel"},template:'
',link:function(a,b,c,d){1==a.show?a.dimmer_class="ui page active dimmer":(a.show=!1,a.dimmer_class="ui page disable dimmer"),a.click_on_dimmer=function(){a.model=!1,a.dimmer_class="ui page dimmer"},a.$watch("model",function(b){0!=b&&void 0!=b&&(a.dimmer_class="ui page active dimmer")})}}}),angular.module("angularify.semantic.dropdown",[]).controller("DropDownController",["$scope",function(a){a.options=[],this.add_option=function(b,c){a.options.push({title:b,value:c}),c==a.model&&this.update_title(c)},this.remove_option=function(b,c){for(var d in a.options)if(a.options[d].value==c&&a.options[d].title==b){a.options.splice(d,1);break}},this.update_model=function(b,c){a.model!==c&&(a.model=c)},this.update_title=function(b){var c=!1;for(var d in a.options)a.options[d].value==b&&(a.title=a.options[d].title,c=!0);c?a.text_class="text":(a.title=a.original_title,a.text_class="default text")}}]).directive("dropdown",function(){return{restrict:"E",replace:!0,transclude:!0,controller:"DropDownController",scope:{title:"@",open:"@",model:"=ngModel"},template:'',link:function(a,b,c,d){a.dropdown_class="ui selection dropdown",a.menu_class="menu transition hidden",a.text_class="default text",a.original_title=a.title,"true"===a.open?(a.is_open=!0,a.dropdown_class=a.dropdown_class+" active visible",a.menu_class=a.menu_class+" visible"):a.is_open=!1,a.element=b,a.$watch("model",function(a){d.update_title(a)}),b.bind("click",function(){a.is_open===!1?a.$apply(function(){a.dropdown_class="ui selection dropdown active visible",a.menu_class="menu transition visible"}):a.$apply(function(){a.dropdown_class="ui selection dropdown",a.menu_class="menu transition hidden"}),a.is_open=!a.is_open})}}}).directive("dropdownGroup",function(){return{restrict:"AE",replace:!0,transclude:!0,require:"^dropdown",scope:{title:"=title",value:"=value"},template:'
{{ item_title }}
',link:function(a,b,c,d){void 0===a.title?a.item_title=c.title||b.children()[0].innerHTML:a.item_title=a.title,void 0===a.value?a.item_value=c.value||a.item_title:a.item_value=a.value,d.add_option(a.item_title,a.item_value),b.bind("click",function(){d.update_model(a.item_title,a.item_value)}),a.$on("$destroy",function(){d.remove_option(a.item_title,a.item_value)})}}}),angular.module("angularify.semantic.modal",[]).directive("modal",function(){return{restrict:"E",replace:!0,transclude:!0,require:"ngModel",template:'',link:function(a,b,c,d){b.modal({onHide:function(){d.$setViewValue(!1)}}),a.$watch(function(){return d.$modelValue},function(a){b.modal(a?"show":"hide")})}}}),angular.module("angularify.semantic.popup",[]).directive("popup",function($document){return{restrict:"A",scope:{popup:"@"},link:function(scope,element,attrs){function getPos(a){for(var b=0,c=0;;){if(b+=a.offsetLeft,c+=a.offsetTop,null===a.offsetParent)break;a=a.offsetParent}return[b,c]}var class_name="",popup_meta_data=eval("("+scope.popup+")"),title=popup_meta_data.title;void 0==title&&(title="");var content=popup_meta_data.content;void 0==content&&(content="");var position=popup_meta_data.position;void 0==position&&(position="top");var size=popup_meta_data.size;void 0==size&&(size="small"),class_name="left"==position?"ui popup left center transition visible "+size:"right"==position?"ui popup right center transition visible "+size:"bottom"==position?"ui popup bottom center transition visible "+size:"ui popup top center transition visible "+size;var current_element_position_top_left=getPos(element[0]),current_element_height=element[0].offsetHeight,current_element_width=element[0].offsetWidth;NodeList.prototype.remove=HTMLCollection.prototype.remove=function(){for(var a=0,b=this.length;b>a;a++)this[a]&&this[a].parentElement&&this[a].parentElement.removeChild(this[a])},element.bind("mouseenter",function(){var a='
'+title+'
'+content+"
";angular.element(element[0]).append(a);var b=document.getElementById("my-popup").clientHeight,c=document.getElementById("my-popup").clientWidth;"left"==position?(document.getElementById("my-popup").style.top=current_element_position_top_left[1]+current_element_height/2-b/2+"px",document.getElementById("my-popup").style.right="auto",document.getElementById("my-popup").style.left=current_element_position_top_left[0]-c-10+"px",document.getElementById("my-popup").style.bottom="auto",document.getElementById("my-popup").style.display="inline-block"):"right"==position?(document.getElementById("my-popup").style.top=current_element_position_top_left[1]+current_element_height/2-b/2+"px",document.getElementById("my-popup").style.right="auto",document.getElementById("my-popup").style.left=current_element_position_top_left[0]+current_element_width+"px",document.getElementById("my-popup").style.bottom="auto",document.getElementById("my-popup").style.display="inline-block"):"bottom"==position?(document.getElementById("my-popup").style.top=current_element_position_top_left[1]+current_element_height+"px",document.getElementById("my-popup").style.left=current_element_position_top_left[0]+current_element_width/2-c/2+15+"px",document.getElementById("my-popup").style.right="auto",document.getElementById("my-popup").style.bottom="auto",document.getElementById("my-popup").style.display="inline-block"):(document.getElementById("my-popup").style.top=current_element_position_top_left[1]-b-10+"px",document.getElementById("my-popup").style.left=current_element_position_top_left[0]+current_element_width/2-c/2+18+"px",document.getElementById("my-popup").style.right="auto",document.getElementById("my-popup").style.bottom="auto",document.getElementById("my-popup").style.display="inline-block")}),element.bind("mouseleave",function(){document.getElementsByClassName("ui popup bottom center transition visible").remove(),null!==document.getElementById("my-popup")&&document.getElementById("my-popup").remove()})}}}),angular.module("angularify.semantic.sidebar",[]).directive("sidebar",sidebar).directive("sidebarLink",sidebarLink).directive("sidebarItem",sidebarItem).directive("sidebarItemGroup",sidebarItemGroup),angular.module("angularify.semantic.rating",[]).directive("rating",function(){return{restrict:"E",replace:!0,transclude:!0,scope:{id:"@",size:"@",type:"@",model:"=ngModel"},template:'
',link:function(a,b,c){void 0==a.model&&(a.model=0),a.model<1&&a.model>5&&(a.model=0);var d=!1;void 0==a.type&&(a.type="star"),void 0==a.size?a.div_class="ui rating "+a.type:"small"==a.size?a.div_class="ui small "+a.type+" rating":"large"==a.size?a.div_class="ui large "+a.type+" rating":"huge"==a.size&&(a.div_class="ui huge "+a.type+" rating"),a.icon_class="icon",a.mouse_enter=function(b){if(1!=d){var c=1;for(c;b>=c;c++)document.getElementById(a.id+c).className="icon active"}},a.mouse_leave=function(b){if(1!=d){var c=1;for(c;5>=c;c++)document.getElementById(a.id+c).className="icon"}},a.click=function(b,c){var e=1;for(e;b>=e;e++)document.getElementById(a.id+e).className="icon active";0!==b&&(d=!0)},a.$watch("model",function(b){a.click(b)})}}}),angular.module("angularify.semantic.wizard",[]).controller("WizardController",["$scope",function(a){function b(){a.steps.forEach(function(a){a.selected=!1}),a.selectedStep=null}a.steps=[],a.currentStep=null,a.stepsLength="",a.$watch("currentStep",function(b){if(b){var c=a.selectedStep.title;a.selectedStep&&c!==a.currentStep&&a.goTo(a.steps.filter(function(b){return b.title==-a.currentStep})[0])}}),a.$watch("[editMode, steps.length]",function(){var b=a.editMode;void 0!==b&&null!==b&&b&&a.steps.forEach(function(a){a.completed=!0})},!0),this.addStep=function(b){a.steps.push(b),1===a.steps.length&&a.goTo(a.steps[0])},a.goTo=function(c){b(),a.selectedStep=c,void 0!==a.currentStep&&(a.currentStep=c.title),c.selected=!0,a.$emit("wizard:stepChanged",{step:c,index:a.steps.indexOf(c)})},this.next=function(){var b=a.steps.indexOf(a.selectedStep);a.selectedStep.completed=!0,b===a.steps.length-1?this.finish():a.goTo(a.steps[b+1])},this.goTo=function(b){var c;c=angular.isNumber(b)?a.steps[b]:a.steps.filter(function(a){return a.title===a})[0],a.goTo(c)},this.finish=function(){a.onFinish&&(a.selectedStep.completed=!0,a.onFinish())},this.cancel=this.previous=function(){var b=a.steps.indexOf(a.selectedStep);if(0===b)throw new Error("Cant go back. Its already in step 0");a.goTo(a.steps[b-1])},a.getStatus=function(a){var b=[];return a.selected&&b.push("active"),a.selected||a.completed||b.push("disabled"),a.completed&&b.push("completed"),b}}]).directive("wizard",function(){return{restrict:"EA",replace:!0,transclude:!0,scope:{fullwidth:"@",currentStep:"=?",onFinish:"&",editMode:"=",name:"@"},controller:"WizardController",template:'
{{step.title}}
',link:function(a,b,c,d){if("true"===a.fullwidth){var e={0:"",1:"one",2:"two",3:"three",4:"four",5:"five",6:"six",7:"seven",8:"eight",9:"nine",10:"ten"};a.stepsLength=e[a.steps.length]}}}}).directive("wizardPane",function(){return{restrict:"EA",replace:!0,transclude:!0,require:"^wizard",controller:"WizardController",scope:{title:"@"},template:'
',link:function(a,b,c,d){d.addStep(a)}}}),wizardButtonDirective("wzNext"),wizardButtonDirective("wzPrevious"),wizardButtonDirective("wzFinish"),wizardButtonDirective("wzCancel"); -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | basePath = '.'; 2 | 3 | files = [ 4 | JASMINE, 5 | JASMINE_ADAPTER, 6 | 'bower_components/jquery/dist/jquery.min.js', 7 | 'bower_components/angular/angular.min.js', 8 | 'bower_components/angular-mocks/angular-mocks.js', 9 | 'src/**/*.js', 10 | ]; 11 | 12 | exclude = [ 13 | 'src/**/docs/*', 'src/**/README.md' 14 | ]; 15 | 16 | browsers = [ 17 | 'PhantomJS' 18 | ]; 19 | 20 | reporters = ['progress']; 21 | 22 | port = 9018; 23 | runnerPort = 9100; 24 | 25 | colors = true; 26 | 27 | logLevel = LOG_INFO 28 | 29 | autoWatch = false; 30 | 31 | singleRun = false; 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-semantic-ui", 3 | "description": "Angular - AngularJS directives for Semantic UI.", 4 | "version": "0.0.3", 5 | "keywords": [ 6 | "angular", 7 | "ui", 8 | "semantic" 9 | ], 10 | "homepage": "http://0xAX.github.io/angular-semantic-ui", 11 | "bugs": "https://github.com/angularify/angular-semantic-ui", 12 | "author": { 13 | "name": "Alex Kuleshov", 14 | "url": "https://github.com/0xAX" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/angularify/angular-semantic-ui.git" 19 | }, 20 | "licenses": [ 21 | { 22 | "type": "MIT", 23 | "url": "https://github.com/angularify/angular-semantic-ui/blob/master/LICENSE.md" 24 | } 25 | ], 26 | "dependencies": {}, 27 | "devDependencies": { 28 | "grunt": "~0.4.1", 29 | "grunt-ngdocs": "~0.1.1", 30 | "grunt-conventional-changelog": "~0.1.2", 31 | "grunt-contrib-concat": "~0.3.0", 32 | "grunt-contrib-copy": "~0.5.0", 33 | "grunt-contrib-uglify": "~0.3.0", 34 | "grunt-contrib-watch": "~0.5.0", 35 | "grunt-contrib-jshint": "~0.8.0", 36 | "karma-phantomjs-launcher" : "latest", 37 | "grunt-html2js": "~0.2.0", 38 | "grunt-karma": "~0.4.4", 39 | "node-markdown": "0.1.1", 40 | "semver": "~2.2.0", 41 | "shelljs": "~0.2.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/accordion/README.md: -------------------------------------------------------------------------------- 1 | angularify.semantic.accordion 2 | =============================== 3 | 4 | `angularify.semantic.accordion` - accordion directive for angular.js. 5 | 6 | Usage 7 | ------------------------------- 8 | 9 | ```html 10 | 11 | 12 |

Some text in first tab

13 |
14 | 15 |

Some text in second tab

16 |
17 |
18 | ``` 19 | 20 | `` - can have following attributes: 21 | 22 | * `close` - true || false, close all tabs if it is `true`. 23 | 24 | `` - can have following attributes: 25 | 26 | * `title` - tab's title; 27 | * `open` - `true` || `false`, current `accordion-group` will be open. 28 | 29 | Contribution 30 | ------------------------------- 31 | 32 | 1. Fork main [repository](https://github.com/angularify/angular-semantic-ui). 33 | 2. Make changes. 34 | 3. Create issue. 35 | 4. Send pull request. 36 | 5. Thank you. 37 | 38 | TODO 39 | ------------------------------- 40 | 41 | 1. Add transition. 42 | 2. Add basic accordion. 43 | 3. Add fluid-accordion. 44 | 3. More tests. -------------------------------------------------------------------------------- /src/accordion/accordion.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angularify.semantic.accordion', []) 4 | 5 | .controller('AccordionController', ['$scope', function($scope){ 6 | $scope.accordions = []; 7 | 8 | this.add_accordion = function(scope) { 9 | $scope.accordions.push(scope); 10 | 11 | var _this = this; 12 | scope.$on('$destroy', function (event) { 13 | _this.remove_accordion(scope); 14 | }); 15 | 16 | return $scope.accordions; 17 | } 18 | 19 | this.closeAll = function(scope) { 20 | var i = 0; 21 | var isCloseAll = false; 22 | 23 | var index = $scope.accordions.indexOf(scope); 24 | 25 | for (i in $scope.accordions){ 26 | if ($scope.accordions[i].close) 27 | isCloseAll = true; 28 | } 29 | 30 | if (isCloseAll == true){ 31 | for (i in $scope.accordions){ 32 | if (i !== index) { 33 | $scope.accordions[i].active = false; 34 | } 35 | } 36 | 37 | return true; 38 | } 39 | 40 | return false; 41 | 42 | } 43 | 44 | this.remove_accordion = function(scope) { 45 | var index = $scope.accordions.indexOf(scope); 46 | if ( index !== -1 ) { 47 | $scope.accordions.splice(index, 1); 48 | } 49 | } 50 | 51 | this.is_close_all = function() { 52 | var i = 0; 53 | 54 | for (i in $scope.accordions){ 55 | if ($scope.accordions[i].close == 'true') 56 | return true; 57 | } 58 | return false; 59 | } 60 | }]) 61 | 62 | .directive('accordion', function () { 63 | return { 64 | restrict: 'E', 65 | replace: true, 66 | transclude: true, 67 | controller: 'AccordionController', 68 | scope: { 69 | 'close': '@' 70 | }, 71 | template: "
", 72 | link: function(scope, element, attrs, AccordionController) { 73 | 74 | if(typeof attrs.styled !== 'undefined') { 75 | element.addClass('styled'); 76 | } 77 | 78 | AccordionController.add_accordion(scope); 79 | } 80 | } 81 | }) 82 | 83 | .directive('accordionGroup', function() { 84 | return { 85 | restrict: 'E', 86 | replace: true, 87 | transclude: true, 88 | scope : { 89 | title: '@', 90 | open: '@' 91 | }, 92 | require:'^accordion', 93 | template: "
\ 94 |
\ 95 | \ 96 | {{ title }} \ 97 |
\ 98 |
\ 99 |
\ 100 |
", 101 | 102 | link: function(scope, element, attrs, AccordionController) { 103 | 104 | // set up active 105 | scope.active = attrs.open === 'true'; 106 | 107 | // Add the accordion to the controller 108 | AccordionController.add_accordion(scope); 109 | 110 | // Click handler 111 | scope.click_on_accordion_tab = function(){ 112 | 113 | // class all first of all 114 | AccordionController.closeAll(scope); 115 | 116 | // Swap the active state 117 | scope.active = !scope.active; 118 | 119 | // Add animation to the accordion group content 120 | element.children().last().slideToggle(); 121 | }; 122 | } 123 | }; 124 | }); -------------------------------------------------------------------------------- /src/accordion/docs/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularify/angular-semantic-ui/6ac38e0bc5c91b084fae8defecb9e3e9ed74c3a8/src/accordion/docs/.gitkeep -------------------------------------------------------------------------------- /src/accordion/docs/controllers.js: -------------------------------------------------------------------------------- 1 | var App = angular.module('AccordionApp', ['angularify.semantic.accordion']); 2 | 3 | function RootCtrl ($scope) { 4 | 5 | } -------------------------------------------------------------------------------- /src/accordion/docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Semantic UI + Angular.JS 6 | 7 | 8 | 9 | 10 | 11 |

Some text in first tab

12 |
13 | 14 |

Some text in second tab

15 |
16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/accordion/test/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularify/angular-semantic-ui/6ac38e0bc5c91b084fae8defecb9e3e9ed74c3a8/src/accordion/test/.gitkeep -------------------------------------------------------------------------------- /src/accordion/test/accordion.spec.js: -------------------------------------------------------------------------------- 1 | describe('accordion', function () { 2 | var $scope; 3 | 4 | beforeEach(module('angularify.semantic.accordion')); 5 | 6 | beforeEach(inject(function ($rootScope) { 7 | $scope = $rootScope; 8 | })); 9 | 10 | describe('controller', function () { 11 | var ctrl, $element, $attrs; 12 | 13 | beforeEach(inject(function($controller) { 14 | $attrs = {}; $element = {}; 15 | ctrl = $controller('AccordionController', { $scope: $scope }); 16 | })); 17 | 18 | describe('add_accordion', function() { 19 | it("AccordionController add_accordion test", function(){ 20 | var acc1, acc2; 21 | ctrl.add_accordion(acc1 = $scope.$new()); 22 | ctrl.add_accordion(acc2 = $scope.$new()); 23 | expect($scope.accordions.length).toBe(2); 24 | }); 25 | }); 26 | 27 | describe('remove_accordion', function(){ 28 | it("AccordionController remove_accordion test", function(){ 29 | var acc1, acc2; 30 | ctrl.add_accordion(acc1 = $scope.$new()); 31 | ctrl.add_accordion(acc2 = $scope.$new()); 32 | ctrl.remove_accordion(acc2); 33 | expect($scope.accordions.length).toBe(1); 34 | }) 35 | }); 36 | }); 37 | }); -------------------------------------------------------------------------------- /src/angularify.semantic.js: -------------------------------------------------------------------------------- 1 | angular.module('angularify.semantic', ['angularify.semantic.accordion', 2 | 'angularify.semantic.checkbox', 3 | 'angularify.semantic.dimmer', 4 | 'angularify.semantic.dropdown', 5 | 'angularify.semantic.modal', 6 | 'angularify.semantic.popup', 7 | 'angularify.semantic.rating', 8 | 'angularify.semantic.sidebar', 9 | 'angularify.semantic.wizard']); 10 | -------------------------------------------------------------------------------- /src/checkbox/README.md: -------------------------------------------------------------------------------- 1 | angularify.semantic.checkbox 2 | =============================== 3 | 4 | `angularify.semantic.checkbox` - checkbox directive for angular.js. 5 | 6 | Usage 7 | ------------------------------- 8 | 9 | ```html 10 |
11 | Alex 12 |
13 | 0xAX 14 |
15 | User 16 |
17 | isActive 18 |
19 | ``` 20 | 21 | `checkbox` - can have following properties: 22 | 23 | * `class / ng-class`: - `standard` || `slider` || `toggle` || `large` || `huge` || `undefined` - the style of checkbox; 24 | * `checked` - `true` || `false`, checked checkbox or not; 25 | - `disabled` - `disabled`, optional if the checkbox is disabled or not; 26 | * `ng-model` - angular model. 27 | 28 | Contribution 29 | ------------------------------- 30 | 31 | 1. Fork main [repository](https://github.com/angularify/angular-semantic-ui). 32 | 2. Make changes. 33 | 3. Create issue. 34 | 4. Send pull request. 35 | 5. Thank you. 36 | 37 | TODO 38 | ------------------------------- 39 | 40 | 1. Add radio-button. 41 | -------------------------------------------------------------------------------- /src/checkbox/checkbox.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angularify.semantic.checkbox', []) 4 | .directive('checkbox', function() { 5 | return { 6 | restrict: 'E', 7 | replace: true, 8 | transclude: true, 9 | scope: { 10 | checked: '&?', 11 | disabled: '&?', 12 | ngModel: '=ngModel' 13 | }, 14 | controller: function() { 15 | var vm = this; 16 | 17 | // TODO: assert this is usefull ? 18 | // if(angular.isUndefined(vm.ngModel)) { vm.ngModel = !!vm.ngModel; } 19 | 20 | if(angular.isFunction(vm.checked)) { vm.ngModel = !!vm.checked(); } 21 | 22 | vm.toggle = function() { 23 | if(angular.isFunction(vm.disabled) && vm.disabled()) return; 24 | vm.ngModel = !vm.ngModel; 25 | } 26 | }, 27 | controllerAs: 'vm', 28 | bindToController: true, 29 | require: 'ngModel', 30 | template: '
' + 31 | '' + 32 | '' + 33 | '
', 34 | link: function() { } 35 | }; 36 | }); 37 | -------------------------------------------------------------------------------- /src/checkbox/docs/controllers.js: -------------------------------------------------------------------------------- 1 | var checkBoxApp = angular.module('checkBoxApp', ['angularify.semantic.checkbox']); 2 | 3 | checkBoxApp.controller('RootCtrl', function() { }); 4 | 5 | -------------------------------------------------------------------------------- /src/checkbox/docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Semantic UI + Angular.JS 7 | 8 | 9 | 10 | 11 | Alex 12 |
13 | 0xAX 14 |
15 | User 16 |
17 | User 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/checkbox/test/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularify/angular-semantic-ui/6ac38e0bc5c91b084fae8defecb9e3e9ed74c3a8/src/checkbox/test/.gitkeep -------------------------------------------------------------------------------- /src/checkbox/test/checkbox.spec.js: -------------------------------------------------------------------------------- 1 | describe('checkbox', function () { 2 | beforeEach(module('angularify.semantic.checkbox')); 3 | 4 | var $controller; 5 | var $compile; 6 | var $rootScope; 7 | 8 | beforeEach(inject(function(_$controller_, _$compile_, _$rootScope_) { 9 | $controller = _$controller_; 10 | $compile = _$compile_; 11 | $rootScope = _$rootScope_; 12 | })); 13 | 14 | describe('directive', function() { 15 | it('should require ng-model', function() { 16 | expect(function() { 17 | $compile('checkbox\'s label')($rootScope) 18 | }).toThrow(); 19 | }); 20 | 21 | it('should compile when ng-model provided', function() { 22 | var element = $compile('checkbox\'s label')($rootScope); 23 | $rootScope.$digest(); 24 | 25 | expect(element.is('.ui.checkbox')).toBeTruthy() 26 | 27 | expect(element.children().length).toEqual(2); 28 | expect(angular.element(element.children()[0]).is('input:checkbox')).toBeTruthy(); 29 | expect(element.children('input').is('input:checkbox')).toBeTruthy(); 30 | expect(angular.element(element.children()[1]).is('label')).toBeTruthy(); 31 | 32 | expect(element.children('label').text()).toEqual('checkbox\'s label'); 33 | expect(element.find('input').is(':checked')).toBeFalsy(); 34 | expect($rootScope.value).toBeFalsy(); 35 | 36 | element.find('input').click(); 37 | expect(element.find('input').is(':checked')).toBeTruthy(); 38 | expect($rootScope.value).toBeTruthy(); 39 | }); 40 | 41 | it('should be checked when marked checked', function() { 42 | var element = $compile('checkbox\'s label')($rootScope); 43 | $rootScope.$digest(); 44 | expect(element.find('input').is(':checked')).toBeTruthy(); 45 | expect($rootScope.value).toBeTruthy(); 46 | }); 47 | 48 | it('should be not checked when marked checked false', function() { 49 | var element = $compile('checkbox\'s label')($rootScope); 50 | $rootScope.$digest(); 51 | expect(element.find('input').is(':checked')).toBeFalsy(); 52 | expect($rootScope.value).toBeFalsy(); 53 | }); 54 | 55 | it('should be disabled when marked disabled', function() { 56 | var element = $compile('checkbox\'s label')($rootScope); 57 | $rootScope.$digest(); 58 | expect(element.find('input').is(':disabled')).toBeTruthy(); 59 | 60 | expect(element.find('input').is(':checked')).toBeFalsy(); 61 | expect($rootScope.value).toBeFalsy(); 62 | element.find('label').click(); 63 | expect(element.find('input').is(':checked')).toBeFalsy(); 64 | expect($rootScope.value).toBeFalsy(); 65 | }); 66 | 67 | it('should be enabled when marked disabled false', function() { 68 | var element = $compile('checkbox\'s label')($rootScope); 69 | $rootScope.$digest(); 70 | expect(element.find('input').is(':disabled')).toBeFalsy(); 71 | }); 72 | 73 | it('should be large when size is large', function() { 74 | var element = $compile('checkbox\'s label')($rootScope); 75 | $rootScope.$digest(); 76 | expect(element.is('.large')).toBeTruthy() 77 | }); 78 | 79 | it('should be huge when size is huge', function() { 80 | var element = $compile('checkbox\'s label')($rootScope); 81 | $rootScope.$digest(); 82 | expect(element.is('.huge')).toBeTruthy() 83 | }); 84 | 85 | it('should be slider when type is slider', function() { 86 | var element = $compile('checkbox\'s label')($rootScope); 87 | $rootScope.$digest(); 88 | expect(element.is('.slider')).toBeTruthy() 89 | }); 90 | 91 | it('should be toggle when type is toggle', function() { 92 | var element = $compile('checkbox\'s label')($rootScope); 93 | $rootScope.$digest(); 94 | expect(element.is('.toggle')).toBeTruthy() 95 | }); 96 | 97 | }); 98 | }); 99 | -------------------------------------------------------------------------------- /src/dimmer/README.md: -------------------------------------------------------------------------------- 1 | angularify.semantic.dimmer 2 | =============================== 3 | 4 | `angularify.semantic.dimmer` - dimmer directive for angular.js. 5 | 6 | Usage 7 | ------------------------------- 8 | 9 | ```html 10 |
11 | Hello 12 |
13 | 14 |
15 | Open dimmer 16 |
17 | ``` 18 | 19 | ```javascript 20 | var dimmerApp = angular.module('dimmerApp', ['angularify.semantic.dimmer']); 21 | 22 | function RootCtrl ($scope) { 23 | $scope.dimmer = function(){ 24 | $scope.show_dimmer = true; 25 | } 26 | } 27 | ``` 28 | 29 | `dimmer` - can have following attributes: 30 | 31 | * `ng-model` - angular model; 32 | * `show` - is current dimmer showed. 33 | 34 | Contribution 35 | ------------------------------- 36 | 37 | 1. Fork main [repository](https://github.com/angularify/angular-semantic-ui). 38 | 2. Make changes. 39 | 3. Create issue. 40 | 4. Send pull request. 41 | 5. Thank you. 42 | 43 | TODO 44 | ------------------------------- 45 | 46 | 1. add duration; 47 | 2. add animation; 48 | 3. add different dimmer types. -------------------------------------------------------------------------------- /src/dimmer/dimmer.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angularify.semantic.dimmer', []) 4 | 5 | .directive("pageDimmer", function () { 6 | return { 7 | restrict: 'E', 8 | replace: true, 9 | transclude: true, 10 | scope : { 11 | show : "=?", 12 | model: '=ngModel' 13 | }, 14 | template: "
" + 15 | "
" + 16 | "
" + 17 | "
" + 18 | "
", 19 | link : function(scope, element, attrs, ngModel) { 20 | 21 | if (scope.show == true) { 22 | scope.dimmer_class = 'ui page active dimmer'; 23 | } 24 | else { 25 | scope.show = false; 26 | scope.dimmer_class = 'ui page disable dimmer'; 27 | } 28 | 29 | // 30 | // Click on dimmer handler 31 | // 32 | scope.click_on_dimmer = function(){ 33 | scope.model = false; 34 | scope.dimmer_class = 'ui page dimmer'; 35 | } 36 | 37 | // 38 | // Watch for the ng-model changing 39 | // 40 | scope.$watch('model', function(val){ 41 | if (val == false || val == undefined) 42 | scope.dimmer_class = 'ui page dimmer'; 43 | else 44 | scope.dimmer_class = 'ui page active dimmer'; 45 | }); 46 | } 47 | }; 48 | }); 49 | -------------------------------------------------------------------------------- /src/dimmer/docs/controllers.js: -------------------------------------------------------------------------------- 1 | var dimmerApp = angular.module('dimmerApp', ['angularify.semantic.dimmer']); 2 | dimmerApp.controller('RootCtrl', RootCtrl); 3 | 4 | function RootCtrl($scope) { 5 | $scope.dimmer = function(){ 6 | $scope.show_dimmer = true; 7 | }; 8 | } -------------------------------------------------------------------------------- /src/dimmer/docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Semantic UI + Angular.JS 6 | 7 | 8 | 9 |
10 | Hello 11 |
12 | 13 |
14 | Open dimmer 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/dimmer/test/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/angularify/angular-semantic-ui/6ac38e0bc5c91b084fae8defecb9e3e9ed74c3a8/src/dimmer/test/.gitkeep -------------------------------------------------------------------------------- /src/dropdown/README.md: -------------------------------------------------------------------------------- 1 | angularify.semantic.dropdown 2 | =============================== 3 | 4 | `angularify.semantic.dropdown` - dropdown directive for angular.js. 5 | 6 | Usage 7 | ------------------------------- 8 | 9 | ```html 10 | 11 | item1 12 | item2 13 | item3 14 | item4 15 | 16 | ``` 17 | 18 | or 19 | 20 | ```html 21 | 22 | {{c.title}} 23 | 24 | ``` 25 | 26 | `dropdown` - can have following attributes: 27 | 28 | * `title` - title(placeholder) of the dropdown; 29 | * `ng-model` - angular model; 30 | * `open` - `true` || `false`. is current dropdown opened. 31 | 32 | `dropdown-group` - can have following attributes: 33 | 34 | * `title` - optional setting to set the name and value (if value not specified) of the entry. Helpful for those {{variables}} that don't; 35 | * `value` - set item value. 36 | 37 | Contribution 38 | ------------------------------- 39 | 40 | 1. Fork main [repository](https://github.com/angularify/angular-semantic-ui). 41 | 2. Make changes. 42 | 3. Create issue. 43 | 4. Send pull request. 44 | 5. Thank you. 45 | 46 | TODO 47 | ------------------------------- 48 | 49 | 1. Add different dropdown types. 50 | -------------------------------------------------------------------------------- /src/dropdown/docs/controllers.js: -------------------------------------------------------------------------------- 1 | 2 | angular 3 | .module('dropdownApp', ['angularify.semantic.dropdown']) 4 | .controller('RootCtrl', RootCtrl); 5 | 6 | function RootCtrl ($scope) { 7 | $scope.dropdown_model = 'item3'; 8 | 9 | $scope.dropdown_repeat_model = 'item1'; 10 | $scope.dropdown_items = [ 11 | 'item1', 12 | 'item2', 13 | 'item3', 14 | 'item4' 15 | ]; 16 | 17 | $scope.dropdown_key_value_model = ''; 18 | $scope.dropdown_key_value_items = { 19 | 'item1': 'Cool item 1', 20 | 'item2': 'Cool item 2', 21 | 'item3': 'Cool item 3', 22 | 'item4': 'Cool item 4' 23 | }; 24 | 25 | 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/dropdown/docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Semantic UI + Angular.JS 6 | 7 | 8 | 9 |

Basic

10 | 11 | 12 | item1 13 | item2 14 | item3 15 | item4 16 | 17 | 18 |

19 | Current selection is: {{ dropdown_model }} 20 |

21 | 22 |

With ng-repeat

23 | 24 | 25 | {{ item }} 26 | 27 | 28 |

29 | Current selection is: {{ dropdown_repeat_model }} 30 |

31 | 32 |

With ng-repeat and key/value objects

33 | 34 | 35 | {{ title }} 36 | 37 | 38 |

39 | Current selection is: {{ dropdown_key_value_model }} 40 |

41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/dropdown/dropdown.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angularify.semantic.dropdown', []) 4 | .controller('DropDownController', ['$scope', 5 | function($scope) { 6 | $scope.options = []; 7 | 8 | this.add_option = function(title, value){ 9 | $scope.options.push({'title': title, 'value': value}); 10 | if (value == $scope.model){ 11 | this.update_title(value) 12 | }; 13 | }; 14 | 15 | this.remove_option = function(title, value){ 16 | for (var index in $scope.options) 17 | if ($scope.options[index].value == value && 18 | $scope.options[index].title == title){ 19 | 20 | $scope.options.splice(index, 1); 21 | // Remove only one item 22 | break; 23 | }; 24 | }; 25 | 26 | this.update_model = function (title, value) { 27 | if ($scope.model !== value) 28 | $scope.model = value; 29 | }; 30 | 31 | this.update_title = function (value) { 32 | var changed = false; 33 | 34 | for (var index in $scope.options) 35 | if ($scope.options[index].value == value){ 36 | $scope.title = $scope.options[index].title; 37 | changed = true; 38 | } 39 | 40 | if (changed){ 41 | $scope.text_class = 'text'; 42 | } else{ 43 | $scope.title = $scope.original_title; 44 | $scope.text_class = 'default text'; 45 | } 46 | }; 47 | 48 | } 49 | ]) 50 | 51 | .directive('dropdown', function() { 52 | return { 53 | restrict: 'E', 54 | replace: true, 55 | transclude: true, 56 | controller: 'DropDownController', 57 | scope: { 58 | title: '@', 59 | open: '@', 60 | model: '=ngModel' 61 | }, 62 | template: '', 68 | link: function(scope, element, attrs, DropDownController) { 69 | scope.dropdown_class = 'ui selection dropdown'; 70 | scope.menu_class = 'menu transition hidden'; 71 | scope.text_class = 'default text'; 72 | scope.original_title = scope.title; 73 | 74 | if (scope.open === 'true') { 75 | scope.is_open = true; 76 | scope.dropdown_class = scope.dropdown_class + ' active visible'; 77 | scope.menu_class = scope.menu_class + ' visible'; 78 | } else { 79 | scope.is_open = false; 80 | } 81 | 82 | /* 83 | * Watch for ng-model changing 84 | */ 85 | scope.element = element; 86 | scope.$watch('model', function (value) { 87 | // update title or reset the original title if its empty 88 | DropDownController.update_title(value); 89 | }); 90 | 91 | /* 92 | * Click handler 93 | */ 94 | element.bind('click', function() { 95 | if (scope.is_open === false) { 96 | scope.$apply(function() { 97 | scope.dropdown_class = 'ui selection dropdown active visible'; 98 | scope.menu_class = 'menu transition visible'; 99 | }); 100 | } else { 101 | scope.$apply(function() { 102 | scope.dropdown_class = 'ui selection dropdown'; 103 | scope.menu_class = 'menu transition hidden'; 104 | }); 105 | } 106 | scope.is_open = !scope.is_open; 107 | }); 108 | } 109 | }; 110 | }) 111 | 112 | .directive('dropdownGroup', function() { 113 | return { 114 | restrict: 'AE', 115 | replace: true, 116 | transclude: true, 117 | require: '^dropdown', 118 | scope: { 119 | title: '=title', 120 | value: '=value' 121 | }, 122 | template: '
{{ item_title }}
', 123 | link: function(scope, element, attrs, DropDownController) { 124 | 125 | // Check if title= was set... if not take the contents of the dropdown-group tag 126 | // title= is for dynamic variables from something like ng-repeat {{variable}} 127 | if (scope.title === undefined) { 128 | scope.item_title = attrs.title || element.children()[0].innerHTML; 129 | } else { 130 | scope.item_title = scope.title; 131 | } 132 | if (scope.value === undefined) { 133 | scope.item_value = attrs.value || scope.item_title; 134 | } else { 135 | scope.item_value = scope.value; 136 | } 137 | 138 | // Keep this option 139 | DropDownController.add_option(scope.item_title, scope.item_value); 140 | 141 | // 142 | // Menu item click handler 143 | // 144 | element.bind('click', function() { 145 | DropDownController.update_model(scope.item_title, scope.item_value); 146 | }); 147 | 148 | scope.$on('$destroy', function(){ 149 | DropDownController.remove_option(scope.item_title, scope.item_value); 150 | }); 151 | 152 | } 153 | }; 154 | }); -------------------------------------------------------------------------------- /src/dropdown/test/dropdown.spec.js: -------------------------------------------------------------------------------- 1 | describe('dropdown', function () { 2 | var element, $scope; 3 | 4 | beforeEach(module('angularify.semantic.dropdown')); 5 | 6 | beforeEach(inject(function($rootScope, $compile) { 7 | element = angular.element( 8 | '
' + 9 | '' + 10 | '' + 13 | '{{ title }}' + 14 | '' + 15 | '' + 16 | '
'); 17 | 18 | scope = $rootScope; 19 | scope.dropdown_model = ''; 20 | scope.dropdown_items = {}; 21 | $compile(element)(scope); 22 | scope.$digest(); 23 | })); 24 | 25 | it('should create element with default header', inject(function($compile, $rootScope) { 26 | var header = element.find('div.dropdown > div'); 27 | expect(header.eq(0).text()).toBe('No value'); 28 | })); 29 | 30 | it('should have right amount of options', inject(function($compile, $rootScope) { 31 | var items = element.find('.menu > div.item'); 32 | expect(items.length).toBe(0); 33 | 34 | scope.$apply(function() { 35 | scope.dropdown_items = [{'item1': 'Cool item1'}, {'item2': 'Cool item2'}]; 36 | }); 37 | 38 | items = element.find('.menu > div.item'); 39 | expect(items.length).toBe(2); 40 | 41 | })); 42 | 43 | it('should change model value when user choose option', inject(function($compile, $rootScope) { 44 | scope.$apply(function() { 45 | scope.dropdown_items = {'item1': 'Cool item1', 46 | 'item2': 'Cool item2'}; 47 | }); 48 | 49 | var dropdown = element.find('.dropdown'); 50 | dropdown.click(); 51 | 52 | var option1 = element.find('.menu > div.item').eq(0); 53 | option1.click() 54 | expect(scope.dropdown_model).toBe('item1'); 55 | 56 | })); 57 | 58 | it('should change element header when user choose option', inject(function($compile, $rootScope) { 59 | scope.$apply(function() { 60 | scope.dropdown_items = {'item1': 'Cool item1', 61 | 'item2': 'Cool item2'}; 62 | }); 63 | 64 | var dropdown = element.find('.dropdown'); 65 | dropdown.click(); 66 | 67 | var option1 = element.find('.menu > div.item').eq(0); 68 | option1.click() 69 | 70 | var header = element.find('div.dropdown > div'); 71 | expect(header.eq(0).text()).toBe('Cool item1'); 72 | 73 | })); 74 | 75 | }); 76 | -------------------------------------------------------------------------------- /src/modal/README.md: -------------------------------------------------------------------------------- 1 | angularify.semantic.modal 2 | =============================== 3 | 4 | `angularify.semantic.modal` - modal window directive for angular.js. 5 | 6 | Usage 7 | ------------------------------- 8 | 9 | ```html 10 | 11 | 12 |
13 | Change Your Homepage 14 |
15 |
16 |
17 | 18 |
19 |
20 |

Are you sure you want to change your homepage to Poodle.com?

21 |
22 |
23 |
24 |
25 |
26 | 27 | No 28 |
29 |
30 | Yes 31 | 32 |
33 |
34 |
35 |
36 | ``` 37 | 38 | and js: 39 | 40 | ```javascript 41 | function RootCtrl ($scope) { 42 | $scope.show_modal = true; 43 | 44 | $scope.close_modal = function(){ 45 | $scope.show_modal = false; 46 | } 47 | } 48 | ``` 49 | 50 | Contribution 51 | ------------------------------- 52 | 53 | 1. Fork main [repository](https://github.com/angularify/angular-semantic-ui). 54 | 2. Make changes. 55 | 3. Create issue. 56 | 4. Send pull request. 57 | 5. Thank you. 58 | 59 | TODO 60 | ------------------------------- 61 | 62 | 1. Add different modal types. -------------------------------------------------------------------------------- /src/modal/docs/controllers.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('modalApp', ['angularify.semantic.modal']) 3 | .controller('RootCtrl', RootCtrl); 4 | 5 | function RootCtrl($scope) { 6 | $scope.show_modal = false; 7 | 8 | $scope.open_modal = function () { 9 | $scope.show_modal = true; 10 | }; 11 | 12 | $scope.close_modal = function (){ 13 | $scope.show_modal = false; 14 | }; 15 | } -------------------------------------------------------------------------------- /src/modal/docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Semantic UI + Angular.JS 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | Profile Picture 14 |
15 |
16 |
17 | 18 |
19 |
20 |
We've auto-chosen a profile image for you.
21 |

We've grabbed the following image from the gravatar image associated with your registered e-mail address.

22 |

Is it okay to use this photo?

23 |
24 |
25 |
26 |
27 | Nope 28 |
29 |
30 | Yep, that's me 31 | 32 |
33 |
34 |
35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/modal/modal.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angularify.semantic.modal', []) 4 | 5 | .directive('modal', function () { 6 | return { 7 | restrict: 'E', 8 | replace: true, 9 | transclude: true, 10 | require: 'ngModel', 11 | template: '', 12 | link: function (scope, element, attrs, ngModel) { 13 | element.modal({ 14 | onHide: function () { 15 | ngModel.$setViewValue(false); 16 | } 17 | }); 18 | scope.$watch(function () { 19 | return ngModel.$modelValue; 20 | }, function (modelValue){ 21 | element.modal(modelValue ? 'show' : 'hide'); 22 | }); 23 | scope.$on('$destroy', function() { 24 | element.modal('hide'); 25 | element.remove(); 26 | }); 27 | } 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /src/modal/test/modal.spec.js: -------------------------------------------------------------------------------- 1 | describe('modal', function () { 2 | var $scope; 3 | 4 | beforeEach(module('angularify.semantic.modal')); 5 | 6 | beforeEach(inject(function ($rootScope) { 7 | $scope = $rootScope; 8 | })); 9 | }); -------------------------------------------------------------------------------- /src/popup/README.md: -------------------------------------------------------------------------------- 1 | angularify.semantic.popup 2 | =============================== 3 | 4 | `angularify.semantic.popup` - popup directive for angular.js. 5 | 6 | Usage 7 | ------------------------------- 8 | 9 | ```html 10 | 15 | ``` 16 | 17 | `position` - can be: `bottom`, `top`, `right` or `left`. 18 | 19 | `size` - can be: `small` or `large`. 20 | 21 | Contribution 22 | ------------------------------- 23 | 24 | 1. Fork main [repository](https://github.com/angularify/angular-semantic-ui). 25 | 2. Make changes. 26 | 3. Create issue. 27 | 4. Send pull request. 28 | 5. Thank you. 29 | 30 | TODO 31 | ------------------------------- 32 | 33 | 1. Add animation. -------------------------------------------------------------------------------- /src/popup/docs/controllers.js: -------------------------------------------------------------------------------- 1 | var popupApp = angular.module('popupApp', ['angularify.semantic.popup']); 2 | 3 | function RootCtrl ($scope) { 4 | 5 | } -------------------------------------------------------------------------------- /src/popup/docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Semantic UI + Angular.JS 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/popup/popup.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angularify.semantic.popup', []) 4 | 5 | .directive('popup', function ($document) { 6 | return { 7 | restrict: "A", 8 | scope : { 9 | popup : "@" 10 | }, 11 | link: function(scope, element, attrs) { 12 | var class_name = ''; 13 | // convert to json 14 | var popup_meta_data = eval('(' + scope.popup + ')'); 15 | 16 | var title = popup_meta_data['title']; 17 | if (title == undefined) 18 | title = ''; 19 | 20 | var content = popup_meta_data['content']; 21 | if (content == undefined) 22 | content = ''; 23 | 24 | var position = popup_meta_data['position']; 25 | if (position == undefined) 26 | position = 'top'; 27 | 28 | var size = popup_meta_data['size']; 29 | if (size == undefined) 30 | size = 'small'; 31 | 32 | if (position == 'left') { 33 | class_name = 'ui popup left center transition visible ' + size; 34 | } else if (position == 'right') { 35 | class_name = 'ui popup right center transition visible ' + size; 36 | } else if (position == 'bottom') { 37 | class_name = 'ui popup bottom center transition visible ' + size; 38 | } else { 39 | class_name = 'ui popup top center transition visible ' + size; 40 | } 41 | 42 | // 43 | // Get element X/Y of left corner 44 | // 45 | function getPos(ele){ 46 | var x = 0; 47 | var y = 0; 48 | while(true){ 49 | x += ele.offsetLeft; 50 | y += ele.offsetTop; 51 | if(ele.offsetParent === null) 52 | break; 53 | ele = ele.offsetParent; 54 | } 55 | return [x, y]; 56 | } 57 | 58 | var current_element_position_top_left = getPos(element[0]); 59 | var current_element_height = element[0].offsetHeight; 60 | var current_element_width = element[0].offsetWidth; 61 | 62 | // 63 | // Remove element by class name 64 | // 65 | NodeList.prototype.remove = HTMLCollection.prototype.remove = function() { 66 | for(var i = 0, len = this.length; i < len; i++) { 67 | if(this[i] && this[i].parentElement) { 68 | this[i].parentElement.removeChild(this[i]); 69 | } 70 | } 71 | } 72 | 73 | // 74 | // Handle mouse over 75 | // 76 | element.bind('mouseenter', function(){ 77 | var html = '
' + title +'
' + content + '
'; 78 | 79 | angular.element(element[0]).append(html); 80 | 81 | var popupHeight = document.getElementById('my-popup').clientHeight; 82 | var popupWidth = document.getElementById('my-popup').clientWidth; 83 | 84 | if (position == 'left') { 85 | document.getElementById('my-popup').style.top = current_element_position_top_left[1] + (current_element_height / 2) - (popupHeight / 2) + 'px'; 86 | document.getElementById('my-popup').style.right = 'auto'; 87 | document.getElementById('my-popup').style.left = current_element_position_top_left[0] - popupWidth - 10 + 'px'; 88 | document.getElementById('my-popup').style.bottom = 'auto'; 89 | document.getElementById('my-popup').style.display = 'inline-block'; 90 | } else if (position == 'right') { 91 | document.getElementById('my-popup').style.top = current_element_position_top_left[1] + (current_element_height / 2) - (popupHeight / 2) + 'px'; 92 | document.getElementById('my-popup').style.right = 'auto'; 93 | document.getElementById('my-popup').style.left = current_element_position_top_left[0] + current_element_width + 'px'; 94 | document.getElementById('my-popup').style.bottom = 'auto'; 95 | document.getElementById('my-popup').style.display = 'inline-block'; 96 | } else if (position == 'bottom') { 97 | document.getElementById('my-popup').style.top = current_element_position_top_left[1] + current_element_height + 'px'; 98 | document.getElementById('my-popup').style.left = current_element_position_top_left[0] + (current_element_width / 2) - (popupWidth / 2) + 15 + 'px'; 99 | document.getElementById('my-popup').style.right = 'auto'; 100 | document.getElementById('my-popup').style.bottom = 'auto'; 101 | document.getElementById('my-popup').style.display = 'inline-block'; 102 | } else { 103 | document.getElementById('my-popup').style.top = current_element_position_top_left[1] - popupHeight - 10 + 'px'; 104 | document.getElementById('my-popup').style.left = current_element_position_top_left[0] + (current_element_width / 2) - (popupWidth / 2) + 18 + 'px'; 105 | document.getElementById('my-popup').style.right = 'auto'; 106 | document.getElementById('my-popup').style.bottom = 'auto'; 107 | document.getElementById('my-popup').style.display = 'inline-block'; 108 | } 109 | }); 110 | 111 | // 112 | // Handle mouse leave 113 | // 114 | element.bind('mouseleave', function(){ 115 | document.getElementsByClassName("ui popup bottom center transition visible").remove(); 116 | if (document.getElementById('my-popup') !== null) 117 | document.getElementById('my-popup').remove(); 118 | }); 119 | } 120 | } 121 | }); -------------------------------------------------------------------------------- /src/popup/test/popup.spec.js: -------------------------------------------------------------------------------- 1 | describe('popup', function () { 2 | var $scope; 3 | 4 | beforeEach(module('angularify.semantic.popup')); 5 | 6 | beforeEach(inject(function ($rootScope) { 7 | $scope = $rootScope; 8 | })); 9 | }); -------------------------------------------------------------------------------- /src/rating/README.md: -------------------------------------------------------------------------------- 1 | angularify.semantic.rating 2 | =============================== 3 | 4 | `angularify.semantic.rating` - rating directive for angular.js. 5 | 6 | Usage 7 | ------------------------------- 8 | 9 | ```html 10 | 11 | ``` 12 | 13 | ```javascript 14 | var ratingApp = angular.module('ratingApp', ['angularify.semantic.rating']); 15 | 16 | function RootCtrl ($scope) { 17 | $scope.rating = 2; 18 | } 19 | ``` 20 | 21 | **IMPORTANT** Every `` must have unique `id` attribute. 22 | 23 | Rating can have following properties: 24 | 25 | * `size` - can be: `small`, `large`, `huge` or `undefined` 26 | 27 | * `type` - can be any icon class (see [semantic-ui](http://semantic-ui.com/elements/icon.html) docs) 28 | 29 | * `ng-model` - return `Int` number: 0..5 (current rating) 30 | 31 | 32 | Contribution 33 | ------------------------------- 34 | 35 | 1. Fork main [repository](https://github.com/angularify/angular-semantic-ui). 36 | 2. Make changes. 37 | 3. Create issue. 38 | 4. Send pull request. 39 | 5. Thank you. 40 | 41 | TODO 42 | ------------------------------ 43 | 44 | 1. Add more tests. -------------------------------------------------------------------------------- /src/rating/docs/controllers.js: -------------------------------------------------------------------------------- 1 | var ratingApp = angular.module('ratingApp', ['angularify.semantic.rating']); 2 | 3 | function RootCtrl ($scope) { 4 | // $scope.rating = 1; 5 | } 6 | -------------------------------------------------------------------------------- /src/rating/docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Semantic UI + Angular.JS 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/rating/rating.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular.module('angularify.semantic.rating', []) 4 | 5 | .directive('rating', function(){ 6 | return { 7 | restrict: "E", 8 | replace: true, 9 | transclude: true, 10 | scope: { 11 | id: "@", 12 | size: "@", 13 | type: "@", 14 | model : '=ngModel' 15 | }, 16 | template: '
' + 17 | '' + 18 | '' + 19 | '' + 20 | '' + 21 | '' + 22 | '
', 23 | link: function(scope, element, attrs){ 24 | if (scope.model == undefined) 25 | scope.model = 0; 26 | 27 | if (scope.model < 1 && scope.model > 5) 28 | scope.model = 0; 29 | 30 | // is rating already checked 31 | var checked = false; 32 | 33 | // 34 | // Set up icon type 35 | // 36 | if (scope.type == undefined) 37 | scope.type = 'star'; 38 | 39 | // 40 | // Set up size 41 | // 42 | if (scope.size == undefined) 43 | scope.div_class = 'ui rating ' + scope.type; 44 | else if (scope.size == 'small') 45 | scope.div_class = 'ui small ' + scope.type + ' rating'; 46 | else if (scope.size == 'large') 47 | scope.div_class = 'ui large ' + scope.type + ' rating'; 48 | else if (scope.size == 'huge') 49 | scope.div_class = 'ui huge ' + scope.type + ' rating'; 50 | 51 | // 52 | // set up icon class 53 | // 54 | scope.icon_class = 'icon'; 55 | 56 | // 57 | // Handle mouse enter 58 | // 59 | scope.mouse_enter = function(icon_index){ 60 | if (checked == true) 61 | return; 62 | 63 | var i = 1; 64 | for (i; i <= icon_index; i++){ 65 | document.getElementById(scope.id + i).className = 'icon active'; 66 | } 67 | 68 | return; 69 | }; 70 | 71 | // 72 | // Handle mouse leave 73 | // 74 | scope.mouse_leave = function(icon_index){ 75 | if (checked == true) 76 | return; 77 | 78 | var i = 1; 79 | for (i; i <= 5; i++){ 80 | document.getElementById(scope.id + i).className = 'icon'; 81 | } 82 | 83 | return; 84 | }; 85 | 86 | // 87 | // Handle click 88 | // 89 | scope.click = function(icon_index, mode){ 90 | var i = 1; 91 | for (i; i <= icon_index; i++){ 92 | document.getElementById(scope.id + i).className = 'icon active'; 93 | } 94 | 95 | if (icon_index !== 0) 96 | checked = true; 97 | 98 | return; 99 | }; 100 | 101 | // 102 | // Watch for model 103 | // 104 | scope.$watch('model', function(val){ 105 | scope.click(val); 106 | }); 107 | } 108 | }; 109 | }); 110 | -------------------------------------------------------------------------------- /src/rating/test/rating.spec.js: -------------------------------------------------------------------------------- 1 | describe('rating', function () { 2 | var $scope; 3 | 4 | beforeEach(module('angularify.semantic.rating')); 5 | 6 | beforeEach(inject(function ($rootScope) { 7 | $scope = $rootScope; 8 | })); 9 | }); 10 | -------------------------------------------------------------------------------- /src/sidebar/README.md: -------------------------------------------------------------------------------- 1 | angularify.semantic.sidebar 2 | =============================== 3 | 4 | `angularify.semantic.sidebar` - sidebar directive for angular.js. 5 | 6 | Usage 7 | ------------------------------- 8 | 9 | ```html 10 | 11 | 12 |

13 |
14 | Sidebar 15 |
Links and items
16 |
17 |

18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 |
29 | 30 |
31 | ``` 32 | 33 | ```javascript 34 | angular 35 | .module('sidebarApp', ['angularify.semantic.sidebar']) 36 | .controller('RootCtrl', RootCtrl); 37 | 38 | function RootCtrl ($scope) { 39 | $scope.isOpen = false; 40 | } 41 | ``` 42 | `` - can have following properties: 43 | 44 | * `button-class` - attach a selector that open the sidebar 45 | 46 | `` - can have following properties: 47 | 48 | * `title` - group title 49 | 50 | `` - can have following properties: 51 | 52 | * `title` - link text 53 | * `icon` - icon name 54 | * `href` - link address 55 | 56 | 57 | Contribution 58 | ------------------------------- 59 | 60 | 1. Fork main [repository](https://github.com/angularify/angular-semantic-ui). 61 | 2. Make changes. 62 | 3. Create issue. 63 | 4. Send pull request. 64 | 5. Thank you. 65 | 66 | TODO 67 | ------------------------------ 68 | 69 | 1. Add more tests. 70 | 2. Add different sidebar types. 71 | -------------------------------------------------------------------------------- /src/sidebar/docs/controllers.js: -------------------------------------------------------------------------------- 1 | angular 2 | .module('sidebarApp', ['angularify.semantic.sidebar']) 3 | .controller('RootCtrl', RootCtrl); 4 | 5 | function RootCtrl ($scope) { 6 | $scope.isOpen = false; 7 | } -------------------------------------------------------------------------------- /src/sidebar/docs/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Semantic UI + Angular.JS 6 | 7 | 8 | 9 | 10 | 11 |

12 |
13 | Sidebar 14 |
Links and items
15 |
16 |

17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/sidebar/sidebar.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | angular 4 | .module('angularify.semantic.sidebar', []) 5 | .directive('sidebar', sidebar) 6 | .directive('sidebarLink', sidebarLink) 7 | .directive('sidebarItem', sidebarItem) 8 | .directive('sidebarItemGroup', sidebarItemGroup); 9 | 10 | function sidebar() { 11 | return { 12 | restrict: 'E', 13 | replace: true, 14 | transclude: true, 15 | template: '', 17 | scope: { 18 | buttonClass: '@' 19 | }, 20 | link: function (scope, element, attrs) { 21 | element.sidebar('attach events', scope.buttonClass, 'show'); 22 | } 23 | }; 24 | } 25 | 26 | function sidebarItemGroup() { 27 | return { 28 | restrict: 'E', 29 | replace: true, 30 | transclude: true, 31 | template: '
' + 32 | '
{{ title }}
' + 33 | '' + 34 | '
', 35 | scope: { 36 | title: '@' 37 | } 38 | }; 39 | } 40 | 41 | function sidebarItem() { 42 | return { 43 | restrict: 'E', 44 | replace: true, 45 | transclude: true, 46 | template: '
' 47 | }; 48 | } 49 | 50 | function sidebarLink() { 51 | return { 52 | restrict: 'E', 53 | replace: true, 54 | template: '' + 55 | '' + 56 | '{{ title }}' + 57 | '', 58 | scope: { 59 | title: '@', 60 | icon: '@', 61 | href: '@' 62 | } 63 | }; 64 | } -------------------------------------------------------------------------------- /src/sidebar/test/sidebar.spec.js: -------------------------------------------------------------------------------- 1 | describe('sidebar', function () { 2 | var $scope; 3 | 4 | beforeEach(module('angularify.semantic.sidebar')); 5 | 6 | beforeEach(inject(function ($rootScope) { 7 | $scope = $rootScope; 8 | })); 9 | }); -------------------------------------------------------------------------------- /src/wizard/README.md: -------------------------------------------------------------------------------- 1 | angularify.semantic.wizard 2 | =============================== 3 | 4 | `angularify.semantic.wizard` - wizard/steps directive for angular.js. 5 | 6 | CREDIT 7 | -------------------- 8 | 9 | This Wizard is a port of the angular-wizard by mgonto from [github](https://github.com/mgonto/angular-wizard) 10 | 11 | Usage 12 | -------------------- 13 | ```html 14 | 15 | 16 |

Step 1

17 |
18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 |

Step 2

26 |
27 |
28 | 29 |
30 | 31 | 32 |
33 |
34 |
35 | ``` 36 | 37 | 38 | `wizard` - can have following attributes: 39 | 40 | * `fullwidth` - Go fullwidth for the steps bar; 41 | * `current-step` - Updated each time a new step is selected 42 | * `on-finish` - Function to call when a button with `wd-finish` will be clicked 43 | 44 | 45 | `wizard-pane` - can have the following attributes 46 | 47 | * `title` - Title of the Step in the wizard 48 | 49 | `Buttons` - There are 4 types of buttons that go in forms to move a wizards direction 50 | 51 | * `wz-next` - next page 52 | * `wz-previous` - previous page 53 | * `wz-finish` - finish Wizard 54 | * `wz-cancel` - cancel wizard -------------------------------------------------------------------------------- /src/wizard/doc/controllers.js: -------------------------------------------------------------------------------- 1 | 2 | angular 3 | .module('dropdownApp', ['angularify.semantic.wizard']) 4 | .controller('RootCtrl', RootCtrl); 5 | 6 | function RootCtrl ($scope) { 7 | $scope.currentStep = ''; 8 | 9 | $scope.callme = function () { 10 | console.log('finished'); 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /src/wizard/doc/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Semantic UI + Angular.JS 6 | 7 | 8 | 9 |

Wizard

10 | 11 |

12 | Current step: {{ currentStep }} 13 |

14 | 15 |

16 | Finished! 17 |

18 | 19 | 20 | 21 |

Step 1

22 |
23 |
24 | 25 |
26 | 27 |
28 |
29 | 30 |

Step 2

31 |
32 |
33 | 34 |
35 | 36 |
37 |
38 | 39 |

Step 3

40 |
41 |
42 | 43 |
44 | 45 | 46 |
47 |
48 |
49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /src/wizard/test/wizard.spec.js: -------------------------------------------------------------------------------- 1 | describe('wizard', function () { 2 | 3 | beforeEach(module('angularify.semantic.wizard')); 4 | 5 | describe('controller', function () { 6 | var controller, 7 | scope; 8 | 9 | beforeEach(inject(function ($controller, $rootScope) { 10 | scope = $rootScope.$new(); 11 | controller = $controller('WizardController', { $scope: scope }); 12 | })); 13 | 14 | describe('with 2 steps', function() { 15 | it("should contain 2 steps", function () { 16 | controller.addStep({ title: 'step1' }); 17 | controller.addStep({ title: 'step2' }); 18 | expect(scope.steps.length).toBe(2); 19 | }); 20 | }); 21 | }); 22 | 23 | describe('directive (wizard)', function () { 24 | var controller, 25 | scope, 26 | elm; 27 | 28 | beforeEach(inject(function ($rootScope, $compile) { 29 | scope = $rootScope; 30 | elm = angular.element('' + 31 | '

Step 1

' + 32 | '

Step 2

' + 33 | '

Step 3

' + 34 | '
'); 35 | $compile(elm)(scope); 36 | scope.$digest(); 37 | })); 38 | 39 | it('should create a .steps div', function () { 40 | expect(elm.find('.steps').length).toBe(1); 41 | }); 42 | 43 | it('should create a have class `three`', function () { 44 | expect(elm.find('.steps').hasClass('three')).toBeTruthy(); 45 | }); 46 | 47 | it('should contain 3 wizard pane', function () { 48 | expect(elm.find('.ui.segment').length).toBe(3); 49 | }); 50 | }); 51 | 52 | describe('directive (wizard-pane)', function () { 53 | var controller, 54 | scope, 55 | elm, 56 | subElm; 57 | 58 | beforeEach(inject(function ($rootScope, $compile) { 59 | scope = $rootScope; 60 | elm = angular.element(''); 61 | subElm = angular.element('

Step 1

'); 62 | 63 | elm.append(subElm); 64 | 65 | $compile(elm)(scope); 66 | scope.$digest(); 67 | })); 68 | 69 | 70 | it('should contain a h1', function () { 71 | expect(elm.find('h1').length).toBe(1); 72 | }); 73 | }); 74 | }); -------------------------------------------------------------------------------- /src/wizard/wizard.js: -------------------------------------------------------------------------------- 1 | /* globals _:false */ 2 | 'use strict'; 3 | angular.module('angularify.semantic.wizard', []) 4 | 5 | .controller('WizardController', ['$scope', 6 | function($scope) { 7 | $scope.steps = []; 8 | $scope.currentStep = null; 9 | $scope.stepsLength = ''; 10 | 11 | $scope.$watch('currentStep', function (step) { 12 | if (!step) return; 13 | var stepTitle = $scope.selectedStep.title; 14 | if ($scope.selectedStep && stepTitle !== $scope.currentStep) { 15 | $scope.goTo($scope.steps.filter(function (step) { 16 | return step.title ==- $scope.currentStep; 17 | })[0]); 18 | } 19 | }); 20 | 21 | $scope.$watch('[editMode, steps.length]', function () { 22 | var editMode = $scope.editMode; 23 | if (editMode === undefined || editMode === null) return; 24 | 25 | if (editMode) { 26 | $scope.steps.forEach(function (step) { 27 | step.completed = true; 28 | }); 29 | } 30 | }, true); 31 | 32 | this.addStep = function (step) { 33 | $scope.steps.push(step); 34 | if ($scope.steps.length === 1) { 35 | $scope.goTo($scope.steps[0]); 36 | } 37 | }; 38 | 39 | $scope.goTo = function (step) { 40 | unselectAll(); 41 | $scope.selectedStep = step; 42 | 43 | if ($scope.currentStep !== undefined) { 44 | $scope.currentStep = step.title; 45 | } 46 | 47 | step.selected = true; 48 | $scope.$emit('wizard:stepChanged', { 49 | step: step, 50 | index: $scope.steps.indexOf(step) 51 | }); 52 | }; 53 | 54 | function unselectAll() { 55 | $scope.steps.forEach(function (step) { 56 | step.selected = false; 57 | }); 58 | $scope.selectedStep = null; 59 | } 60 | 61 | this.next = function () { 62 | var index = $scope.steps.indexOf($scope.selectedStep); 63 | $scope.selectedStep.completed = true; 64 | if (index === $scope.steps.length - 1) { 65 | this.finish(); 66 | } else { 67 | $scope.goTo($scope.steps[index + 1]); 68 | } 69 | }; 70 | 71 | this.goTo = function (step) { 72 | var stepTo; 73 | 74 | if (angular.isNumber(step)) { 75 | stepTo = $scope.steps[step]; 76 | } else { 77 | stepTo = $scope.steps.filter(function (step) { 78 | return step.title === step; 79 | })[0]; 80 | } 81 | $scope.goTo(stepTo); 82 | }; 83 | 84 | this.finish = function() { 85 | if ($scope.onFinish) { 86 | $scope.selectedStep.completed = true; 87 | $scope.onFinish(); 88 | } 89 | }; 90 | 91 | this.cancel = this.previous = function() { 92 | var index = $scope.steps.indexOf($scope.selectedStep); 93 | if (index === 0) { 94 | throw new Error('Cant go back. Its already in step 0'); 95 | } else { 96 | $scope.goTo($scope.steps[index - 1]); 97 | } 98 | }; 99 | 100 | $scope.getStatus = function (step) { 101 | var statusClass = []; 102 | 103 | if (step.selected) 104 | statusClass.push('active'); 105 | if (!step.selected && !step.completed) 106 | statusClass.push('disabled'); 107 | if (step.completed) 108 | statusClass.push('completed'); 109 | 110 | return statusClass; 111 | }; 112 | } 113 | ]) 114 | .directive('wizard', function() { 115 | return { 116 | restrict: 'EA', 117 | replace: true, 118 | transclude: true, 119 | scope: { 120 | fullwidth: "@", 121 | currentStep: '=?', 122 | onFinish: '&', 123 | editMode: '=', 124 | name: '@' 125 | }, 126 | controller: 'WizardController', 127 | template: '
' + 128 | '
' + 129 | '
' + 130 | '{{step.title}}' + 131 | '
' + 132 | '
' + 133 | '' + 134 | '
' + 135 | '
', 136 | link: function(scope, element, attrs, WizardController) { 137 | if (scope.fullwidth === 'true') { 138 | var widthmatrix = { 139 | 0: '', 140 | 1: 'one', 141 | 2: 'two', 142 | 3: 'three', 143 | 4: 'four', 144 | 5: 'five', 145 | 6: 'six', 146 | 7: 'seven', 147 | 8: 'eight', 148 | 9: 'nine', 149 | 10: 'ten' 150 | }; 151 | scope.stepsLength = widthmatrix[scope.steps.length]; 152 | } 153 | 154 | } 155 | }; 156 | }) 157 | .directive('wizardPane', function() { 158 | return { 159 | restrict: 'EA', 160 | replace: true, 161 | transclude: true, 162 | require: '^wizard', 163 | controller: 'WizardController', 164 | scope: { 165 | title: '@' 166 | }, 167 | template: '
', 168 | link: function(scope, element, attrs, WizardController) { 169 | WizardController.addStep(scope); 170 | } 171 | }; 172 | }); 173 | 174 | function wizardButtonDirective(action) { 175 | angular.module('angularify.semantic.wizard') 176 | .directive(action, function () { 177 | return { 178 | restrict: 'A', 179 | replace: false, 180 | require: '^wizard', 181 | link: function ($scope, $element, $attrs, wizard) { 182 | $scope.noMargin = { margin: 0 }; 183 | $element.on('click', function (e) { 184 | e.preventDefault(); 185 | $scope.$apply(function () { 186 | $scope.$eval($attrs[action]); 187 | wizard[action.replace('wz', '').toLowerCase()](); 188 | }); 189 | }); 190 | } 191 | }; 192 | }); 193 | } 194 | 195 | wizardButtonDirective('wzNext'); 196 | wizardButtonDirective('wzPrevious'); 197 | wizardButtonDirective('wzFinish'); 198 | wizardButtonDirective('wzCancel'); 199 | --------------------------------------------------------------------------------