/
githubmirror
/
brackets
Обзор
Документация
Войти
/
githubmirror
/
brackets
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/extensions/default/InlineTimingFunctionEditor/TimingFunctionUtils.js
445 строк
16 KB
ficristo
Move most inline jslint directives to config files
12 авг 2016, 10:22
12 авг 2016, 10:22
074382a
Код
Авторство
О чём код?
/* * Copyright (c) 2013 - present Adobe Systems Incorporated. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * */ /*jslint regexp: true */ /** * Utilities functions related to color matching */ define(function (require, exports, module) { "use strict"; var Strings = brackets.getModule("strings"), StringUtils = brackets.getModule("utils/StringUtils"), AnimationUtils = brackets.getModule("utils/AnimationUtils"); /** * Regular expressions for matching timing functions * @const @type {RegExp} */ var BEZIER_CURVE_VALID_REGEX = /cubic-bezier\(\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*,\s*(\S+)\s*\)/, BEZIER_CURVE_GENERAL_REGEX = /cubic-bezier\((.*)\)/, EASE_STRICT_REGEX = /[: ,]ease(?:-in)?(?:-out)?[ ,;]/, EASE_LAX_REGEX = /ease(?:-in)?(?:-out)?/, LINEAR_STRICT_REGEX = /(transition|animation).*?[: ,]linear[ ,;]/, LINEAR_LAX_REGEX = /linear/, STEPS_VALID_REGEX = /steps\(\s*(\d+)\s*(?:,\s*(\w+)\s*)?\)/, STEPS_GENERAL_REGEX = /steps\((.*)\)/, STEP_STRICT_REGEX = /[: ,](?:step-start|step-end)[ ,;]/, STEP_LAX_REGEX = /step-start|step-end/; /** * Type constants * @const @type {number} */ var BEZIER = 1, STEP = 2; /** * If string is a number, then convert it. * * @param {string} str value parsed from page. * @return { isNumber: boolean, value: ?number } */ function _convertToNumber(str) { if (typeof str !== "string") { return { isNumber: false, value: null }; } var val = parseFloat(+str, 10), isNum = (typeof val === "number") && !isNaN(val) && (val !== Infinity) && (val !== -Infinity); return { isNumber: isNum, value: val }; } /** * Get valid params for an invalid cubic-bezier. * * @param {RegExp.match} match (Invalid) matches from cubicBezierMatch() * @return {?RegExp.match} Valid match or null if the output is not valid */ function _getValidBezierParams(match) { var param, // take ease-in-out as default value in case there are no params yet (or they are invalid) def = [ ".42", "0", ".58", "1" ], oldIndex = match.index, // we need to store the old match.index to re-set the index afterwards originalString = match[0], i; if (match) { match = match[1].split(","); } if (match) { for (i = 0; i <= 3; i++) { if (match[i]) { match[i] = match[i].trim(); param = _convertToNumber(match[i]); // Verify the param is a number // If not, replace it with the default value if (!param.isNumber) { match[i] = undefined; // Verify x coordinates are in 0-1 range // If not, set them to the closest value in range } else if (i === 0 || i === 2) { if (param.value < 0) { match[i] = "0"; } else if (param.value > 1) { match[i] = "1"; } } } if (!match[i]) { match[i] = def[i]; } } } else { match = def; } match = match.splice(0, 4); // make sure there are only 4 params match = "cubic-bezier(" + match.join(", ") + ")"; match = match.match(BEZIER_CURVE_VALID_REGEX); if (match) { match.index = oldIndex; // re-set the index here to get the right context match.originalString = originalString; return match; } return null; } /** * Validate cubic-bezier function parameters that are not already validated by regex: * * @param {RegExp.match} match RegExp Match object with cubic-bezier function parameters * in array positions 1-4. * @return {boolean} true if all parameters are valid, otherwise, false */ function _validateCubicBezierParams(match) { var x1 = _convertToNumber(match[1]), y1 = _convertToNumber(match[2]), x2 = _convertToNumber(match[3]), y2 = _convertToNumber(match[4]); // Verify all params are numbers if (!x1.isNumber || !y1.isNumber || !x2.isNumber || !y2.isNumber) { return false; } // Verify x params are in 0-1 range if (x1.value < 0 || x1.value > 1 || x2.value < 0 || x2.value > 1) { return false; } return true; } /** * Get valid params for an invalid steps function. * * @param {RegExp.match} match (Invalid) matches from stepsMatch() * @return {?RegExp.match} Valid match or null if the output is not valid */ function _getValidStepsParams(match) { var param, def = [ "5", "end" ], params = def, oldIndex = match.index, // we need to store the old match.index to re-set the index afterwards originalString = match[0]; if (match) { match = match[1].split(","); } if (match) { if (match[0]) { param = match[0].replace(/[\s\"']/g, ""); // replace possible trailing whitespace or leading quotes param = _convertToNumber(param); // Verify number_of_params is a number // If not, replace it with the default value if (!param.isNumber) { param.value = def[0]; // Round number_of_params to an integer } else if (param.value) { param.value = Math.floor(param.value); } // Verify number_of_steps is >= 1 // If not, set them to the default value if (param.value < 1) { param.value = def[0]; } params[0] = param.value; } if (match[1]) { // little autocorrect feature: leading s gets 'start', everything else gets 'end' param = match[1].replace(/[\s\"']/g, ""); // replace possible trailing whitespace or leading quotes param = param.substr(0, 1); if (param === "s") { params[1] = "start"; } else { params[1] = "end"; } } } params = "steps(" + params.join(", ") + ")"; params = params.match(STEPS_VALID_REGEX); if (params) { params.index = oldIndex; // re-set the index here to get the right context params.originalString = originalString; return params; } return null; } /** * Validate steps function parameters that are not already validated by regex: * * @param {RegExp.match} match RegExp Match object with steps function parameters * in array position 1 (and optionally 2). * @return {boolean} true if all parameters are valid, otherwise, false */ function _validateStepsParams(match) { var count = _convertToNumber(match[1]); if (!count.isNumber || count.value < 1 || Math.floor(count.value) !== count.value) { return false; } if (match[2] && match[2] !== "start" && match[2] !== "end") { return false; } return true; } /** * Show, hide or update the hint text * * @param {object} hint Editor.hint object of the current InlineTimingFunctionEditor * @param {boolean} show Whether the hint should be shown or hidden * @param {string=} documentCode The invalid code from the document (can be omitted when hiding) * @param {string=} editorCode The valid code that is shown in the Inline Editor (can be omitted when hiding) */ function showHideHint(hint, show, documentCode, editorCode) { if (!hint || !hint.elem) { return; } if (show) { hint.shown = true; hint.animationInProgress = false; hint.elem.removeClass("fadeout"); hint.elem.html(StringUtils.format(Strings.INLINE_TIMING_EDITOR_INVALID, documentCode, editorCode)); hint.elem.css("display", "block"); } else if (hint.shown) { hint.animationInProgress = true; AnimationUtils.animateUsingClass(hint.elem[0], "fadeout", 750) .done(function () { if (hint.animationInProgress) { // do this only if the animation was not cancelled hint.elem.hide(); } hint.shown = false; hint.animationInProgress = false; }); } else { hint.elem.hide(); } } /** * Tag this match with type and return it for chaining * * @param {!RegExp.match} match RegExp Match object with steps function parameters * in array position 1 (and optionally 2). * @param {number} type Either BEZIER or STEP * @return {RegExp.match} Same object that was passed in. */ function _tagMatch(match, type) { switch (type) { case BEZIER: match.isBezier = true; break; case STEP: match.isStep = true; break; } return match; } /** * Match a bezier curve function value from a CSS Declaration or Value. * * Matches returned from this function must be handled in * BezierCurveEditor._getCubicBezierCoords(). * * @param {string} str Input string. * @param {!boolean} lax Parsing mode where: * lax=false Input is a Full or partial line containing CSS Declaration. * This is the more strict search used for initial detection. * lax=true Input is a previously parsed value. This is the less strict search * used to convert previously parsed values to RegExp match format. * @return {!RegExpMatch} */ function bezierCurveMatch(str, lax) { var match; // First look for any cubic-bezier(). match = str.match(BEZIER_CURVE_VALID_REGEX); if (match && _validateCubicBezierParams(match)) { // cubic-bezier() with valid params return _tagMatch(match, BEZIER); } match = str.match(BEZIER_CURVE_GENERAL_REGEX); if (match) { match = _getValidBezierParams(match); if (match && _validateCubicBezierParams(match)) { return _tagMatch(match, BEZIER); } else { // this should not happen! window.console.log("brackets-cubic-bezier: TimingFunctionUtils._getValidBezierParams created invalid code"); } } // Next look for the ease functions (which are special cases of cubic-bezier()) if (lax) { // For lax parsing, just look for the keywords match = str.match(EASE_LAX_REGEX); if (match) { return _tagMatch(match, BEZIER); } } else { // For strict parsing, start with a syntax verifying search match = str.match(EASE_STRICT_REGEX); if (match) { // return exact match to keyword that we need for later replacement return _tagMatch(str.match(EASE_LAX_REGEX), BEZIER); } } // Final case is linear. if (lax) { // For lax parsing, just look for the keyword match = str.match(LINEAR_LAX_REGEX); if (match) { return _tagMatch(match, BEZIER); } } else { // The linear keyword can occur in other values, so for strict parsing we // only detect when it's on same line as "transition" or "animation" match = str.match(LINEAR_STRICT_REGEX); if (match) { // return exact match to keyword that we need for later replacement return _tagMatch(str.match(LINEAR_LAX_REGEX), BEZIER); } } return null; } /** * Match a steps function value from a CSS Declaration or Value. * * Matches returned from this function must be handled in * BezierCurveEditor._getCubicBezierCoords(). * * @param {string} str Input string. * @param {!boolean} lax Parsing mode where: * lax=false Input is a Full or partial line containing CSS Declaration. * This is the more strict search used for initial detection. * lax=true Input is a previously parsed value. This is the less strict search * used to convert previously parsed values to RegExp match format. * @return {!RegExpMatch} */ function stepsMatch(str, lax) { var match; // First look for any steps(). match = str.match(STEPS_VALID_REGEX); if (match && _validateStepsParams(match)) { // cubic-bezier() with valid params return _tagMatch(match, STEP); } match = str.match(STEPS_GENERAL_REGEX); if (match) { match = _getValidStepsParams(match); if (match && _validateStepsParams(match)) { return _tagMatch(match, STEP); } else { // this should not happen! window.console.log("brackets-steps: TimingFunctionUtils._getValidStepsParams created invalid code"); } } // Next look for the step functions (which are special cases of steps()) if (lax) { // For lax parsing, just look for the keywords match = str.match(STEP_LAX_REGEX); if (match) { return _tagMatch(match, STEP); } } else { // For strict parsing, start with a syntax verifying search match = str.match(STEP_STRICT_REGEX); if (match) { // return exact match to keyword that we need for later replacement return _tagMatch(str.match(STEP_LAX_REGEX), STEP); } } return null; } /** * Match a timing function value from a CSS Declaration or Value. * * Matches returned from this function must be handled in * BezierCurveEditor._getCubicBezierCoords(). * * @param {string} str Input string. * @param {!boolean} lax Parsing mode where: * lax=false Input is a Full or partial line containing CSS Declaration. * This is the more strict search used for initial detection. * lax=true Input is a previously parsed value. This is the less strict search * used to convert previously parsed values to RegExp match format. * @return {!RegExpMatch} */ function timingFunctionMatch(str, lax) { return bezierCurveMatch(str, lax) || stepsMatch(str, lax); } // Define public API exports.timingFunctionMatch = timingFunctionMatch; exports.bezierCurveMatch = bezierCurveMatch; exports.stepsMatch = stepsMatch; exports.showHideHint = showHideHint; });