From e2c31318da273d036d3ecc5a0779a26e42930590 Mon Sep 17 00:00:00 2001 From: Scott Trenda Date: Tue, 21 Aug 2018 11:36:13 -0500 Subject: [PATCH 1/4] Add template overwriting, ctrl/innerScope --- dist/tool-box.js | 17 ++++++++++++----- src/directive-helper.js | 17 ++++++++++++----- test/directive-helper-test.js | 17 +++++++++++++++++ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/dist/tool-box.js b/dist/tool-box.js index 761bbac..ea292ac 100644 --- a/dist/tool-box.js +++ b/dist/tool-box.js @@ -115,7 +115,7 @@ angular.module('jdalt.toolBox') options = (typeof options == 'boolean') ? { flushRequests: options } : options || {} - return function compile(scopeParams, overrideOptions) { + return angular.extend(function compile(scopeParams, overrideOptions) { scopeParams = scopeParams || {} var scope = $rootScope.$new() @@ -125,13 +125,20 @@ angular.module('jdalt.toolBox') var cloneAttachFn if (callOptions.attach) cloneAttachFn = function(clone) { clone.appendTo('body') } - var el = $compile(tmpl)(scope, cloneAttachFn) + var el = $compile(callOptions.template || compile.template)(scope, cloneAttachFn) scope.$digest() if (callOptions.flushRequests) $httpBackend.flush() - - return angular.extend({ scope: scope }, DomHelper(el)) - } + var innerScope = el.isolateScope() + + return angular.extend({ + scope: scope, + innerScope: innerScope, + ctrl: innerScope && (innerScope.$ctrl || innerScope.ctrl) + }, DomHelper(el)) + }, { + template: tmpl + }) } diff --git a/src/directive-helper.js b/src/directive-helper.js index 63f3b1e..03fda00 100644 --- a/src/directive-helper.js +++ b/src/directive-helper.js @@ -10,7 +10,7 @@ angular.module('jdalt.toolBox') options = (typeof options == 'boolean') ? { flushRequests: options } : options || {} - return function compile(scopeParams, overrideOptions) { + return angular.extend(function compile(scopeParams, overrideOptions) { scopeParams = scopeParams || {} var scope = $rootScope.$new() @@ -20,13 +20,20 @@ angular.module('jdalt.toolBox') var cloneAttachFn if (callOptions.attach) cloneAttachFn = function(clone) { clone.appendTo('body') } - var el = $compile(tmpl)(scope, cloneAttachFn) + var el = $compile(callOptions.template || compile.template)(scope, cloneAttachFn) scope.$digest() if (callOptions.flushRequests) $httpBackend.flush() - - return angular.extend({ scope: scope }, DomHelper(el)) - } + var innerScope = el.isolateScope() + + return angular.extend({ + scope: scope, + innerScope: innerScope, + ctrl: innerScope && (innerScope.$ctrl || innerScope.ctrl) + }, DomHelper(el)) + }, { + template: tmpl + }) } diff --git a/test/directive-helper-test.js b/test/directive-helper-test.js index 24c14e4..14d9395 100644 --- a/test/directive-helper-test.js +++ b/test/directive-helper-test.js @@ -21,6 +21,23 @@ describe('DirectiveHelper', function() { dom = compile(null, { attach: true }) expect(angular.element('#simp-main').length).toEqual(1) // angular.element searches from the body }) + + it('should allow overwriting the template on the compile function', function() { + compile.template = '
' + dom = compile() + expect(dom.$el.attr('test-attr')).toBe('1') + }) + + it('should allow overwriting the template on the compile options', function() { + dom = compile(null, { template: '
' }) + expect(dom.$el.attr('test-attr')).toBe('2') + }) + + it('should set scope, innerScope, and ctrl on dom', function() { + dom = compile() + expect(dom.innerScope).toBe(dom.$el.isolateScope()) + expect(dom.ctrl).toBe(dom.$el.isolateScope().ctrl) + }) }) describe('for directives that accept scope parameters', function() { From 0bd2ac4464fead09200b8f8bc23b6fb6d18ca0d5 Mon Sep 17 00:00:00 2001 From: Scott Trenda Date: Tue, 21 Aug 2018 11:36:22 -0500 Subject: [PATCH 2/4] Fix isPath detection --- dist/tool-box.js | 2 +- src/request-helper.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/tool-box.js b/dist/tool-box.js index ea292ac..5ec8ab5 100644 --- a/dist/tool-box.js +++ b/dist/tool-box.js @@ -445,7 +445,7 @@ angular.module('jdalt.toolBox') } function isPath(def) { - return def[0] == '/' + return /^(https?:)?\//i.test(def) } function urlFromPath(method, path, params) { diff --git a/src/request-helper.js b/src/request-helper.js index d1f91be..96dc51d 100644 --- a/src/request-helper.js +++ b/src/request-helper.js @@ -66,7 +66,7 @@ angular.module('jdalt.toolBox') } function isPath(def) { - return def[0] == '/' + return /^(https?:)?\//i.test(def) } function urlFromPath(method, path, params) { From 4b74080a19218ddbdf684c55eb613e0627fa6926 Mon Sep 17 00:00:00 2001 From: Scott Trenda Date: Thu, 11 Oct 2018 14:44:15 -0500 Subject: [PATCH 3/4] Add support for suffixes in resource definitions --- dist/tool-box.js | 11 +++++++---- src/request-helper.js | 11 +++++++---- test/dummy-js-data/js-data-directive.js | 3 ++- test/js-data-request-test.js | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/dist/tool-box.js b/dist/tool-box.js index 5ec8ab5..f8d76b5 100644 --- a/dist/tool-box.js +++ b/dist/tool-box.js @@ -402,10 +402,10 @@ angular.module('jdalt.toolBox') baseResourceFinder ) { - var DSHttpAdapter + var DS, DSHttpAdapter var resourceDefs = {} - if($injector.has('DS') && $injector.has('DS')) { - var DS = $injector.get('DS') + if($injector.has('DS') && $injector.get('DS')) { + DS = $injector.get('DS') DSHttpAdapter = $injector.get('DSHttpAdapter') resourceDefs = DS.definitions } @@ -471,7 +471,10 @@ angular.module('jdalt.toolBox') var resourceBase = baseResourceFinder(def) var path = DSHttpAdapter.getPath(method, resourceBase, params, { params: params }) - return completePath(method, path, params) // params gets mutated by getPath, parent params (for nested routes) get stripped out when they are used + path = completePath(method, path, params) // params gets mutated by getPath, parent params (for nested routes) get stripped out when they are used + var suffix = resourceBase.suffix + if (suffix && !~path.indexOf(suffix)) path = path.replace(/(\?.*)?$/, suffix + '$1') // this is done in each js-data-http method, yuck + return path } function omit(sourceObj, keys) { diff --git a/src/request-helper.js b/src/request-helper.js index 96dc51d..1f3eb10 100644 --- a/src/request-helper.js +++ b/src/request-helper.js @@ -23,10 +23,10 @@ angular.module('jdalt.toolBox') baseResourceFinder ) { - var DSHttpAdapter + var DS, DSHttpAdapter var resourceDefs = {} - if($injector.has('DS') && $injector.has('DS')) { - var DS = $injector.get('DS') + if($injector.has('DS') && $injector.get('DS')) { + DS = $injector.get('DS') DSHttpAdapter = $injector.get('DSHttpAdapter') resourceDefs = DS.definitions } @@ -92,7 +92,10 @@ angular.module('jdalt.toolBox') var resourceBase = baseResourceFinder(def) var path = DSHttpAdapter.getPath(method, resourceBase, params, { params: params }) - return completePath(method, path, params) // params gets mutated by getPath, parent params (for nested routes) get stripped out when they are used + path = completePath(method, path, params) // params gets mutated by getPath, parent params (for nested routes) get stripped out when they are used + var suffix = resourceBase.suffix + if (suffix && !~path.indexOf(suffix)) path = path.replace(/(\?.*)?$/, suffix + '$1') // this is done in each js-data-http method, yuck + return path } function omit(sourceObj, keys) { diff --git a/test/dummy-js-data/js-data-directive.js b/test/dummy-js-data/js-data-directive.js index eba55d3..63c9eee 100644 --- a/test/dummy-js-data/js-data-directive.js +++ b/test/dummy-js-data/js-data-directive.js @@ -22,7 +22,8 @@ angular.module('dummy-js-data') DS.defineResource({ name: 'monkey', - endpoint: '/bed/monkeys' + endpoint: '/bed/monkeys', + suffix: '.json' }) DS.defineResource({ diff --git a/test/js-data-request-test.js b/test/js-data-request-test.js index 5df95a7..6c3694c 100644 --- a/test/js-data-request-test.js +++ b/test/js-data-request-test.js @@ -76,7 +76,7 @@ describe('JsData Request', function() { }) it('should request monkey and display monkey names
  • ', function() { - Req.expectMany('/api/bed/monkeys', { bunch: 10 }, { result: [{ id: 1, name: 'Monkey 1' }, { id: 2, name: 'Monkey 2'}] }) + Req.expectMany('/api/bed/monkeys.json', { bunch: 10 }, { result: [{ id: 1, name: 'Monkey 1' }, { id: 2, name: 'Monkey 2'}] }) dom.click('#monkey-button').flush() expect(dom.text('ul li')).toContain('Monkey 1') From c05e103a16a8449ee57024012c2cb16a871893b0 Mon Sep 17 00:00:00 2001 From: Scott Trenda Date: Wed, 24 Oct 2018 11:03:39 -0500 Subject: [PATCH 4/4] Add checkbox+option support to setInputValue --- dist/tool-box.js | 31 ++++++++++++++++++++++++++++--- src/dom-helper.js | 31 ++++++++++++++++++++++++++++--- test/dom-helper-test.js | 31 +++++++++++++++++++++++++++++++ test/dummy/multi-dom-directive.js | 9 +++++++++ 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/dist/tool-box.js b/dist/tool-box.js index f8d76b5..8d1e938 100644 --- a/dist/tool-box.js +++ b/dist/tool-box.js @@ -155,11 +155,36 @@ angular.module('jdalt.toolBox') function DomHelper(root) { + var booleanInputs = 'input[type=checkbox], input[type=radio], option' + function normalizeText(str) { if (typeof str !== 'string') throw new Error('normalizeWhitespace called with a non-string argument: ' + typeof str) return str.replace(/\s+/g, ' ').trim() } + function getVal(input) { + input = input.first() + return input.is(booleanInputs) ? input.prop(input.is('option') ? 'selected' : 'checked') : input.val() + } + function setVal(input, value) { + // input.focus() // triggers directive binding + input.filter(booleanInputs).each(setBooleanInput) + input.not(booleanInputs).val(value).triggerHandler('change')//.triggerHandler('blur') + + function setBooleanInput() { + var $input = angular.element(this) + var isOption = input.is('option') + var prop = isOption ? 'selected' : 'checked' + var $changer = isOption ? $input.parents('select') : $input + + var triggerChange = !!value !== $input.prop(prop) + $input.prop(prop, !!value) // Force attribute state for $setViewValue + if (!isOption) $input.triggerHandler('click') // Trigger click handler (will call $setViewValue) + if (triggerChange) $changer.triggerHandler('change') + // if (scope) scope.$digest() // just in case something is $watching + } + } + return { $el: root, // jQuery wrapped element @@ -236,13 +261,13 @@ angular.module('jdalt.toolBox') throw new Error('Element "'+ selector +'" not found to setInputValue') } - inputEl.val(inputVal).trigger('change') + setVal(inputEl, inputVal) return DomHelper(inputEl) }, val: function(value) { - if(arguments.length > 0) root.val(value).trigger('change') - return root.val() + if(arguments.length > 0) setVal(root, value) + return getVal(root) }, cssClasses: function() { diff --git a/src/dom-helper.js b/src/dom-helper.js index 068db5c..ac52b4b 100644 --- a/src/dom-helper.js +++ b/src/dom-helper.js @@ -5,11 +5,36 @@ angular.module('jdalt.toolBox') function DomHelper(root) { + var booleanInputs = 'input[type=checkbox], input[type=radio], option' + function normalizeText(str) { if (typeof str !== 'string') throw new Error('normalizeWhitespace called with a non-string argument: ' + typeof str) return str.replace(/\s+/g, ' ').trim() } + function getVal(input) { + input = input.first() + return input.is(booleanInputs) ? input.prop(input.is('option') ? 'selected' : 'checked') : input.val() + } + function setVal(input, value) { + // input.focus() // triggers directive binding + input.filter(booleanInputs).each(setBooleanInput) + input.not(booleanInputs).val(value).triggerHandler('change')//.triggerHandler('blur') + + function setBooleanInput() { + var $input = angular.element(this) + var isOption = input.is('option') + var prop = isOption ? 'selected' : 'checked' + var $changer = isOption ? $input.parents('select') : $input + + var triggerChange = !!value !== $input.prop(prop) + $input.prop(prop, !!value) // Force attribute state for $setViewValue + if (!isOption) $input.triggerHandler('click') // Trigger click handler (will call $setViewValue) + if (triggerChange) $changer.triggerHandler('change') + // if (scope) scope.$digest() // just in case something is $watching + } + } + return { $el: root, // jQuery wrapped element @@ -86,13 +111,13 @@ angular.module('jdalt.toolBox') throw new Error('Element "'+ selector +'" not found to setInputValue') } - inputEl.val(inputVal).trigger('change') + setVal(inputEl, inputVal) return DomHelper(inputEl) }, val: function(value) { - if(arguments.length > 0) root.val(value).trigger('change') - return root.val() + if(arguments.length > 0) setVal(root, value) + return getVal(root) }, cssClasses: function() { diff --git a/test/dom-helper-test.js b/test/dom-helper-test.js index 4a6ce62..f12bc54 100644 --- a/test/dom-helper-test.js +++ b/test/dom-helper-test.js @@ -102,6 +102,37 @@ describe('DomHelper', function() { expect(dom.text('#deep-thought-val')).toBe('Fun Fun Fun') }) + it('should setInputValue on checkbox input', function() { + expect(dom.text('#check-val')).toBe('') + dom.setInputValue('#check-el', true) + expect(dom.text('#check-val')).toBe('true') + expect(dom.find('#check-el').val()).toBe(true) + dom.setInputValue('#check-el', null) + expect(dom.text('#check-val')).toBe('false') + expect(dom.find('#check-el').val()).toBe(false) + }) + + it('should setInputValue on select', function() { + expect(dom.text('#sel-val')).toBe('') + dom.setInputValue('#sel-el', 'string:rock') + expect(dom.text('#sel-val')).toBe('rock') + dom.setInputValue('#sel-el', 'string:glam') + expect(dom.text('#sel-val')).toBe('glam') + }) + + it('should setInputValue on option', function() { + expect(dom.text('#sel-val')).toBe('') + dom.setInputValue('#sel-el option:eq(1)', true) + expect(dom.text('#sel-val')).toBe('prog') + expect(dom.find('#sel-el option:eq(1)').val()).toBe(true) + dom.setInputValue('#sel-el option:eq(2)', true) + expect(dom.text('#sel-val')).toBe('rock') + expect(dom.find('#sel-el option:eq(2)').val()).toBe(true) + dom.setInputValue('#sel-el option:eq(2)', false) + expect(dom.text('#sel-val')).toBe('') + expect(dom.find('#sel-el option:eq(2)').val()).toBe(false) + }) + it('should set input val() on input#deep-thought-inp', function() { expect(dom.text('#deep-thought-val')).toBe('42') var ret = dom.find('#deep-thought-inp').val('Fun Fun Fun') diff --git a/test/dummy/multi-dom-directive.js b/test/dummy/multi-dom-directive.js index acba778..52cab62 100644 --- a/test/dummy/multi-dom-directive.js +++ b/test/dummy/multi-dom-directive.js @@ -15,7 +15,11 @@ angular.module('dummy') '
  • Thing 3
  • \n' + ' \n' + ' \n' + + ' \n' + + ' \n' + '
    {{ ctrl.allThought }}
    \n' + + '
    {{ ctrl.checkVal }}
    \n' + + '
    {{ ctrl.selVal }}
    \n' + '
    \n' + '
    \n', controllerAs: 'ctrl', @@ -23,6 +27,11 @@ angular.module('dummy') var vm = this vm.allThought = '42' + vm.opts = { + Rush: 'prog', + Queen: 'rock', + Kiss: 'glam' + } } }