From 745623722a71399fbe8b07fc6b9eac51f96d2e74 Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Fri, 16 Nov 2018 16:50:46 -0500 Subject: [PATCH 01/10] add mouse event details gridPoint, clientPoint, and pagePoint --- src/Hypergrid/events.js | 21 ++++++++++++++++++++- src/lib/dispatchGridEvent.js | 3 +++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Hypergrid/events.js b/src/Hypergrid/events.js index 0f0f8db20..3c360fc7b 100644 --- a/src/Hypergrid/events.js +++ b/src/Hypergrid/events.js @@ -458,6 +458,25 @@ exports.mixin = { writable: true } ); + + // add some interesting mouse offsets + var drilldown; + if ((drilldown = primitiveEvent.primitiveEvent && primitiveEvent.primitiveEvent.detail)) { + decoratedEvent.gridPoint = drilldown.mouse; + if ((drilldown = drilldown.primitiveEvent)) { + decoratedEvent.clientPoint = { + x: drilldown.clientX, + y: drilldown.clientY + }; + decoratedEvent.pagePoint = { + x: drilldown.clientX + window.scrollX, + y: drilldown.clientY + window.scrollY + }; + } + } + + + cb.call(grid, decoratedEvent); } } @@ -576,7 +595,7 @@ exports.mixin = { }); this.addInternalEventListener('fin-canvas-context-menu', function(e) { - handleMouseEvent(e, function(mouseEvent){ + handleMouseEvent(e, function(mouseEvent) { grid.delegateContextMenu(mouseEvent); grid.fireSyntheticContextMenuEvent(mouseEvent); }); diff --git a/src/lib/dispatchGridEvent.js b/src/lib/dispatchGridEvent.js index 80a5a626d..a71c1320e 100644 --- a/src/lib/dispatchGridEvent.js +++ b/src/lib/dispatchGridEvent.js @@ -6,6 +6,9 @@ var details = [ 'gridCell', 'dataCell', 'mousePoint', + 'gridPoint', + 'clientPoint', + 'pagePoint', 'keys', 'row' ]; From ca5f6fb2d2dadca81c9bfbdec037e9b30b73b243 Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Thu, 15 Nov 2018 01:05:35 -0500 Subject: [PATCH 02/10] add versionAtLeast function to all classes descended from Base --- src/Base.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Base.js b/src/Base.js index 40fb2c335..7bb5eecf3 100644 --- a/src/Base.js +++ b/src/Base.js @@ -19,14 +19,16 @@ Object.defineProperty(Base.prototype, 'version', { value: require('../package.json').version }); -Base.prototype.atLeastVersion = function(neededVersion) { - var neededParts = neededVersion.split('.'), - thisParts = this.version.split('.'), - delta; - neededParts.find(function(neededPart, i) { - return (delta = neededPart - thisParts[i]); - }); - return delta >= 0; +Base.prototype.versionAtLeast = function(neededVersion) { + var neededParts = neededVersion.split('.').map(Number), + delta = this.version.split('.').map(function(part, i) { return Number(part) - neededParts[i]; }); + return ( + delta[0] > 0 || + delta[0] === 0 && ( + delta[1] > 0 || + delta[1] === 0 && delta[2] >= 0 + ) + ); }; Base.prototype.deprecated = require('./lib/deprecated'); From 410ecbf9154e56d33d4a792cfc7b381c2de6806c Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Sat, 17 Nov 2018 00:47:25 -0500 Subject: [PATCH 03/10] add Registry#make --- src/lib/Registry.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lib/Registry.js b/src/lib/Registry.js index 6321dc1a3..b5bbec977 100644 --- a/src/lib/Registry.js +++ b/src/lib/Registry.js @@ -32,6 +32,7 @@ var Registry = Base.extend('Registry', { return; } + // getClassName defined if new item derived from extend-me name = name || item.getClassName && item.getClassName(); if (!name) { @@ -60,6 +61,16 @@ var Registry = Base.extend('Registry', { return (this.items[synonymName] = this.items[existingName]); }, + /** + * Create a new item extended from base class. For formal parameters, see {@link Registry#add add}. + * @memberOf Registry# + */ + make: function(name, prototype) { + var last = arguments.length - 1; + arguments[last] = this.BaseClass.extend(arguments[last]); + this.add.apply(this, arguments); + }, + /** * Fetch a registered item. * @param {string} [name] From 9045d5d0028d4382442f018fda277b20808f1b69 Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Sat, 17 Nov 2018 00:45:24 -0500 Subject: [PATCH 04/10] encode svg & ico files; theme svg images and create rules --- gulpfile.js | 2 +- images/index.js | 129 ++++++++++++++++++++++++++++++++++++---- package.json | 3 +- src/Hypergrid/themes.js | 64 ++++++++++---------- 4 files changed, 153 insertions(+), 45 deletions(-) diff --git a/gulpfile.js b/gulpfile.js index ae6bedf2b..86b9a5477 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -70,7 +70,7 @@ function clearBashScreen() { function swallowImages() { var config = { src: { - globs: [ 'images/*.png', 'images/*.gif','images/*.jpeg', 'images/*.jpg' ], + globs: 'images/*.{gif,png,jpg,jpeg,svg,ico}', options: {} }, transform: { diff --git a/images/index.js b/images/index.js index fc0b692d5..5f4eefbd9 100644 --- a/images/index.js +++ b/images/index.js @@ -71,39 +71,142 @@ images['checkbox-on'] = images.checked; */ images['checkbox-off'] = images.unchecked; +var RULE_PREFIX = '.hypergrid-'; + /** - * @name add * @method - * @param {string} key + * @param {string} name * @param {HTMLImageElement} img + * @param {function} [setSvgProps=svgThemer.setSvgProps] - Used to theme the image and the styles. _If omitted, `styles` is promoted 2nd parameter position._ + * @param {string[]} [styles] - Array of style names. + * If falsy (or omitted), no rules are created. + * If empty array, a default value of `['background-image']` is substituted. + * Create a CSS rule for each array element value; otherwise no rules are created. + * The rule is inserted into `style#injected-stylesheet-grid`. + * The rule's selector is `.hypergrid-style-name` (where `style` is element value and `name` is image name). + * (If a rule with that selector already exists, it is replaced.) + * The rule has a single image data style (also element value) that takes a `url(...)` construct as its value. + * Image data styles include `background-image`, `list-style-image`, `border-image`, and `content`. + * The image and the rule(s) thus created are all subject to hypergrid theming (which is the whole point). + * @see {https://github.com/joneit/svg-themer} + * @memberOf module:images + */ +function add(name, img, setSvgProps, styles) { + //if (!/^data:image\/svg\+xml|\.svg/.test(img.src)) { // todo need to handle external files via AJAX a la svg-themer + if (/^data:image\/svg\+xml/.test(img.src)) { + img.themeable = true; + if (typeof setSvgProps === 'object') { + styles = setSvgProps; + setSvgProps = undefined; + } + if (setSvgProps) { + img.setSvgProps = setSvgProps; + } + if (styles) { + img.themeableRules = createThemeableRules(name, img, setSvgProps, styles); + } + } + return images[name] = img; +} + +function createThemeableRules(key, img, setSvgProps, styles) { + // find or create stylesheet as needed + var styleEl = document.querySelector('style#injected-stylesheet-themeables'); + if (!styleEl) { + styleEl = document.createElement('style'); + styleEl.id = 'injected-stylesheet-themeables'; + document.head.appendChild(styleEl); + } + var sheet = styleEl.sheet; + + return (styles.length ? styles : ['background-image']).reduce(function(rules, styleName) { + var selectorText = RULE_PREFIX + styleName + '-' + key; + + // find and delete existing rule, if any + var ruleIndex = Array.prototype.findIndex.call(sheet.cssRules, function(rule) { + return rule.selectorText === selectorText; + }); + if (ruleIndex !== -1) { + sheet.deleteRule(ruleIndex); + } + + // create and insert new rule consisting of selector + style "collection" + var ruleStyles = {}; + + // add image data style + ruleStyles[styleName] = 'url(' + img.src + ')'; + + // add dimensions if known + if (img.width) { ruleStyles.width = img.width + 'px'; } + if (img.height) { ruleStyles.height = img.height + 'px'; } + + // combine the above styles into a semi-colon-separated "collection" + var styleCollection = Object.keys(ruleStyles).map(function(key) { + return key + ':' + ruleStyles[key]; + }).join(';'); + + var ruleText = '{' + styleCollection + '}'; + sheet.insertRule(selectorText + ruleText); + + var themeableRule = { + rule: sheet.cssRules[0] + }; + if (setSvgProps) { + themeableRule.setSvgProps = setSvgProps; + } + rules.push(themeableRule); + return rules; + }, []); +} + +/** + * @param {object} theme * @memberOf module:images */ -images.add = function(key, img) { - return images[key] = img; -}; +function setTheme(theme) { + Object.keys(images).forEach(function(name) { + var img = images[name]; + if (img.themeable) { + svgThemer.setImgSvgProps.call(img, theme, img.setSvgProps); + } + if (img.themeableRules) { + img.themeableRules.forEach(function(themeable) { + var selectorText = themeable.rule.selectorText; + var len = RULE_PREFIX.length; + var styleName = selectorText.substr(len, selectorText.length - len - 1 - name.length); + svgThemer.setRuleSvgProps.call(themeable.rule, theme, img.setSvgProps, styleName); + }); + } + }); +} /** * Convenience function. - * @name checkbox - * @method * @param {boolean} state * @returns {HTMLImageElement} {@link module:images.checked|checked} when `state` is truthy or {@link module:images.unchecked|unchecked} otherwise. * @memberOf module:images */ -images.checkbox = function(state) { +function checkbox(state) { return images[state ? 'checked' : 'unchecked']; -}; +} /** * Convenience function. - * @name filter - * @method * @param {boolean} state * @returns {HTMLImageElement} {@link module:images.filter-off|filter-off} when `state` is truthy or {@link module:images.filter-on|filter-on} otherwise. * @memberOf module:images */ -images.filter = function(state) { +function filter(state) { return images[state ? 'filter-on' : 'filter-off']; -}; +} + +// add methods as non-enumerable members so member images can be enumerated +Object.defineProperties(images, { + add: { value: add }, + setTheme: { value: setTheme }, + checkbox: { value: checkbox }, + filter: { value: filter } +}); + module.exports = images; diff --git a/package.json b/package.json index 0d8f059cf..00e184b10 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "overrider": "^0", "rectangular": "1.0.1", "sparse-boolean-array": "1.0.1", + "svg-themer": "^1.1.2", "synonomous": "^2.1.2" }, "devDependencies": { @@ -41,7 +42,7 @@ "gulp-eslint": "^4.0.2", "gulp-footer": "^1.1.1", "gulp-header": "^1.8.2", - "gulp-imagine-64": "^1.0.1", + "gulp-imagine-64": "^2.0.1", "gulp-load-plugins": "^1.1.0", "gulp-mocha": "^6.0.0", "run-sequence": "^1.1.4" diff --git a/src/Hypergrid/themes.js b/src/Hypergrid/themes.js index d66a9617c..940f286be 100644 --- a/src/Hypergrid/themes.js +++ b/src/Hypergrid/themes.js @@ -11,6 +11,7 @@ var _ = require('object-iterators'); // fyi: installs the Array.prototype.find p var defaults = require('../defaults'); var dynamicPropertyDescriptors = require('../lib/dynamicProperties'); var HypergridError = require('../lib/error'); +var images = require('../../images'); var styles = [ 'BackgroundColor', @@ -73,15 +74,9 @@ stylers.reduce(function(theme, styler) { var registry = Object.create(null, { default: { value: defaultTheme } }); -var pseudopropAdvice = { - showRowNumbers: 'rowHeaderCheckboxes and rowHeaderNumbers', - lineColor: 'gridLinesHColor and gridLinesVColor', - lineWidth: 'gridLinesHWidth and gridLinesVWidth', - gridBorder: 'gridBorderLeft, gridBorderRight, gridBorderTop, and gridBorderBottom' -}; function applyTheme(theme) { - var themeLayer, grids, props; + var themeLayer, grids, props, themeObject; if (theme && typeof theme === 'object' && !Object.getOwnPropertyNames(theme).length) { theme = null; @@ -117,45 +112,50 @@ function applyTheme(theme) { theme = theme || 'default'; } - if (typeof theme === 'string') { - if (!registry[theme]) { - throw new HypergridError('Unknown theme "' + theme + '"'); - } - theme = registry[theme]; + if (typeof theme === 'object') { + themeObject = theme; + } else if (!registry[theme]) { + throw new HypergridError('Unknown theme "' + theme + '"'); + } else { + themeObject = registry[theme]; } - if (theme) { + if (themeObject) { // When no theme name, set it to explicit `undefined` (to mask defaults.themeName). - if (!theme.themeName) { - theme.themeName = undefined; + if (!themeObject.themeName) { + themeObject.themeName = undefined; } - Object.keys(theme).forEach(function(key) { + Object.keys(themeObject).forEach(function(key) { if (key in dynamicPropertyDescriptors) { if (key in dynamicCosmetics) { grids.forEach(function(grid) { - grid.properties[key] = theme[key]; + grid.properties[key] = themeObject[key]; }); } else { // Dynamic properties are defined on properties layer; defining these // r-values on the theme layer is ineffective so let's not allow it. - var message = pseudopropAdvice[key]; - message = message - ? 'Ignoring unexpected pseudo-prop ' + key + ' in theme object. Use actual props ' + message + ' instead.' - : 'Ignoring invalid property ' + key + ' in theme object.'; - console.warn(message); - delete theme[key]; + switch (key) { + case 'lineColor': + themeObject.gridLinesHColor = themeObject.gridLinesVColor = themeObject[key]; + break; + default: + console.warn('Ignoring unexpected dynamic property ' + key + ' from theme object.'); + } + // delete themeObject[key]; } } }); // No .assign() because themeName is read-only in defaults layer - Object.defineProperties(themeLayer, Object.getOwnPropertyDescriptors(theme)); + Object.defineProperties(themeLayer, Object.getOwnPropertyDescriptors(themeObject)); } grids.forEach(function(grid) { grid.repaint(); }); + + return themeObject; } @@ -185,8 +185,8 @@ var mixin = { * @this {Hypergrid} * @param {object|string} [theme] - One of: * * **string:** A registered theme name. - * * **object:** A unregistered (anonymous) theme object. Empty object removes grid theme, exposing global theme. - * * _falsy value:_ Also removes grid theme. + * * **object:** An anonymous (unregistered) theme object. Empty object removes grid theme, exposing global theme. + * * _falsy value:_ Also removes grid theme (like empty object). * @param {string|undefined} [theme.themeName=undefined] * @memberOf Hypergrid# */ @@ -213,7 +213,7 @@ var mixin = { }; Object.defineProperty(mixin, 'theme', { enumerable: true, - set: mixin.applyTheme, + set: applyTheme, get: mixin.getTheme }); @@ -234,7 +234,8 @@ var sharedMixin = { * ```javascript * var myTheme = require('fin-hypergrid-themes').buildTheme(); * ``` - * If omitted, the theme named in the first parameter is unregistered. + * If omitted, unregister the theme named in the first parameter. + * * Grid instances that have previously applied the named theme are unaffected by this action (whether re-registering or unregistering). * @memberOf Hypergrid. */ @@ -292,11 +293,14 @@ var sharedMixin = { * @param {string|undefined} [theme.themeName=undefined] * @memberOf Hypergrid. */ - applyTheme: applyTheme + applyTheme: function(theme) { + var themeObject = applyTheme.call(this, theme); + images.setTheme(themeObject); + } }; Object.defineProperty(sharedMixin, 'theme', { // global theme setter/getter enumerable: true, - set: applyTheme, + set: sharedMixin.applyTheme, get: function() { return defaults; } // the defaults layer *is* the global theme layer }); From 889269d58b2d2567d4dac798684a0e5ab091dc96 Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Thu, 15 Nov 2018 13:32:45 -0500 Subject: [PATCH 05/10] allow images.add(img) with imgs.src = external SVG file --- images/index.js | 13 ++++++------- src/cellRenderers/SimpleCell.js | 16 +++++++++++++--- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/images/index.js b/images/index.js index 5f4eefbd9..de6d91522 100644 --- a/images/index.js +++ b/images/index.js @@ -12,6 +12,7 @@ 'use strict'; var _ = require('object-iterators'); +var svgThemer = require('svg-themer'); var images = require('./images'); // this is the file generated by gulpfile.js (and ignored by git) @@ -71,8 +72,6 @@ images['checkbox-on'] = images.checked; */ images['checkbox-off'] = images.unchecked; -var RULE_PREFIX = '.hypergrid-'; - /** * @method * @param {string} name @@ -92,8 +91,7 @@ var RULE_PREFIX = '.hypergrid-'; * @memberOf module:images */ function add(name, img, setSvgProps, styles) { - //if (!/^data:image\/svg\+xml|\.svg/.test(img.src)) { // todo need to handle external files via AJAX a la svg-themer - if (/^data:image\/svg\+xml/.test(img.src)) { + if (/^data:image\/svg\+xml|\.svg/.test(img.src)) { img.themeable = true; if (typeof setSvgProps === 'object') { styles = setSvgProps; @@ -120,7 +118,7 @@ function createThemeableRules(key, img, setSvgProps, styles) { var sheet = styleEl.sheet; return (styles.length ? styles : ['background-image']).reduce(function(rules, styleName) { - var selectorText = RULE_PREFIX + styleName + '-' + key; + var selectorText = '.hypergrid-' + styleName + '-' + key; // find and delete existing rule, if any var ruleIndex = Array.prototype.findIndex.call(sheet.cssRules, function(rule) { @@ -172,8 +170,9 @@ function setTheme(theme) { if (img.themeableRules) { img.themeableRules.forEach(function(themeable) { var selectorText = themeable.rule.selectorText; - var len = RULE_PREFIX.length; - var styleName = selectorText.substr(len, selectorText.length - len - 1 - name.length); + // extract style name using list of possible names + var regex = new RegExp('^\.hypergrid-(' + svgThemer.cssImagePropertyNames.join('|') + ')-.*$'); + var styleName = selectorText.replace(regex, '$1'); svgThemer.setRuleSvgProps.call(themeable.rule, theme, img.setSvgProps, styleName); }); } diff --git a/src/cellRenderers/SimpleCell.js b/src/cellRenderers/SimpleCell.js index 51d37d446..fe01b0d9d 100644 --- a/src/cellRenderers/SimpleCell.js +++ b/src/cellRenderers/SimpleCell.js @@ -141,7 +141,7 @@ var SimpleCell = CellRenderer.extend('SimpleCell', { // Measure & draw center icon iyoffset = Math.round((height - centerIcon.height) / 2); ixoffset = width - Math.round((width - centerIcon.width) / 2) - centerIcon.width; - gc.drawImage(centerIcon, x + ixoffset, y + iyoffset); + gc.drawImage(centerIcon, x + ixoffset, y + iyoffset, centerIcon.width, centerIcon.height); // see [SIZE NOTE]! valWidth = iconPadding + centerIcon.width + iconPadding; if (config.hotIcon === 'center') { config.clickRect = new Rectangle(ixoffset, iyoffset, centerIcon.width, centerIcon.height); @@ -152,7 +152,7 @@ var SimpleCell = CellRenderer.extend('SimpleCell', { if (leftIcon) { // Draw left icon iyoffset = Math.round((height - leftIcon.height) / 2); - gc.drawImage(leftIcon, x + iconPadding, y + iyoffset); + gc.drawImage(leftIcon, x + iconPadding, y + iyoffset, leftIcon.width, leftIcon.height); // see [SIZE NOTE]! if (config.hotIcon === 'left') { config.clickRect = new Rectangle(iconPadding, iyoffset, leftIcon.width, leftIcon.height); } @@ -171,7 +171,7 @@ var SimpleCell = CellRenderer.extend('SimpleCell', { // Draw right icon iyoffset = Math.round((height - rightIcon.height) / 2); - gc.drawImage(rightIcon, rightX, y + iyoffset); + gc.drawImage(rightIcon, rightX, y + iyoffset, rightIcon.width, rightIcon.height); // see [SIZE NOTE]! if (config.hotIcon === 'right') { config.clickRect = new Rectangle(ixoffset, iyoffset, rightIcon.width, rightIcon.height); } @@ -190,6 +190,16 @@ var SimpleCell = CellRenderer.extend('SimpleCell', { } }); +/* [SIZE NOTE] (11/1/2018): Always call `drawImage` with explicit width and height overload. + * Possible browser bug: Although 3rd and 4th parameters to `drawImage` are optional, + * when image data derived from SVG source, some browsers (e.g., Chrome 70) implementation + * of `drawImage` only respects _implicit_ `width` x `height` specified in the root + * element `width` & `height` attributes. Otherwise, image is copied into canvas using its + * `naturalWidth` x `naturalHeight`. That is, _explict_ settings of `width` & `height` + * (i.e, via property assignment, calling setAttribute, or in `new Image` call) have no + * effect on `drawImage` in the case of SVGs on these browsers. + */ + /** * @summary Renders single line text. * @param {CanvasRenderingContext2D} gc From 90cb5142ec9ae1b0b7c37d845c6db75c1e2b507f Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Fri, 16 Nov 2018 10:29:56 -0500 Subject: [PATCH 06/10] tweaked jsdoc comment for images.add method --- images/index.js | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/images/index.js b/images/index.js index de6d91522..46a215234 100644 --- a/images/index.js +++ b/images/index.js @@ -76,18 +76,24 @@ images['checkbox-off'] = images.unchecked; * @method * @param {string} name * @param {HTMLImageElement} img - * @param {function} [setSvgProps=svgThemer.setSvgProps] - Used to theme the image and the styles. _If omitted, `styles` is promoted 2nd parameter position._ - * @param {string[]} [styles] - Array of style names. - * If falsy (or omitted), no rules are created. - * If empty array, a default value of `['background-image']` is substituted. - * Create a CSS rule for each array element value; otherwise no rules are created. - * The rule is inserted into `style#injected-stylesheet-grid`. - * The rule's selector is `.hypergrid-style-name` (where `style` is element value and `name` is image name). + * @param {function} [setSvgProps=svgThemer.setSvgProps] - Optional custom theming code for this image and the rules implied by `styles`. _If omitted, `styles` is promoted 2nd parameter position._ + * @param {boolean|string[]} [styles] - Optional list style names with which to create CSS rules. + * * If falsy (or omitted), no rules are created. + * * Else if truthy but not an array, create a single rule: + * ```css + * `.hypergrid-background-image-name { background-image: url(...) }` + * where _name_ is the value of the `name` parameter. + * * Else if an array, create a CSS rule for each style named therein. + * + * For each rule thus created: + * * Inserted into `style#injected-stylesheet-grid`. + * * Selector is `.hypergrid-style-name` (where `style` is element value and `name` is image name). * (If a rule with that selector already exists, it is replaced.) - * The rule has a single image data style (also element value) that takes a `url(...)` construct as its value. - * Image data styles include `background-image`, `list-style-image`, `border-image`, and `content`. - * The image and the rule(s) thus created are all subject to hypergrid theming (which is the whole point). - * @see {https://github.com/joneit/svg-themer} + * * Contains the named style with a value of `url(...)` where `...` is the image data. + * Possible styles must be one of those listed in {*link https://github.com/joneit/svg-themer/blob/master/README.md#cssimagepropertynames svgThemer.cssImagePropertyNames} (which you can extend if needed). + * * Will be automatically themed when the grid is themed (which is the whole point). + * + * @see {@link https://github.com/joneit/svg-themer} * @memberOf module:images */ function add(name, img, setSvgProps, styles) { From aacbfd05625be32de682dd618574ff4d75fe679a Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Sat, 17 Nov 2018 00:34:07 -0500 Subject: [PATCH 07/10] added themeable formal parameter to images.add defintion --- images/index.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/images/index.js b/images/index.js index 46a215234..a2272f378 100644 --- a/images/index.js +++ b/images/index.js @@ -76,6 +76,9 @@ images['checkbox-off'] = images.unchecked; * @method * @param {string} name * @param {HTMLImageElement} img + * @param {boolean} [themeable] - If truthy, the image will be themed by {@link module:images.setTheme images.setTheme}, called by {@link Hypergrid.applyTheme}. + * If falsy, the image won't be themed until `images[name].themeable` is set to `true`. + * In any case the remaining parameters are processed. * @param {function} [setSvgProps=svgThemer.setSvgProps] - Optional custom theming code for this image and the rules implied by `styles`. _If omitted, `styles` is promoted 2nd parameter position._ * @param {boolean|string[]} [styles] - Optional list style names with which to create CSS rules. * * If falsy (or omitted), no rules are created. @@ -96,9 +99,9 @@ images['checkbox-off'] = images.unchecked; * @see {@link https://github.com/joneit/svg-themer} * @memberOf module:images */ -function add(name, img, setSvgProps, styles) { +function add(name, img, themeable, setSvgProps, styles) { if (/^data:image\/svg\+xml|\.svg/.test(img.src)) { - img.themeable = true; + img.themeable = !!themeable; if (typeof setSvgProps === 'object') { styles = setSvgProps; setSvgProps = undefined; From 3c9cfe87c242562c8f83d036e6dbce60f3a62c69 Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Sat, 17 Nov 2018 13:15:19 -0500 Subject: [PATCH 08/10] bump version number --- images/index.js | 2 +- package.json | 2 +- src/Hypergrid/events.js | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/images/index.js b/images/index.js index a2272f378..723fb52f4 100644 --- a/images/index.js +++ b/images/index.js @@ -113,7 +113,7 @@ function add(name, img, themeable, setSvgProps, styles) { img.themeableRules = createThemeableRules(name, img, setSvgProps, styles); } } - return images[name] = img; + return (images[name] = img); } function createThemeableRules(key, img, setSvgProps, styles) { diff --git a/package.json b/package.json index 00e184b10..574219574 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fin-hypergrid", - "version": "3.1.0", + "version": "3.2.0", "description": "Canvas-based high-performance grid", "main": "src/Hypergrid", "repository": { diff --git a/src/Hypergrid/events.js b/src/Hypergrid/events.js index 3c360fc7b..1128c27fb 100644 --- a/src/Hypergrid/events.js +++ b/src/Hypergrid/events.js @@ -475,8 +475,6 @@ exports.mixin = { } } - - cb.call(grid, decoratedEvent); } } From 08cc1eb086652ada16825c4f6258ededce01619d Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Sat, 17 Nov 2018 13:29:02 -0500 Subject: [PATCH 09/10] updated readme --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 477e955c3..39018b1a3 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ It also highlights a DOM-based custom external editor triggered via hypergrid ev * [Roadmap](#roadmap) * [Contributing](#contributors) -### Current Release (3.1.0 - 29 September 2018) +### Current Release (3.2.0 - 17 November 2018) -**Hypergrid 3.1 includes 3.0’s revised data model with some breaking changes.** +> **CAUTION:** For those considering upgrading directly from v2, be advised Hypergrid v3 introduced a revised data model _with breaking changes._ The impact of these changes has been intentionally minimized and should not affect the vast majority of users. See the [v3.0.0 release notes](https://github.com/fin-hypergrid/core/releases/tag/v3.0.0) for more information. _For a complete list of changes, see the [release notes](https://github.com/fin-hypergrid/core/releases)._ @@ -25,7 +25,7 @@ _For a complete list of changes, see the [release notes](https://github.com/fin- #### npm module _(recommended)_ Published as a CommonJS module to npmjs.org. -Specify a SEMVER of `"fin-hypergrid": "3.1.0"` (or `"^3.1.0"`) in your package.json file, +Specify a SEMVER of `"fin-hypergrid": "3.2.0"` (or `"^3.2.0"`) in your package.json file, issue the `npm install` command, and let your bundler (wepback, Browserify) create a single file containing both Hypergrid and your application. From 220b0ff25407fa5f370d6e8ca6c1462b11f61b6a Mon Sep 17 00:00:00 2001 From: Jonathan Eiten Date: Sat, 17 Nov 2018 13:44:00 -0500 Subject: [PATCH 10/10] resolve jsdoc compilation error --- src/Hypergrid/themes.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Hypergrid/themes.js b/src/Hypergrid/themes.js index 940f286be..d5f819737 100644 --- a/src/Hypergrid/themes.js +++ b/src/Hypergrid/themes.js @@ -285,7 +285,6 @@ var sharedMixin = { * @summary Apply global theme. * @desc Apply props from the given theme object to the global theme object, * the `defaults` layer at the bottom of the properties hierarchy. - * @this {Hypergrid.} * @param {object|string} [theme=registry.default] - One of: * * **string:** A registered theme name. * * **object:** A theme object. Empty object removes global them, restoring defaults.