diff --git a/index.html b/index.html new file mode 100644 index 0000000..dfcc3bd --- /dev/null +++ b/index.html @@ -0,0 +1,85 @@ + + + + + + Document + + + + + + + + + + + + + Level 1 + + +

Welcome to level 1

+ + + + Level 1A + + + + Level 1A Contents + + + + + Level 1A-A + + + Level 1A-A Contents + + + + Level 1A-B + + + Level 1A-B Contents + + + + + + + Level 1B + + + Level 1B Contents + + + + Level 1C + + + Level 1C Contents + + + +
+ + + Level 2 + + +

Welcome to level 2

+
+ + + Level 3 + + +

Welcome to level 3

+
+
+ + + + \ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js index bac5982..c81af87 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,91 +1,90 @@ module.exports = function(config) { - config.set({ + config.set({ - // base path that will be used to resolve all patterns (eg. files, exclude) - basePath: '', + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', - // frameworks to use - // available frameworks: https://npmjs.org/browse/keyword/karma-adapter - frameworks: ['jasmine'], + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], - // list of files / patterns to load in the browser - files: [ - './node_modules/jquery/dist/jquery.js', - './node_modules/phantomjs-polyfill/bind-polyfill.js', - './node_modules/angular/angular.js', - './node_modules/angular-mocks/angular-mocks.js', - { pattern: 'spec.bundle.js', watched: false } - ], + // list of files / patterns to load in the browser + files: [ + './node_modules/jquery/dist/jquery.js', + './node_modules/phantomjs-polyfill/bind-polyfill.js', + './node_modules/angular/angular.js', + './node_modules/angular-mocks/angular-mocks.js', + { pattern: 'spec.bundle.js', watched: false } + ], - // list of files to exclude - exclude: [ - ], + // list of files to exclude + exclude: [], - plugins: [ - require("karma-phantomjs-launcher"), - require("karma-sourcemap-loader"), - require('karma-jasmine'), - require('karma-webpack') - ], + plugins: [ + require("karma-phantomjs-launcher"), + require("karma-sourcemap-loader"), + require('karma-jasmine'), + require('karma-webpack') + ], - // preprocess matching files before serving them to the browser - // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor - preprocessors: { - 'spec.bundle.js': ['webpack', 'sourcemap'] - }, + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + 'spec.bundle.js': ['webpack', 'sourcemap'] + }, - webpack: { - devtools: 'inline-source-map', - module: { - preLoaders: [ - { test: /\.ts$/, exclude: /node_modules/, loader: 'tslint-loader' } - ], - loaders: [ - { test: /\.ts?$/, exclude: /node_modules/, loader: 'ts-loader' }, - { test: /\.json?$/, exclude: /node_modules/, loader: 'json-loader' } - ] - }, - tslint: { - configuration: require('./tslint.json') - }, - resolve: { - extensions: ['', '.ts', '.js'] - } - }, + webpack: { + devtools: 'inline-source-map', + module: { + preLoaders: [ + { test: /\.ts$/, exclude: /node_modules/, loader: 'tslint-loader' } + ], + loaders: [ + { test: /\.ts?$/, exclude: /node_modules/, loader: 'ts-loader' }, + { test: /\.json?$/, exclude: /node_modules/, loader: 'json-loader' } + ] + }, + tslint: { + configuration: require('./tslint.json') + }, + resolve: { + extensions: ['', '.ts', '.js'] + } + }, - // test results reporter to use - // possible values: 'dots', 'progress' - // available reporters: https://npmjs.org/browse/keyword/karma-reporter - reporters: ['progress'], + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], - // web server port - port: 9876, + // web server port + port: 9876, - // enable / disable colors in the output (reporters and logs) - colors: true, + // enable / disable colors in the output (reporters and logs) + colors: true, - // level of logging - // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, - // enable / disable watching file and executing tests whenever any file changes - autoWatch: false, + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, - // start these browsers - // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher - browsers: ['PhantomJS'], + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['PhantomJS'], - // Continuous Integration mode - // if true, Karma captures browsers, runs the tests and exits - singleRun: true - }); -}; + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: true + }); +}; \ No newline at end of file diff --git a/package.json b/package.json index ae42d2d..d0d135f 100644 --- a/package.json +++ b/package.json @@ -1,57 +1,60 @@ { - "name": "semantic-ui-angular", - "version": "0.0.0", - "description": "Pure AngularJS directives to support Semantic-UI components", - "main": "index.js", - "scripts": { - "postinstall": "node_modules/.bin/tsd install", - "test": "node_modules/karma/bin/karma start", - "test-dev": "./node_modules/karma/bin/karma start --auto-watch --no-single-run", - "build": "rm -rf dist && node_modules/.bin/webpack" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/Semantic-Org/Semantic-UI-Angular" - }, - "keywords": [ - "angularjs", - "semantic-ui", - "directives", - "components", - "typescript" - ], - "author": "", - "license": "MIT", - "bugs": { - "url": "https://github.com/Semantic-Org/Semantic-UI-Angular/issues" - }, - "homepage": "https://github.com/Semantic-Org/Semantic-UI-Angular#readme", - "devDependencies": { - "angular": "1.4.8", - "angular-mocks": "1.4.8", - "cz-conventional-changelog": "^1.1.5", - "jasmine-core": "2.4.1", - "jquery": "2.2.0", - "jscs": "2.8.0", - "jscs-loader": "0.2.0", - "json-loader": "0.5.4", - "karma": "0.13.19", - "karma-jasmine": "0.3.6", - "karma-phantomjs-launcher": "0.2.3", - "karma-sourcemap-loader": "0.3.6", - "karma-webpack": "1.7.0", - "phantomjs": "1.9.19", - "phantomjs-polyfill": "0.0.1", - "ts-loader": "0.7.2", - "tsd": "0.6.5", - "tslint": "3.2.1", - "tslint-loader": "2.1.0", - "typescript": "1.7.5", - "webpack": "1.12.10" - }, - "config": { - "commitizen": { - "path": "./node_modules/cz-conventional-changelog" + "name": "semantic-ui-angular", + "version": "0.0.0", + "description": "Pure AngularJS directives to support Semantic-UI components", + "main": "index.js", + "scripts": { + "postinstall": "node_modules/.bin/tsd install", + "test": "karma start", + "test-dev": "karma start --auto-watch --no-single-run", + "build": "rimraf dist && webpack", + "start": "webpack-dev-server --inline --progress --port 8080" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Semantic-Org/Semantic-UI-Angular" + }, + "keywords": [ + "angularjs", + "semantic-ui", + "directives", + "components", + "typescript" + ], + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/Semantic-Org/Semantic-UI-Angular/issues" + }, + "homepage": "https://github.com/Semantic-Org/Semantic-UI-Angular#readme", + "devDependencies": { + "angular": "1.6.1", + "angular-mocks": "1.6.1", + "cz-conventional-changelog": "^1.1.5", + "jasmine-core": "2.5.2", + "jquery": "3.1.1", + "jscs": "3.0.7", + "jscs-loader": "0.3.0", + "json-loader": "0.5.4", + "karma": "1.3.0", + "karma-jasmine": "1.1.0", + "karma-phantomjs-launcher": "1.0.2", + "karma-sourcemap-loader": "0.3.7", + "karma-webpack": "1.8.1", + "phantomjs": "2.1.7", + "phantomjs-polyfill": "0.0.2", + "rimraf": "^2.5.4", + "ts-loader": "1.3.3", + "tsd": "0.6.5", + "tslint": "4.2.0", + "tslint-loader": "3.3.0", + "typescript": "2.1.4", + "webpack": "1.14.0", + "webpack-dev-server": "^1.16.2" + }, + "config": { + "commitizen": { + "path": "./node_modules/cz-conventional-changelog" + } } - } } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 091759c..8939ce1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,7 @@ /// + +import { smAccordionModule } from './modules/accordion/accordion.module'; import { smButtonModule } from './elements/button/button'; import { smRatingModule } from './modules/rating/rating'; import { smDividerModule } from './elements/divider/divider'; @@ -11,7 +13,9 @@ import { smDividerModule } from './elements/divider/divider'; .module('semantic.ui', [ smButtonModule.name, smRatingModule.name, - smDividerModule.name + smDividerModule.name, + + smAccordionModule.name ]); })(); diff --git a/src/modules/accordion/accordion.module.ts b/src/modules/accordion/accordion.module.ts new file mode 100644 index 0000000..3fc4936 --- /dev/null +++ b/src/modules/accordion/accordion.module.ts @@ -0,0 +1,130 @@ +/// + +'use strict'; + +interface ISmAccordionSettings { + exclusive: Boolean, + on: String, + animateChildren: Boolean, + closeNested: Boolean, + collapsible: Boolean, + duration: Number, + easing: String +} + +const accordionSettings: ISmAccordionSettings = { + exclusive: true, + on: 'click', + animateChildren: true, + closeNested: true, + collapsible: true, + duration: 500, + easing: 'easeInOutQuint' +}; + +class SmAccordionController { + static $inject = ['$scope', '$element', '$attrs']; + + ngModel: ng.INgModelController; + accordionGroups = []; + + constructor(public $scope: ng.IScope, public $element: ng.IAugmentedJQuery, public $attrs) { + + } + + addGroup = function (element) { + this.accordionGroups.push(element); + } + setActive = function (title) { + + var content = this.accordionGroups[this.accordionGroups.indexOf(title) + 1]; + + if (content && content.hasClass('content')) { + content.toggleClass('active'); + } + title.toggleClass('active'); + + if (accordionSettings.exclusive) { + this.accordionGroups.forEach(e => { + if (e != title && e != content) + e.removeClass('active') + }); + } + } +} + +class SmAccordionDirective implements ng.IDirective { + static instance(): ng.IDirective { + return new SmAccordionDirective; + } + + restrict = 'E'; + controller = SmAccordionController; + controllerAs = 'accordion'; + replace = true; + transclude = true; + template = '
'; + link = ( + scope: ng.IScope, + element: ng.IAugmentedJQuery, + attrs + ) => { + + }; +} + +class SmAccordionTitleDirective implements ng.IDirective { + static instance(): ng.IDirective { + return new SmAccordionTitleDirective; + } + + restrict = 'E'; + replace = true; + transclude = true; + require = '^smAccordion'; + + template = '
'; + + link = ( + scope: ng.IScope, + element: ng.IAugmentedJQuery, + attrs, + ctrl + ) => { + ctrl.addGroup(element); + + element.bind('click', () => { + ctrl.setActive(element); + }); + + }; +} + +class SmAccordionContentDirective implements ng.IDirective { + static instance(): ng.IDirective { + return new SmAccordionContentDirective; + } + + restrict = 'E'; + replace = true; + transclude = true; + require = '^smAccordion'; + + template = '
'; + link = ( + scope: ng.IScope, + element: ng.IAugmentedJQuery, + attrs, + ctrl + ) => { + ctrl.addGroup(element); + }; +} + + +export const smAccordionModule = angular + .module('semantic.ui.modules.accordion', []) + .directive('smAccordion', SmAccordionDirective.instance) + .directive('smAccordionTitle', SmAccordionTitleDirective.instance) + .directive('smAccordionContent', SmAccordionContentDirective.instance) + .constant('smAccordionSettings', accordionSettings); diff --git a/src/modules/accordion/accordion.spec.ts b/src/modules/accordion/accordion.spec.ts new file mode 100644 index 0000000..bde5f1f --- /dev/null +++ b/src/modules/accordion/accordion.spec.ts @@ -0,0 +1,180 @@ +/// +/// + +import { smAccordionModule } from './accordion.module'; + +describe('Semantic-UI: Components - smAccordion', function () { + 'use strict'; + + let $scope, $compile, element, settings; + + beforeEach(angular.mock.module(smAccordionModule.name)); + + beforeEach(inject(function ($rootScope, $injector, smAccordionSettings) { + $scope = $rootScope.$new(); + $compile = $injector.get('$compile'); + element = $compile(template)($scope); + settings = smAccordionModule; + $scope.$digest(); + })); + + it('expected elements length', function () { + expect(element.find('.title').length).toBe(8); + expect(element.find('.content').length).toBe(8); + }); + + it('no one active by default', function () { + expect(element.find('.active').length).toBe(0); + }); + + it('all title have icon', function () { + expect(element.find('.title:first').children('i.icon').length).toBe(1); + }); + + + it('open first group', function () { + var firstTitle = element.find('.title:first'); + firstTitle.click(); + $scope.$digest(); + + expect(firstTitle.hasClass('active')).toBe(true); + expect(firstTitle.next().hasClass('active')).toBe(true); + + var activeTitle = element.find('.title.active'); + expect(activeTitle.length > 0).toBe(true); + activeTitle.click(); + $scope.$digest(); + expect(element.find('.title.active').length).toBe(0); + expect(element.find('.content.active').length).toBe(0); + + }); + + it('exclusive setting', function () { + var firstTitle = element.find('.title:first'); + var lastTitle = element.find('.title:last'); + firstTitle.click(); + $scope.$digest(); + + expect(firstTitle.hasClass('active')).toBe(true); + expect(firstTitle.next().hasClass('active')).toBe(true); + + lastTitle.click(); + $scope.$digest(); + + expect(firstTitle.hasClass('active')).toBe(false); + expect(firstTitle.next().hasClass('active')).toBe(false); + expect(lastTitle.hasClass('active')).toBe(true); + expect(lastTitle.next().hasClass('active')).toBe(true); + + }); + +}); + +describe('Semantic-UI: Components - smAccordion - Custom Settings', function () { + 'use strict'; + + let $scope, $compile, element; + let settings = { + exclusive: false + } + + beforeEach(angular.mock.module(smAccordionModule.name)); + + beforeEach(inject(function ($rootScope, $injector, smAccordionSettings) { + $scope = $rootScope.$new(); + $compile = $injector.get('$compile'); + element = $compile(template)($scope); + angular.extend(smAccordionSettings, settings); + $scope.$digest(); + })); + + + + it('exclusive setting is false', function () { + var firstTitle = element.find('.title:first'); + var lastTitle = element.find('.title:last'); + firstTitle.click(); + $scope.$digest(); + + expect(firstTitle.hasClass('active')).toBe(true); + expect(firstTitle.next().hasClass('active')).toBe(true); + + lastTitle.click(); + $scope.$digest(); + + expect(firstTitle.hasClass('active')).toBe(true); + expect(firstTitle.next().hasClass('active')).toBe(true); + expect(lastTitle.hasClass('active')).toBe(true); + expect(lastTitle.next().hasClass('active')).toBe(true); + + }); + +}); + + +var template = ` + + + Level 1 + + +

Welcome to level 1

+ + + + Level 1A + + + + Level 1A Contents + + + + + Level 1A-A + + + Level 1A-A Contents + + + + Level 1A-B + + + Level 1A-B Contents + + + + + + + Level 1B + + + Level 1B Contents + + + + Level 1C + + + Level 1C Contents + + + +
+ + + Level 2 + + +

Welcome to level 2

+
+ + + Level 3 + + +

Welcome to level 3

+
+
`; \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index e493a20..67a6a63 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -3,46 +3,46 @@ var webpack = require('webpack'); var VERSION = require('./package.json').version; var banner = - '/*!\n' + - ' * Semantic-UI AngularJS integration\n' + - ' * https://github.com/semantic-org/semantic-ui-angular\n' + - ' * @license MIT\n' + - ' * v' + VERSION + '\n' + - ' */\n'; + '/*!\n' + + ' * Semantic-UI AngularJS integration\n' + + ' * https://github.com/semantic-org/semantic-ui-angular\n' + + ' * @license MIT\n' + + ' * v' + VERSION + '\n' + + ' */\n'; module.exports = { - context: path.resolve('src'), - devtool: "source-map", - entry: { - 'semantic-ui-angular': './index', - 'semantic-ui-angular.min': './index' - }, - output: { - path: path.resolve('dist'), - filename: '[name].js' - }, - plugins: [ - new webpack.optimize.UglifyJsPlugin({ - include: /\.min\.js$/, - minimize: true - }), - new webpack.BannerPlugin(banner, {raw: true}) - ], - module: { - preLoaders: [ - { test: /\.ts$/, exclude: /node_modules/, loader: 'tslint-loader' }, - // TODO(m0t0r): JSCS complains on TS code, decide if we actually can/need make it work - //{ test: /\.ts$/, exclude: /node_modules/, loader: 'jscs-loader' } + context: path.resolve('src'), + devtool: "source-map", + entry: { + 'semantic-ui-angular': './index', + 'semantic-ui-angular.min': './index' + }, + output: { + path: path.resolve('dist'), + filename: '[name].js' + }, + plugins: [ + // new webpack.optimize.UglifyJsPlugin({ + // include: /\.min\.js$/, + // minimize: true + // }), + // new webpack.BannerPlugin(banner, {raw: true}) ], - loaders: [ - { test: /\.ts?$/, exclude: /node_modules/, loader: 'ts-loader' }, - { test: /\.json?$/, exclude: /node_modules/, loader: 'json-loader' } - ] - }, - tslint: { - configuration: require('./tslint.json') - }, - resolve: { - extensions: ['', '.ts', '.js'] - } -}; + module: { + preLoaders: [ + { test: /\.ts$/, exclude: /node_modules/, loader: 'tslint-loader' }, + // TODO(m0t0r): JSCS complains on TS code, decide if we actually can/need make it work + //{ test: /\.ts$/, exclude: /node_modules/, loader: 'jscs-loader' } + ], + loaders: [ + { test: /\.ts?$/, exclude: /node_modules/, loader: 'ts-loader' }, + { test: /\.json?$/, exclude: /node_modules/, loader: 'json-loader' } + ] + }, + tslint: { + configuration: require('./tslint.json') + }, + resolve: { + extensions: ['', '.ts', '.js'] + } +}; \ No newline at end of file