235 lines
5.9 KiB
JavaScript
235 lines
5.9 KiB
JavaScript
import $ from 'jquery';
|
|
import * as util from './util';
|
|
import keywordAngleMap from './keywordAngleMap';
|
|
|
|
const angleKeywordMap = util.flip(keywordAngleMap);
|
|
|
|
const RegExpStrings = (() => {
|
|
const color = /(?:rgba|rgb|hsla|hsl)\s*\([\s\d\.,%]+\)|#[a-z0-9]{3,6}|[a-z]+/i;
|
|
const position = /\d{1,3}%/i;
|
|
const angle = /(?:to ){0,1}(?:(?:top|left|right|bottom)\s*){1,2}|\d+deg/i;
|
|
const stop = new RegExp(`(${color.source})\\s*(${position.source}){0,1}`, 'i');
|
|
const stops = new RegExp(stop.source, 'gi');
|
|
const parameters = new RegExp(`(?:(${angle.source})){0,1}\\s*,{0,1}\\s*(.*?)\\s*`, 'i');
|
|
const full = new RegExp(`^(-webkit-|-moz-|-ms-|-o-){0,1}(linear|radial|repeating-linear)-gradient\\s*\\(\\s*(${parameters.source})\\s*\\)$`, 'i');
|
|
|
|
return {
|
|
FULL: full,
|
|
ANGLE: angle,
|
|
COLOR: color,
|
|
POSITION: position,
|
|
STOP: stop,
|
|
STOPS: stops,
|
|
PARAMETERS: new RegExp(`^${parameters.source}$`, 'i')
|
|
};
|
|
})();
|
|
|
|
export default {
|
|
matchString: function(string) {
|
|
const matched = this.parseString(string);
|
|
if(matched && matched.value && matched.value.stops && matched.value.stops.length > 1){
|
|
return true;
|
|
}
|
|
return false;
|
|
},
|
|
|
|
parseString: function(string) {
|
|
string = $.trim(string);
|
|
let matched;
|
|
if ((matched = RegExpStrings.FULL.exec(string)) !== null) {
|
|
let value = this.parseParameters(matched[3]);
|
|
|
|
return {
|
|
prefix: (typeof matched[1] === 'undefined') ? null : matched[1],
|
|
type: matched[2],
|
|
value: value
|
|
};
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
parseParameters: function(string) {
|
|
let matched;
|
|
if ((matched = RegExpStrings.PARAMETERS.exec(string)) !== null) {
|
|
let stops = this.parseStops(matched[2]);
|
|
return {
|
|
angle: (typeof matched[1] === 'undefined') ? 0 : matched[1],
|
|
stops: stops
|
|
};
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
parseStops: function(string) {
|
|
let matched;
|
|
const result = [];
|
|
if ((matched = string.match(RegExpStrings.STOPS)) !== null) {
|
|
|
|
$.each(matched, (i, item) => {
|
|
const stop = this.parseStop(item);
|
|
if (stop) {
|
|
result.push(stop);
|
|
}
|
|
});
|
|
return result;
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
formatStops: function(stops, cleanPosition) {
|
|
let stop;
|
|
const output = [];
|
|
let positions = [];
|
|
const colors = [];
|
|
let position;
|
|
|
|
for (let i = 0; i < stops.length; i++) {
|
|
stop = stops[i];
|
|
if (typeof stop.position === 'undefined' || stop.position === null) {
|
|
if (i === 0) {
|
|
position = 0;
|
|
} else if (i === stops.length - 1) {
|
|
position = 1;
|
|
} else {
|
|
position = undefined;
|
|
}
|
|
} else {
|
|
position = stop.position;
|
|
}
|
|
positions.push(position);
|
|
colors.push(stop.color.toString());
|
|
}
|
|
|
|
positions = ((data => {
|
|
let start = null;
|
|
let average;
|
|
for (let i = 0; i < data.length; i++) {
|
|
if (isNaN(data[i])) {
|
|
if (start === null) {
|
|
start = i;
|
|
continue;
|
|
}
|
|
} else if (start) {
|
|
average = (data[i] - data[start - 1]) / (i - start + 1);
|
|
for (let j = start; j < i; j++) {
|
|
data[j] = data[start - 1] + (j - start + 1) * average;
|
|
}
|
|
start = null;
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}))(positions);
|
|
|
|
for (let x = 0; x < stops.length; x++) {
|
|
if (cleanPosition && ((x === 0 && positions[x] === 0) || (x === stops.length - 1 && positions[x] === 1))) {
|
|
position = '';
|
|
} else {
|
|
position = ` ${this.formatPosition(positions[x])}`;
|
|
}
|
|
|
|
output.push(colors[x] + position);
|
|
}
|
|
return output.join(', ');
|
|
},
|
|
|
|
parseStop: function(string) {
|
|
let matched;
|
|
if ((matched = RegExpStrings.STOP.exec(string)) !== null) {
|
|
let position = this.parsePosition(matched[2]);
|
|
|
|
return {
|
|
color: matched[1],
|
|
position: position
|
|
};
|
|
} else {
|
|
return false;
|
|
}
|
|
},
|
|
|
|
parsePosition: function(string) {
|
|
if (typeof string === 'string' && string.substr(-1) === '%') {
|
|
string = parseFloat(string.slice(0, -1) / 100);
|
|
}
|
|
|
|
if(typeof string !== 'undefined' && string !== null) {
|
|
return parseFloat(string, 10);
|
|
} else {
|
|
return null;
|
|
}
|
|
},
|
|
|
|
formatPosition: function(value) {
|
|
return `${parseInt(value * 100, 10)}%`;
|
|
},
|
|
|
|
parseAngle: function(string, notStandard) {
|
|
if (typeof string === 'string' && string.includes('deg')) {
|
|
string = string.replace('deg', '');
|
|
}
|
|
if (!isNaN(string)) {
|
|
if (notStandard) {
|
|
string = this.fixOldAngle(string);
|
|
}
|
|
}
|
|
if (typeof string === 'string') {
|
|
const directions = string.split(' ');
|
|
|
|
const filtered = [];
|
|
for (const i in directions) {
|
|
if (util.isDirection(directions[i])) {
|
|
filtered.push(directions[i].toLowerCase());
|
|
}
|
|
}
|
|
let keyword = filtered.join(' ');
|
|
|
|
if (!string.includes('to ')) {
|
|
keyword = util.reverseDirection(keyword);
|
|
}
|
|
keyword = `to ${keyword}`;
|
|
if (keywordAngleMap.hasOwnProperty(keyword)) {
|
|
string = keywordAngleMap[keyword];
|
|
}
|
|
}
|
|
let value = parseFloat(string, 10);
|
|
|
|
if (value > 360) {
|
|
value %= 360;
|
|
} else if (value < 0) {
|
|
value %= -360;
|
|
|
|
if (value !== 0) {
|
|
value += 360;
|
|
}
|
|
}
|
|
return value;
|
|
},
|
|
|
|
fixOldAngle: function(value) {
|
|
value = parseFloat(value);
|
|
value = Math.abs(450 - value) % 360;
|
|
value = parseFloat(value.toFixed(3));
|
|
return value;
|
|
},
|
|
|
|
formatAngle: function(value, notStandard, useKeyword) {
|
|
value = parseInt(value, 10);
|
|
if (useKeyword && angleKeywordMap.hasOwnProperty(value)) {
|
|
value = angleKeywordMap[value];
|
|
if (notStandard) {
|
|
value = util.reverseDirection(value.substr(3));
|
|
}
|
|
} else {
|
|
if (notStandard) {
|
|
value = this.fixOldAngle(value);
|
|
}
|
|
value = `${value}deg`;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
}
|