Skip to content

Commit

Permalink
Merge pull request #780 from fin-hypergrid/develop
Browse files Browse the repository at this point in the history
Hypergrid v3.2.0
  • Loading branch information
joneit authored Nov 17, 2018
2 parents fff78e6 + bd54261 commit 9d19656
Show file tree
Hide file tree
Showing 10 changed files with 220 additions and 62 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,17 @@ 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)._

### Distribution

#### npm module _(recommended)_
Published as a CommonJS module to npmjs.org.
Specify a <a href="https://semver.org/">SEMVER</a> of `"fin-hypergrid": "3.1.0"` (or `"^3.1.0"`) in your package.json file,
Specify a <a href="https://semver.org/">SEMVER</a> of `"fin-hypergrid": "3.2.0"` (or `"^3.2.0"`) in your package.json file,
issue the `npm install` command, and let your bundler (<a target="webpack" href="https://webpack.js.org/">wepback</a>,
<a target="browserify" href="http://browserify.org/">Browserify</a>) create a single file containing both Hypergrid and your application.

Expand Down
2 changes: 1 addition & 1 deletion gulpfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
137 changes: 124 additions & 13 deletions images/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -72,38 +73,148 @@ images['checkbox-on'] = images.checked;
images['checkbox-off'] = images.unchecked;

/**
* @name add
* @method
* @param {string} key
* @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.
* * 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.)
* * 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, themeable, setSvgProps, styles) {
if (/^data:image\/svg\+xml|\.svg/.test(img.src)) {
img.themeable = !!themeable;
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 = '.hypergrid-' + 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;
// 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);
});
}
});
}

/**
* 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;
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down Expand Up @@ -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": {
Expand All @@ -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"
Expand Down
18 changes: 10 additions & 8 deletions src/Base.js
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down
19 changes: 18 additions & 1 deletion src/Hypergrid/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,23 @@ 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);
}
}
Expand Down Expand Up @@ -576,7 +593,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);
});
Expand Down
Loading

0 comments on commit 9d19656

Please sign in to comment.