- compact_bool: false,
-
- // Use self-closing style for writing empty elements, e.g.
or
- self_closing_tag: 'xhtml',
-
- // Profile-level output filters, re-defines syntax filters
- filters: '',
-
- // Additional filters applied to abbreviation.
- // Unlike "filters", this preference doesn't override default filters
- // but add the instead every time given profile is chosen
- extraFilters: ''
- };
-
- /**
- * @constructor
- * @type OutputProfile
- * @param {Object} options
- */
- function OutputProfile(options) {
- utils.extend(this, defaultProfile, options);
- }
-
- OutputProfile.prototype = {
- /**
- * Transforms tag name case depending on current profile settings
- * @param {String} name String to transform
- * @returns {String}
- */
- tagName: function(name) {
- return stringCase(name, this.tag_case);
- },
-
- /**
- * Transforms attribute name case depending on current profile settings
- * @param {String} name String to transform
- * @returns {String}
- */
- attributeName: function(name) {
- return stringCase(name, this.attr_case);
- },
-
- /**
- * Returns quote character for current profile
- * @returns {String}
- */
- attributeQuote: function() {
- return this.attr_quotes == 'single' ? "'" : '"';
- },
-
- /**
- * Returns self-closing tag symbol for current profile
- * @returns {String}
- */
- selfClosing: function() {
- if (this.self_closing_tag == 'xhtml')
- return ' /';
-
- if (this.self_closing_tag === true)
- return '/';
-
- return '';
- },
-
- /**
- * Returns cursor token based on current profile settings
- * @returns {String}
- */
- cursor: function() {
- return this.place_cursor ? utils.getCaretPlaceholder() : '';
- },
-
- /**
- * Check if attribute with given name is boolean,
- * e.g. written as `contenteditable` instead of
- * `contenteditable="contenteditable"`
- * @param {String} name Attribute name
- * @return {Boolean}
- */
- isBoolean: function(name, value) {
- if (name == value) {
- return true;
- }
-
- var boolAttrs = prefs.get('profile.booleanAttributes');
- if (!value && boolAttrs) {
- boolAttrs = new RegExp(boolAttrs, 'i');
- return boolAttrs.test(name);
- }
-
- return false;
- },
-
- /**
- * Check if compact boolean attribute record is
- * allowed for current profile
- * @return {Boolean}
- */
- allowCompactBoolean: function() {
- return this.compact_bool && prefs.get('profile.allowCompactBoolean');
- }
- };
-
- /**
- * Helper function that converts string case depending on
- *
caseValue
- * @param {String} str String to transform
- * @param {String} caseValue Case value: can be
lower ,
- *
upper and
leave
- * @returns {String}
- */
- function stringCase(str, caseValue) {
- switch (String(caseValue || '').toLowerCase()) {
- case 'lower':
- return str.toLowerCase();
- case 'upper':
- return str.toUpperCase();
- }
-
- return str;
- }
-
- /**
- * Creates new output profile
- * @param {String} name Profile name
- * @param {Object} options Profile options
- */
- function createProfile(name, options) {
- return profiles[name.toLowerCase()] = new OutputProfile(options);
- }
-
- function createDefaultProfiles() {
- createProfile('xhtml');
- createProfile('html', {self_closing_tag: false, compact_bool: true});
- createProfile('xml', {self_closing_tag: true, tag_nl: true});
- createProfile('plain', {tag_nl: false, indent: false, place_cursor: false});
- createProfile('line', {tag_nl: false, indent: false, extraFilters: 's'});
- createProfile('css', {tag_nl: true});
- createProfile('css_line', {tag_nl: false});
- }
-
- createDefaultProfiles();
-
- return {
- /**
- * Creates new output profile and adds it into internal dictionary
- * @param {String} name Profile name
- * @param {Object} options Profile options
- * @memberOf emmet.profile
- * @returns {Object} New profile
- */
- create: function(name, options) {
- if (arguments.length == 2)
- return createProfile(name, options);
- else
- // create profile object only
- return new OutputProfile(utils.defaults(name || {}, defaultProfile));
- },
-
- /**
- * Returns profile by its name. If profile wasn't found, returns
- * 'plain' profile
- * @param {String} name Profile name. Might be profile itself
- * @param {String} syntax. Optional. Current editor syntax. If defined,
- * profile is searched in resources first, then in predefined profiles
- * @returns {Object}
- */
- get: function(name, syntax) {
- if (!name && syntax) {
- // search in user resources first
- var profile = resources.findItem(syntax, 'profile');
- if (profile) {
- name = profile;
- }
- }
-
- if (!name) {
- return profiles.plain;
- }
-
- if (name instanceof OutputProfile) {
- return name;
- }
-
- if (typeof name === 'string' && name.toLowerCase() in profiles) {
- return profiles[name.toLowerCase()];
- }
-
- return this.create(name);
- },
-
- /**
- * Deletes profile with specified name
- * @param {String} name Profile name
- */
- remove: function(name) {
- name = (name || '').toLowerCase();
- if (name in profiles)
- delete profiles[name];
- },
-
- /**
- * Resets all user-defined profiles
- */
- reset: function() {
- profiles = {};
- createDefaultProfiles();
- },
-
- /**
- * Helper function that converts string case depending on
- *
caseValue
- * @param {String} str String to transform
- * @param {String} caseValue Case value: can be
lower ,
- *
upper and
leave
- * @returns {String}
- */
- stringCase: stringCase
- };
-});
-
-},{"../utils/common":"utils\\common.js","./preferences":"assets\\preferences.js","./resources":"assets\\resources.js"}],"assets\\range.js":[function(require,module,exports){
-/**
- * Helper module to work with ranges
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- function cmp(a, b, op) {
- switch (op) {
- case 'eq':
- case '==':
- return a === b;
- case 'lt':
- case '<':
- return a < b;
- case 'lte':
- case '<=':
- return a <= b;
- case 'gt':
- case '>':
- return a > b;
- case 'gte':
- case '>=':
- return a >= b;
- }
- }
-
-
- /**
- * @type Range
- * @constructor
- * @param {Object} start
- * @param {Number} len
- */
- function Range(start, len) {
- if (typeof start === 'object' && 'start' in start) {
- // create range from object stub
- this.start = Math.min(start.start, start.end);
- this.end = Math.max(start.start, start.end);
- } else if (Array.isArray(start)) {
- this.start = start[0];
- this.end = start[1];
- } else {
- len = typeof len === 'string' ? len.length : +len;
- this.start = start;
- this.end = start + len;
- }
- }
-
- Range.prototype = {
- length: function() {
- return Math.abs(this.end - this.start);
- },
-
- /**
- * Returns
true if passed range is equals to current one
- * @param {Range} range
- * @returns {Boolean}
- */
- equal: function(range) {
- return this.cmp(range, 'eq', 'eq');
-// return this.start === range.start && this.end === range.end;
- },
-
- /**
- * Shifts indexes position with passed
delta
- * @param {Number} delta
- * @returns {Range} range itself
- */
- shift: function(delta) {
- this.start += delta;
- this.end += delta;
- return this;
- },
-
- /**
- * Check if two ranges are overlapped
- * @param {Range} range
- * @returns {Boolean}
- */
- overlap: function(range) {
- return range.start <= this.end && range.end >= this.start;
- },
-
- /**
- * Finds intersection of two ranges
- * @param {Range} range
- * @returns {Range}
null if ranges does not overlap
- */
- intersection: function(range) {
- if (this.overlap(range)) {
- var start = Math.max(range.start, this.start);
- var end = Math.min(range.end, this.end);
- return new Range(start, end - start);
- }
-
- return null;
- },
-
- /**
- * Returns the union of the thow ranges.
- * @param {Range} range
- * @returns {Range}
null if ranges are not overlapped
- */
- union: function(range) {
- if (this.overlap(range)) {
- var start = Math.min(range.start, this.start);
- var end = Math.max(range.end, this.end);
- return new Range(start, end - start);
- }
-
- return null;
- },
-
- /**
- * Returns a Boolean value that indicates whether a specified position
- * is in a given range.
- * @param {Number} loc
- */
- inside: function(loc) {
- return this.cmp(loc, 'lte', 'gt');
-// return this.start <= loc && this.end > loc;
- },
-
- /**
- * Returns a Boolean value that indicates whether a specified position
- * is in a given range, but not equals bounds.
- * @param {Number} loc
- */
- contains: function(loc) {
- return this.cmp(loc, 'lt', 'gt');
- },
-
- /**
- * Check if current range completely includes specified one
- * @param {Range} r
- * @returns {Boolean}
- */
- include: function(r) {
- return this.cmp(r, 'lte', 'gte');
-// return this.start <= r.start && this.end >= r.end;
- },
-
- /**
- * Low-level comparision method
- * @param {Number} loc
- * @param {String} left Left comparison operator
- * @param {String} right Right comaprison operator
- */
- cmp: function(loc, left, right) {
- var a, b;
- if (loc instanceof Range) {
- a = loc.start;
- b = loc.end;
- } else {
- a = b = loc;
- }
-
- return cmp(this.start, a, left || '<=') && cmp(this.end, b, right || '>');
- },
-
- /**
- * Returns substring of specified
str for current range
- * @param {String} str
- * @returns {String}
- */
- substring: function(str) {
- return this.length() > 0
- ? str.substring(this.start, this.end)
- : '';
- },
-
- /**
- * Creates copy of current range
- * @returns {Range}
- */
- clone: function() {
- return new Range(this.start, this.length());
- },
-
- /**
- * @returns {Array}
- */
- toArray: function() {
- return [this.start, this.end];
- },
-
- toString: function() {
- return this.valueOf();
- },
-
- valueOf: function() {
- return '{' + this.start + ', ' + this.length() + '}';
- }
- };
-
- /**
- * Creates new range object instance
- * @param {Object} start Range start or array with 'start' and 'end'
- * as two first indexes or object with 'start' and 'end' properties
- * @param {Number} len Range length or string to produce range from
- * @returns {Range}
- */
- module.exports = function(start, len) {
- if (typeof start == 'undefined' || start === null)
- return null;
-
- if (start instanceof Range)
- return start;
-
- if (typeof start == 'object' && 'start' in start && 'end' in start) {
- len = start.end - start.start;
- start = start.start;
- }
-
- return new Range(start, len);
- };
-
- module.exports.create = module.exports;
-
- module.exports.isRange = function(val) {
- return val instanceof Range;
- };
-
- /**
- *
Range object factory, the same as
this.create()
- * but last argument represents end of range, not length
- * @returns {Range}
- */
- module.exports.create2 = function(start, end) {
- if (typeof start === 'number' && typeof end === 'number') {
- end -= start;
- }
-
- return this.create(start, end);
- };
-
- /**
- * Helper function that sorts ranges in order as they
- * appear in text
- * @param {Array} ranges
- * @return {Array}
- */
- module.exports.sort = function(ranges, reverse) {
- ranges = ranges.sort(function(a, b) {
- if (a.start === b.start) {
- return b.end - a.end;
- }
-
- return a.start - b.start;
- });
-
- reverse && ranges.reverse();
- return ranges;
- };
-
- return module.exports;
-});
-},{}],"assets\\resources.js":[function(require,module,exports){
-/**
- * Parsed resources (snippets, abbreviations, variables, etc.) for Emmet.
- * Contains convenient method to get access for snippets with respect of
- * inheritance. Also provides ability to store data in different vocabularies
- * ('system' and 'user') for fast and safe resource update
- * @author Sergey Chikuyonok (serge.che@gmail.com)
- * @link http://chikuyonok.ru
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var handlerList = require('./handlerList');
- var utils = require('../utils/common');
- var elements = require('./elements');
- var logger = require('../assets/logger');
- var stringScore = require('../vendor/stringScore');
- var cssResolver = require('../resolver/css');
-
- var VOC_SYSTEM = 'system';
- var VOC_USER = 'user';
-
- var cache = {};
-
- /** Regular expression for XML tag matching */
- var reTag = /^<(\w+\:?[\w\-]*)((?:\s+[@\!]?[\w\:\-]+\s*=\s*(['"]).*?\3)*)\s*(\/?)>/;
-
- var systemSettings = {};
- var userSettings = {};
-
- /** @type HandlerList List of registered abbreviation resolvers */
- var resolvers = handlerList.create();
-
- function each(obj, fn) {
- if (!obj) {
- return;
- }
-
- Object.keys(obj).forEach(function(key) {
- fn(obj[key], key);
- });
- }
-
- /**
- * Normalizes caret plceholder in passed text: replaces | character with
- * default caret placeholder
- * @param {String} text
- * @returns {String}
- */
- function normalizeCaretPlaceholder(text) {
- return utils.replaceUnescapedSymbol(text, '|', utils.getCaretPlaceholder());
- }
-
- function parseItem(name, value, type) {
- value = normalizeCaretPlaceholder(value);
-
- if (type == 'snippets') {
- return elements.create('snippet', value);
- }
-
- if (type == 'abbreviations') {
- return parseAbbreviation(name, value);
- }
- }
-
- /**
- * Parses single abbreviation
- * @param {String} key Abbreviation name
- * @param {String} value Abbreviation value
- * @return {Object}
- */
- function parseAbbreviation(key, value) {
- key = utils.trim(key);
- var m;
- if ((m = reTag.exec(value))) {
- return elements.create('element', m[1], m[2], m[4] == '/');
- } else {
- // assume it's reference to another abbreviation
- return elements.create('reference', value);
- }
- }
-
- /**
- * Normalizes snippet key name for better fuzzy search
- * @param {String} str
- * @returns {String}
- */
- function normalizeName(str) {
- return str.replace(/:$/, '').replace(/:/g, '-');
- }
-
- function expandSnippetsDefinition(snippets) {
- var out = {};
- each(snippets, function(val, key) {
- var items = key.split('|');
- // do not use iterators for better performance
- for (var i = items.length - 1; i >= 0; i--) {
- out[items[i]] = val;
- }
- });
-
- return out;
- }
-
- utils.extend(exports, {
- /**
- * Sets new unparsed data for specified settings vocabulary
- * @param {Object} data
- * @param {String} type Vocabulary type ('system' or 'user')
- * @memberOf resources
- */
- setVocabulary: function(data, type) {
- cache = {};
-
- // sections like "snippets" and "abbreviations" could have
- // definitions like `"f|fs": "fieldset"` which is the same as distinct
- // "f" and "fs" keys both equals to "fieldset".
- // We should parse these definitions first
- var voc = {};
- each(data, function(section, syntax) {
- var _section = {};
- each(section, function(subsection, name) {
- if (name == 'abbreviations' || name == 'snippets') {
- subsection = expandSnippetsDefinition(subsection);
- }
- _section[name] = subsection;
- });
-
- voc[syntax] = _section;
- });
-
-
- if (type == VOC_SYSTEM) {
- systemSettings = voc;
- } else {
- userSettings = voc;
- }
- },
-
- /**
- * Returns resource vocabulary by its name
- * @param {String} name Vocabulary name ('system' or 'user')
- * @return {Object}
- */
- getVocabulary: function(name) {
- return name == VOC_SYSTEM ? systemSettings : userSettings;
- },
-
- /**
- * Returns resource (abbreviation, snippet, etc.) matched for passed
- * abbreviation
- * @param {AbbreviationNode} node
- * @param {String} syntax
- * @returns {Object}
- */
- getMatchedResource: function(node, syntax) {
- return resolvers.exec(null, utils.toArray(arguments))
- || this.findSnippet(syntax, node.name());
- },
-
- /**
- * Returns variable value
- * @return {String}
- */
- getVariable: function(name) {
- return (this.getSection('variables') || {})[name];
- },
-
- /**
- * Store runtime variable in user storage
- * @param {String} name Variable name
- * @param {String} value Variable value
- */
- setVariable: function(name, value){
- var voc = this.getVocabulary('user') || {};
- if (!('variables' in voc))
- voc.variables = {};
-
- voc.variables[name] = value;
- this.setVocabulary(voc, 'user');
- },
-
- /**
- * Check if there are resources for specified syntax
- * @param {String} syntax
- * @return {Boolean}
- */
- hasSyntax: function(syntax) {
- return syntax in this.getVocabulary(VOC_USER)
- || syntax in this.getVocabulary(VOC_SYSTEM);
- },
-
- /**
- * Registers new abbreviation resolver.
- * @param {Function} fn Abbreviation resolver which will receive
- * abbreviation as first argument and should return parsed abbreviation
- * object if abbreviation has handled successfully,
null
- * otherwise
- * @param {Object} options Options list as described in
- * {@link HandlerList#add()} method
- */
- addResolver: function(fn, options) {
- resolvers.add(fn, options);
- },
-
- removeResolver: function(fn) {
- resolvers.remove(fn);
- },
-
- /**
- * Returns actual section data, merged from both
- * system and user data
- * @param {String} name Section name (syntax)
- * @param {String} ...args Subsections
- * @returns
- */
- getSection: function(name) {
- if (!name)
- return null;
-
- if (!(name in cache)) {
- cache[name] = utils.deepMerge({}, systemSettings[name], userSettings[name]);
- }
-
- var data = cache[name], subsections = utils.toArray(arguments, 1), key;
- while (data && (key = subsections.shift())) {
- if (key in data) {
- data = data[key];
- } else {
- return null;
- }
- }
-
- return data;
- },
-
- /**
- * Recursively searches for a item inside top level sections (syntaxes)
- * with respect of `extends` attribute
- * @param {String} topSection Top section name (syntax)
- * @param {String} subsection Inner section name
- * @returns {Object}
- */
- findItem: function(topSection, subsection) {
- var data = this.getSection(topSection);
- while (data) {
- if (subsection in data)
- return data[subsection];
-
- data = this.getSection(data['extends']);
- }
- },
-
- /**
- * Recursively searches for a snippet definition inside syntax section.
- * Definition is searched inside `snippets` and `abbreviations`
- * subsections
- * @param {String} syntax Top-level section name (syntax)
- * @param {String} name Snippet name
- * @returns {Object}
- */
- findSnippet: function(syntax, name, memo) {
- if (!syntax || !name)
- return null;
-
- memo = memo || [];
-
- var names = [name];
- // create automatic aliases to properties with colons,
- // e.g. pos-a == pos:a
- if (~name.indexOf('-')) {
- names.push(name.replace(/\-/g, ':'));
- }
-
- var data = this.getSection(syntax), matchedItem = null;
- ['snippets', 'abbreviations'].some(function(sectionName) {
- var data = this.getSection(syntax, sectionName);
- if (data) {
- return names.some(function(n) {
- if (data[n]) {
- return matchedItem = parseItem(n, data[n], sectionName);
- }
- });
- }
- }, this);
-
- memo.push(syntax);
- if (!matchedItem && data['extends'] && !~memo.indexOf(data['extends'])) {
- // try to find item in parent syntax section
- return this.findSnippet(data['extends'], name, memo);
- }
-
- return matchedItem;
- },
-
- /**
- * Performs fuzzy search of snippet definition
- * @param {String} syntax Top-level section name (syntax)
- * @param {String} name Snippet name
- * @returns
- */
- fuzzyFindSnippet: function(syntax, name, minScore) {
- var result = this.fuzzyFindMatches(syntax, name, minScore)[0];
- if (result) {
- return result.value.parsedValue;
- }
- },
-
- fuzzyFindMatches: function(syntax, name, minScore) {
- minScore = minScore || 0.3;
- name = normalizeName(name);
- var snippets = this.getAllSnippets(syntax);
-
- return Object.keys(snippets)
- .map(function(key) {
- var value = snippets[key];
- return {
- key: key,
- score: stringScore.score(value.nk, name, 0.1),
- value: value
- };
- })
- .filter(function(item) {
- return item.score >= minScore;
- })
- .sort(function(a, b) {
- return a.score - b.score;
- })
- .reverse();
- },
-
- /**
- * Returns plain dictionary of all available abbreviations and snippets
- * for specified syntax with respect of inheritance
- * @param {String} syntax
- * @returns {Object}
- */
- getAllSnippets: function(syntax) {
- var cacheKey = 'all-' + syntax;
- if (!cache[cacheKey]) {
- var stack = [], sectionKey = syntax;
- var memo = [];
-
- do {
- var section = this.getSection(sectionKey);
- if (!section)
- break;
-
- ['snippets', 'abbreviations'].forEach(function(sectionName) {
- var stackItem = {};
- each(section[sectionName] || null, function(v, k) {
- stackItem[k] = {
- nk: normalizeName(k),
- value: v,
- parsedValue: parseItem(k, v, sectionName),
- type: sectionName
- };
- });
-
- stack.push(stackItem);
- });
-
- memo.push(sectionKey);
- sectionKey = section['extends'];
- } while (sectionKey && !~memo.indexOf(sectionKey));
-
-
- cache[cacheKey] = utils.extend.apply(utils, stack.reverse());
- }
-
- return cache[cacheKey];
- },
-
- /**
- * Returns newline character
- * @returns {String}
- */
- getNewline: function() {
- var nl = this.getVariable('newline');
- return typeof nl === 'string' ? nl : '\n';
- },
-
- /**
- * Sets new newline character that will be used in output
- * @param {String} str
- */
- setNewline: function(str) {
- this.setVariable('newline', str);
- this.setVariable('nl', str);
- }
- });
-
- // XXX add default resolvers
- exports.addResolver(cssResolver.resolve.bind(cssResolver));
-
- // try to load snippets
- // hide it from Require.JS parser
- (function(r) {
- if (typeof define === 'undefined' || !define.amd) {
- try {
- exports.setVocabulary(r('../snippets.json'), VOC_SYSTEM);
- } catch (e) {}
- }
- })(require);
-
-
- return exports;
-});
-
-},{"../assets/logger":"assets\\logger.js","../resolver/css":"resolver\\css.js","../utils/common":"utils\\common.js","../vendor/stringScore":"vendor\\stringScore.js","./elements":"assets\\elements.js","./handlerList":"assets\\handlerList.js"}],"assets\\stringStream.js":[function(require,module,exports){
-/**
- * A trimmed version of CodeMirror's StringStream module for string parsing
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- /**
- * @type StringStream
- * @constructor
- * @param {String} string Assuming that bound string should be
- * immutable
- */
- function StringStream(string) {
- this.pos = this.start = 0;
- this.string = string;
- this._length = string.length;
- }
-
- StringStream.prototype = {
- /**
- * Returns true only if the stream is at the end of the line.
- * @returns {Boolean}
- */
- eol: function() {
- return this.pos >= this._length;
- },
-
- /**
- * Returns true only if the stream is at the start of the line
- * @returns {Boolean}
- */
- sol: function() {
- return this.pos === 0;
- },
-
- /**
- * Returns the next character in the stream without advancing it.
- * Will return
undefined at the end of the line.
- * @returns {String}
- */
- peek: function() {
- return this.string.charAt(this.pos);
- },
-
- /**
- * Returns the next character in the stream and advances it.
- * Also returns
undefined when no more characters are available.
- * @returns {String}
- */
- next: function() {
- if (this.pos < this._length)
- return this.string.charAt(this.pos++);
- },
-
- /**
- * match can be a character, a regular expression, or a function that
- * takes a character and returns a boolean. If the next character in the
- * stream 'matches' the given argument, it is consumed and returned.
- * Otherwise, undefined is returned.
- * @param {Object} match
- * @returns {String}
- */
- eat: function(match) {
- var ch = this.string.charAt(this.pos), ok;
- if (typeof match == "string")
- ok = ch == match;
- else
- ok = ch && (match.test ? match.test(ch) : match(ch));
-
- if (ok) {
- ++this.pos;
- return ch;
- }
- },
-
- /**
- * Repeatedly calls
eat with the given argument, until it
- * fails. Returns
true if any characters were eaten.
- * @param {Object} match
- * @returns {Boolean}
- */
- eatWhile: function(match) {
- var start = this.pos;
- while (this.eat(match)) {}
- return this.pos > start;
- },
-
- /**
- * Shortcut for
eatWhile when matching white-space.
- * @returns {Boolean}
- */
- eatSpace: function() {
- var start = this.pos;
- while (/[\s\u00a0]/.test(this.string.charAt(this.pos)))
- ++this.pos;
- return this.pos > start;
- },
-
- /**
- * Moves the position to the end of the line.
- */
- skipToEnd: function() {
- this.pos = this._length;
- },
-
- /**
- * Skips to the next occurrence of the given character, if found on the
- * current line (doesn't advance the stream if the character does not
- * occur on the line). Returns true if the character was found.
- * @param {String} ch
- * @returns {Boolean}
- */
- skipTo: function(ch) {
- var found = this.string.indexOf(ch, this.pos);
- if (found > -1) {
- this.pos = found;
- return true;
- }
- },
-
- /**
- * Skips to
close character which is pair to
open
- * character, considering possible pair nesting. This function is used
- * to consume pair of characters, like opening and closing braces
- * @param {String} open
- * @param {String} close
- * @returns {Boolean} Returns
true if pair was successfully
- * consumed
- */
- skipToPair: function(open, close, skipString) {
- var braceCount = 0, ch;
- var pos = this.pos, len = this._length;
- while (pos < len) {
- ch = this.string.charAt(pos++);
- if (ch == open) {
- braceCount++;
- } else if (ch == close) {
- braceCount--;
- if (braceCount < 1) {
- this.pos = pos;
- return true;
- }
- } else if (skipString && (ch == '"' || ch == "'")) {
- this.skipString(ch);
- }
- }
-
- return false;
- },
-
- /**
- * A helper function which, in case of either single or
- * double quote was found in current position, skips entire
- * string (quoted value)
- * @return {Boolean} Wether quoted string was skipped
- */
- skipQuoted: function(noBackup) {
- var ch = this.string.charAt(noBackup ? this.pos : this.pos - 1);
- if (ch === '"' || ch === "'") {
- if (noBackup) {
- this.pos++;
- }
- return this.skipString(ch);
- }
- },
-
- /**
- * A custom function to skip string literal, e.g. a "double-quoted"
- * or 'single-quoted' value
- * @param {String} quote An opening quote
- * @return {Boolean}
- */
- skipString: function(quote) {
- var pos = this.pos, len = this._length, ch;
- while (pos < len) {
- ch = this.string.charAt(pos++);
- if (ch == '\\') {
- continue;
- } else if (ch == quote) {
- this.pos = pos;
- return true;
- }
- }
-
- return false;
- },
-
- /**
- * Backs up the stream n characters. Backing it up further than the
- * start of the current token will cause things to break, so be careful.
- * @param {Number} n
- */
- backUp : function(n) {
- this.pos -= n;
- },
-
- /**
- * Act like a multi-character
eat—if
consume is true or
- * not given—or a look-ahead that doesn't update the stream position—if
- * it is false.
pattern can be either a string or a
- * regular expression starting with ^. When it is a string,
- *
caseInsensitive can be set to true to make the match
- * case-insensitive. When successfully matching a regular expression,
- * the returned value will be the array returned by
match,
- * in case you need to extract matched groups.
- *
- * @param {RegExp} pattern
- * @param {Boolean} consume
- * @param {Boolean} caseInsensitive
- * @returns
- */
- match: function(pattern, consume, caseInsensitive) {
- if (typeof pattern == "string") {
- var cased = caseInsensitive
- ? function(str) {return str.toLowerCase();}
- : function(str) {return str;};
-
- if (cased(this.string).indexOf(cased(pattern), this.pos) == this.pos) {
- if (consume !== false)
- this.pos += pattern.length;
- return true;
- }
- } else {
- var match = this.string.slice(this.pos).match(pattern);
- if (match && consume !== false)
- this.pos += match[0].length;
- return match;
- }
- },
-
- /**
- * Get the string between the start of the current token and the
- * current stream position.
- * @returns {String}
- */
- current: function(backUp) {
- return this.string.slice(this.start, this.pos - (backUp ? 1 : 0));
- }
- };
-
- module.exports = function(string) {
- return new StringStream(string);
- };
-
- /** @deprecated */
- module.exports.create = module.exports;
- return module.exports;
-});
-},{}],"assets\\tabStops.js":[function(require,module,exports){
-/**
- * Utility module for handling tabstops tokens generated by Emmet's
- * "Expand Abbreviation" action. The main
extract method will take
- * raw text (for example:
${0} some ${1:text} ), find all tabstops
- * occurrences, replace them with tokens suitable for your editor of choice and
- * return object with processed text and list of found tabstops and their ranges.
- * For sake of portability (Objective-C/Java) the tabstops list is a plain
- * sorted array with plain objects.
- *
- * Placeholders with the same are meant to be
linked in your editor.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../utils/common');
- var stringStream = require('./stringStream');
- var resources = require('./resources');
-
- /**
- * Global placeholder value, automatically incremented by
- *
variablesResolver() function
- */
- var startPlaceholderNum = 100;
- var tabstopIndex = 0;
-
- var defaultOptions = {
- replaceCarets: false,
- escape: function(ch) {
- return '\\' + ch;
- },
- tabstop: function(data) {
- return data.token;
- },
- variable: function(data) {
- return data.token;
- }
- };
-
- return {
- /**
- * Main function that looks for a tabstops in provided
text
- * and returns a processed version of
text with expanded
- * placeholders and list of tabstops found.
- * @param {String} text Text to process
- * @param {Object} options List of processor options:
- *
- *
replaceCarets :
Boolean — replace all default
- * caret placeholders (like
{%::emmet-caret::%} ) with
${0:caret}
- *
- *
escape :
Function — function that handle escaped
- * characters (mostly '$'). By default, it returns the character itself
- * to be displayed as is in output, but sometimes you will use
- *
extract method as intermediate solution for further
- * processing and want to keep character escaped. Thus, you should override
- *
escape method to return escaped symbol (e.g. '\\$')
- *
- *
tabstop :
Function – a tabstop handler. Receives
- * a single argument – an object describing token: its position, number
- * group, placeholder and token itself. Should return a replacement
- * string that will appear in final output
- *
- *
variable :
Function – variable handler. Receives
- * a single argument – an object describing token: its position, name
- * and original token itself. Should return a replacement
- * string that will appear in final output
- *
- * @returns {Object} Object with processed
text property
- * and array of
tabstops found
- * @memberOf tabStops
- */
- extract: function(text, options) {
- // prepare defaults
- var placeholders = {carets: ''};
- var marks = [];
-
- options = utils.extend({}, defaultOptions, options, {
- tabstop: function(data) {
- var token = data.token;
- var ret = '';
- if (data.placeholder == 'cursor') {
- marks.push({
- start: data.start,
- end: data.start + token.length,
- group: 'carets',
- value: ''
- });
- } else {
- // unify placeholder value for single group
- if ('placeholder' in data)
- placeholders[data.group] = data.placeholder;
-
- if (data.group in placeholders)
- ret = placeholders[data.group];
-
- marks.push({
- start: data.start,
- end: data.start + token.length,
- group: data.group,
- value: ret
- });
- }
-
- return token;
- }
- });
-
- if (options.replaceCarets) {
- text = text.replace(new RegExp( utils.escapeForRegexp( utils.getCaretPlaceholder() ), 'g'), '${0:cursor}');
- }
-
- // locate tabstops and unify group's placeholders
- text = this.processText(text, options);
-
- // now, replace all tabstops with placeholders
- var buf = '', lastIx = 0;
- var tabStops = marks.map(function(mark) {
- buf += text.substring(lastIx, mark.start);
-
- var pos = buf.length;
- var ph = placeholders[mark.group] || '';
-
- buf += ph;
- lastIx = mark.end;
-
- return {
- group: mark.group,
- start: pos,
- end: pos + ph.length
- };
- });
-
- buf += text.substring(lastIx);
-
- return {
- text: buf,
- tabstops: tabStops.sort(function(a, b) {
- return a.start - b.start;
- })
- };
- },
-
- /**
- * Text processing routine. Locates escaped characters and tabstops and
- * replaces them with values returned by handlers defined in
- *
options
- * @param {String} text
- * @param {Object} options See
extract method options
- * description
- * @returns {String}
- */
- processText: function(text, options) {
- options = utils.extend({}, defaultOptions, options);
-
- var buf = '';
- /** @type StringStream */
- var stream = stringStream.create(text);
- var ch, m, a;
-
- while ((ch = stream.next())) {
- if (ch == '\\' && !stream.eol()) {
- // handle escaped character
- buf += options.escape(stream.next());
- continue;
- }
-
- a = ch;
-
- if (ch == '$') {
- // looks like a tabstop
- stream.start = stream.pos - 1;
-
- if ((m = stream.match(/^[0-9]+/))) {
- // it's $N
- a = options.tabstop({
- start: buf.length,
- group: stream.current().substr(1),
- token: stream.current()
- });
- } else if ((m = stream.match(/^\{([a-z_\-][\w\-]*)\}/))) {
- // ${variable}
- a = options.variable({
- start: buf.length,
- name: m[1],
- token: stream.current()
- });
- } else if ((m = stream.match(/^\{([0-9]+)(:.+?)?\}/, false))) {
- // ${N:value} or ${N} placeholder
- // parse placeholder, including nested ones
- stream.skipToPair('{', '}');
-
- var obj = {
- start: buf.length,
- group: m[1],
- token: stream.current()
- };
-
- var placeholder = obj.token.substring(obj.group.length + 2, obj.token.length - 1);
-
- if (placeholder) {
- obj.placeholder = placeholder.substr(1);
- }
-
- a = options.tabstop(obj);
- }
- }
-
- buf += a;
- }
-
- return buf;
- },
-
- /**
- * Upgrades tabstops in output node in order to prevent naming conflicts
- * @param {AbbreviationNode} node
- * @param {Number} offset Tab index offset
- * @returns {Number} Maximum tabstop index in element
- */
- upgrade: function(node, offset) {
- var maxNum = 0;
- var options = {
- tabstop: function(data) {
- var group = parseInt(data.group, 10);
- if (group > maxNum) maxNum = group;
-
- if (data.placeholder)
- return '${' + (group + offset) + ':' + data.placeholder + '}';
- else
- return '${' + (group + offset) + '}';
- }
- };
-
- ['start', 'end', 'content'].forEach(function(p) {
- node[p] = this.processText(node[p], options);
- }, this);
-
- return maxNum;
- },
-
- /**
- * Helper function that produces a callback function for
- *
replaceVariables() method from {@link utils}
- * module. This callback will replace variable definitions (like
- * ${var_name}) with their value defined in
resource module,
- * or outputs tabstop with variable name otherwise.
- * @param {AbbreviationNode} node Context node
- * @returns {Function}
- */
- variablesResolver: function(node) {
- var placeholderMemo = {};
- return function(str, varName) {
- // do not mark `child` variable as placeholder – it‘s a reserved
- // variable name
- if (varName == 'child') {
- return str;
- }
-
- if (varName == 'cursor') {
- return utils.getCaretPlaceholder();
- }
-
- var attr = node.attribute(varName);
- if (typeof attr !== 'undefined' && attr !== str) {
- return attr;
- }
-
- var varValue = resources.getVariable(varName);
- if (varValue) {
- return varValue;
- }
-
- // output as placeholder
- if (!placeholderMemo[varName]) {
- placeholderMemo[varName] = startPlaceholderNum++;
- }
-
- return '${' + placeholderMemo[varName] + ':' + varName + '}';
- };
- },
-
- /**
- * Replace variables like ${var} in string
- * @param {String} str
- * @param {Object} vars Variable set (defaults to variables defined in
- *
snippets.json) or variable resolver (
Function)
- * @return {String}
- */
- replaceVariables: function(str, vars) {
- vars = vars || {};
- var resolver = typeof vars === 'function' ? vars : function(str, p1) {
- return p1 in vars ? vars[p1] : null;
- };
-
- return this.processText(str, {
- variable: function(data) {
- var newValue = resolver(data.token, data.name, data);
- if (newValue === null) {
- // try to find variable in resources
- newValue = resources.getVariable(data.name);
- }
-
- if (newValue === null || typeof newValue === 'undefined')
- // nothing found, return token itself
- newValue = data.token;
- return newValue;
- }
- });
- },
-
- /**
- * Resets global tabstop index. When parsed tree is converted to output
- * string (
AbbreviationNode.toString()), all tabstops
- * defined in snippets and elements are upgraded in order to prevent
- * naming conflicts of nested. For example,
${1} of a node
- * should not be linked with the same placehilder of the child node.
- * By default,
AbbreviationNode.toString() automatically
- * upgrades tabstops of the same index for each node and writes maximum
- * tabstop index into the
tabstopIndex variable. To keep
- * this variable at reasonable value, it is recommended to call
- *
resetTabstopIndex() method each time you expand variable
- * @returns
- */
- resetTabstopIndex: function() {
- tabstopIndex = 0;
- startPlaceholderNum = 100;
- },
-
- /**
- * Output processor for abbreviation parser that will upgrade tabstops
- * of parsed node in order to prevent tabstop index conflicts
- */
- abbrOutputProcessor: function(text, node, type) {
- var maxNum = 0;
- var that = this;
-
- var tsOptions = {
- tabstop: function(data) {
- var group = parseInt(data.group, 10);
- if (group === 0)
- return '${0}';
-
- if (group > maxNum) maxNum = group;
- if (data.placeholder) {
- // respect nested placeholders
- var ix = group + tabstopIndex;
- var placeholder = that.processText(data.placeholder, tsOptions);
- return '${' + ix + ':' + placeholder + '}';
- } else {
- return '${' + (group + tabstopIndex) + '}';
- }
- }
- };
-
- // upgrade tabstops
- text = this.processText(text, tsOptions);
-
- // resolve variables
- text = this.replaceVariables(text, this.variablesResolver(node));
-
- tabstopIndex += maxNum + 1;
- return text;
- }
- };
-});
-},{"../utils/common":"utils\\common.js","./resources":"assets\\resources.js","./stringStream":"assets\\stringStream.js"}],"assets\\tokenIterator.js":[function(require,module,exports){
-/**
- * Helper class for convenient token iteration
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- /**
- * @type TokenIterator
- * @param {Array} tokens
- * @type TokenIterator
- * @constructor
- */
- function TokenIterator(tokens) {
- /** @type Array */
- this.tokens = tokens;
- this._position = 0;
- this.reset();
- }
-
- TokenIterator.prototype = {
- next: function() {
- if (this.hasNext()) {
- var token = this.tokens[++this._i];
- this._position = token.start;
- return token;
- } else {
- this._i = this._il;
- }
-
- return null;
- },
-
- current: function() {
- return this.tokens[this._i];
- },
-
- peek: function() {
- return this.tokens[this._i + i];
- },
-
- position: function() {
- return this._position;
- },
-
- hasNext: function() {
- return this._i < this._il - 1;
- },
-
- reset: function() {
- this._i = 0;
- this._il = this.tokens.length;
- },
-
- item: function() {
- return this.tokens[this._i];
- },
-
- itemNext: function() {
- return this.tokens[this._i + 1];
- },
-
- itemPrev: function() {
- return this.tokens[this._i - 1];
- },
-
- nextUntil: function(type, callback) {
- var token;
- var test = typeof type == 'string'
- ? function(t){return t.type == type;}
- : type;
-
- while ((token = this.next())) {
- if (callback)
- callback.call(this, token);
- if (test.call(this, token))
- break;
- }
- }
- };
-
- return {
- create: function(tokens) {
- return new TokenIterator(tokens);
- }
- };
-});
-},{}],"editTree\\base.js":[function(require,module,exports){
-/**
- * Abstract implementation of edit tree interface.
- * Edit tree is a named container of editable “name-value” child elements,
- * parsed from
source. This container provides convenient methods
- * for editing/adding/removing child elements. All these update actions are
- * instantly reflected in the
source code with respect of formatting.
- *
- * For example, developer can create an edit tree from CSS rule and add or
- * remove properties from it–all changes will be immediately reflected in the
- * original source.
- *
- * All classes defined in this module should be extended the same way as in
- * Backbone framework: using
extend method to create new class and
- *
initialize method to define custom class constructor.
- *
- * @example
- *
- * var MyClass = require('editTree/base').EditElement.extend({
- * initialize: function() {
- * // constructor code here
- * }
- * });
- *
- * var elem = new MyClass();
- *
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var range = require('../assets/range');
- var utils = require('../utils/common');
- var klass = require('../vendor/klass');
-
- /**
- * Named container of edited source
- * @type EditContainer
- * @param {String} source
- * @param {Object} options
- */
- function EditContainer(source, options) {
- this.options = utils.extend({offset: 0}, options);
- /**
- * Source code of edited structure. All changes in the structure are
- * immediately reflected into this property
- */
- this.source = source;
-
- /**
- * List of all editable children
- * @private
- */
- this._children = [];
-
- /**
- * Hash of all positions of container
- * @private
- */
- this._positions = {
- name: 0
- };
-
- this.initialize.apply(this, arguments);
- }
-
- /**
- * The self-propagating extend function for classes.
- * @type Function
- */
- EditContainer.extend = klass.extend;
-
- EditContainer.prototype = {
- type: 'container',
- /**
- * Child class constructor
- */
- initialize: function() {},
-
- /**
- * Make position absolute
- * @private
- * @param {Number} num
- * @param {Boolean} isAbsolute
- * @returns {Boolean}
- */
- _pos: function(num, isAbsolute) {
- return num + (isAbsolute ? this.options.offset : 0);
- },
-
- /**
- * Replace substring of tag's source
- * @param {String} value
- * @param {Number} start
- * @param {Number} end
- * @private
- */
- _updateSource: function(value, start, end) {
- // create modification range
- var r = range.create(start, typeof end === 'undefined' ? 0 : end - start);
- var delta = value.length - r.length();
-
- var update = function(obj) {
- Object.keys(obj).forEach(function(k) {
- if (obj[k] >= r.end) {
- obj[k] += delta;
- }
- });
- };
-
- // update affected positions of current container
- update(this._positions);
-
- // update affected positions of children
- var recursiveUpdate = function(items) {
- items.forEach(function(item) {
- update(item._positions);
- if (item.type == 'container') {
- recursiveUpdate(item.list());
- }
- });
- };
-
- recursiveUpdate(this.list());
- this.source = utils.replaceSubstring(this.source, value, r);
- },
-
-
- /**
- * Adds new attribute
- * @param {String} name Property name
- * @param {String} value Property value
- * @param {Number} pos Position at which to insert new property. By
- * default the property is inserted at the end of rule
- * @returns {EditElement} Newly created element
- */
- add: function(name, value, pos) {
- // this is abstract implementation
- var item = new EditElement(name, value);
- this._children.push(item);
- return item;
- },
-
- /**
- * Returns attribute object
- * @param {String} name Attribute name or its index
- * @returns {EditElement}
- */
- get: function(name) {
- if (typeof name === 'number') {
- return this.list()[name];
- }
-
- if (typeof name === 'string') {
- return utils.find(this.list(), function(prop) {
- return prop.name() === name;
- });
- }
-
- return name;
- },
-
- /**
- * Returns all children by name or indexes
- * @param {Object} name Element name(s) or indexes (
String,
- *
Array,
Number)
- * @returns {Array}
- */
- getAll: function(name) {
- if (!Array.isArray(name))
- name = [name];
-
- // split names and indexes
- var names = [], indexes = [];
- name.forEach(function(item) {
- if (typeof item === 'string') {
- names.push(item);
- } else if (typeof item === 'number') {
- indexes.push(item);
- }
- });
-
- return this.list().filter(function(attribute, i) {
- return ~indexes.indexOf(i) || ~names.indexOf(attribute.name());
- });
- },
-
- /**
- * Returns list of all editable child elements
- * @returns {Array}
- */
- list: function() {
- return this._children;
- },
-
- /**
- * Remove child element
- * @param {String} name Property name or its index
- */
- remove: function(name) {
- var element = this.get(name);
- if (element) {
- this._updateSource('', element.fullRange());
- var ix = this._children.indexOf(element);
- if (~ix) {
- this._children.splice(ix, 1);
- }
- }
- },
-
- /**
- * Returns index of editble child in list
- * @param {Object} item
- * @returns {Number}
- */
- indexOf: function(item) {
- return this.list().indexOf(this.get(item));
- },
-
- /**
- * Returns or updates element value. If such element doesn't exists,
- * it will be created automatically and added at the end of child list.
- * @param {String} name Element name or its index
- * @param {String} value New element value
- * @returns {String}
- */
- value: function(name, value, pos) {
- var element = this.get(name);
- if (element)
- return element.value(value);
-
- if (typeof value !== 'undefined') {
- // no such element — create it
- return this.add(name, value, pos);
- }
- },
-
- /**
- * Returns all values of child elements found by
getAll()
- * method
- * @param {Object} name Element name(s) or indexes (
String,
- *
Array,
Number)
- * @returns {Array}
- */
- values: function(name) {
- return this.getAll(name).map(function(element) {
- return element.value();
- });
- },
-
- /**
- * Sets or gets container name
- * @param {String} val New name. If not passed, current
- * name is returned
- * @return {String}
- */
- name: function(val) {
- if (typeof val !== 'undefined' && this._name !== (val = String(val))) {
- this._updateSource(val, this._positions.name, this._positions.name + this._name.length);
- this._name = val;
- }
-
- return this._name;
- },
-
- /**
- * Returns name range object
- * @param {Boolean} isAbsolute Return absolute range (with respect of
- * rule offset)
- * @returns {Range}
- */
- nameRange: function(isAbsolute) {
- return range.create(this._positions.name + (isAbsolute ? this.options.offset : 0), this.name());
- },
-
- /**
- * Returns range of current source
- * @param {Boolean} isAbsolute
- */
- range: function(isAbsolute) {
- return range.create(isAbsolute ? this.options.offset : 0, this.valueOf());
- },
-
- /**
- * Returns element that belongs to specified position
- * @param {Number} pos
- * @param {Boolean} isAbsolute
- * @returns {EditElement}
- */
- itemFromPosition: function(pos, isAbsolute) {
- return utils.find(this.list(), function(elem) {
- return elem.range(isAbsolute).inside(pos);
- });
- },
-
- /**
- * Returns source code of current container
- * @returns {String}
- */
- toString: function() {
- return this.valueOf();
- },
-
- valueOf: function() {
- return this.source;
- }
- };
-
- /**
- * @param {EditContainer} parent
- * @param {Object} nameToken
- * @param {Object} valueToken
- */
- function EditElement(parent, nameToken, valueToken) {
- /** @type EditContainer */
- this.parent = parent;
-
- this._name = nameToken.value;
- this._value = valueToken ? valueToken.value : '';
-
- this._positions = {
- name: nameToken.start,
- value: valueToken ? valueToken.start : -1
- };
-
- this.initialize.apply(this, arguments);
- }
-
- /**
- * The self-propagating extend function for classes.
- * @type Function
- */
- EditElement.extend = klass.extend;
-
- EditElement.prototype = {
- type: 'element',
-
- /**
- * Child class constructor
- */
- initialize: function() {},
-
- /**
- * Make position absolute
- * @private
- * @param {Number} num
- * @param {Boolean} isAbsolute
- * @returns {Boolean}
- */
- _pos: function(num, isAbsolute) {
- return num + (isAbsolute ? this.parent.options.offset : 0);
- },
-
- /**
- * Sets of gets element value
- * @param {String} val New element value. If not passed, current
- * value is returned
- * @returns {String}
- */
- value: function(val) {
- if (typeof val !== 'undefined' && this._value !== (val = String(val))) {
- this.parent._updateSource(val, this.valueRange());
- this._value = val;
- }
-
- return this._value;
- },
-
- /**
- * Sets of gets element name
- * @param {String} val New element name. If not passed, current
- * name is returned
- * @returns {String}
- */
- name: function(val) {
- if (typeof val !== 'undefined' && this._name !== (val = String(val))) {
- this.parent._updateSource(val, this.nameRange());
- this._name = val;
- }
-
- return this._name;
- },
-
- /**
- * Returns position of element name token
- * @param {Boolean} isAbsolute Return absolute position
- * @returns {Number}
- */
- namePosition: function(isAbsolute) {
- return this._pos(this._positions.name, isAbsolute);
- },
-
- /**
- * Returns position of element value token
- * @param {Boolean} isAbsolute Return absolute position
- * @returns {Number}
- */
- valuePosition: function(isAbsolute) {
- return this._pos(this._positions.value, isAbsolute);
- },
-
- /**
- * Returns element name
- * @param {Boolean} isAbsolute Return absolute range
- * @returns {Range}
- */
- range: function(isAbsolute) {
- return range.create(this.namePosition(isAbsolute), this.valueOf());
- },
-
- /**
- * Returns full element range, including possible indentation
- * @param {Boolean} isAbsolute Return absolute range
- * @returns {Range}
- */
- fullRange: function(isAbsolute) {
- return this.range(isAbsolute);
- },
-
- /**
- * Returns element name range
- * @param {Boolean} isAbsolute Return absolute range
- * @returns {Range}
- */
- nameRange: function(isAbsolute) {
- return range.create(this.namePosition(isAbsolute), this.name());
- },
-
- /**
- * Returns element value range
- * @param {Boolean} isAbsolute Return absolute range
- * @returns {Range}
- */
- valueRange: function(isAbsolute) {
- return range.create(this.valuePosition(isAbsolute), this.value());
- },
-
- /**
- * Returns current element string representation
- * @returns {String}
- */
- toString: function() {
- return this.valueOf();
- },
-
- valueOf: function() {
- return this.name() + this.value();
- }
- };
-
- return {
- EditContainer: EditContainer,
- EditElement: EditElement,
-
- /**
- * Creates token that can be fed to
EditElement
- * @param {Number} start
- * @param {String} value
- * @param {String} type
- * @returns
- */
- createToken: function(start, value, type) {
- var obj = {
- start: start || 0,
- value: value || '',
- type: type
- };
-
- obj.end = obj.start + obj.value.length;
- return obj;
- }
- };
-});
-},{"../assets/range":"assets\\range.js","../utils/common":"utils\\common.js","../vendor/klass":"vendor\\klass.js"}],"editTree\\css.js":[function(require,module,exports){
-/**
- * CSS EditTree is a module that can parse a CSS rule into a tree with
- * convenient methods for adding, modifying and removing CSS properties. These
- * changes can be written back to string with respect of code formatting.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../utils/common');
- var editTree = require('./base');
- var cssParser = require('../parser/css');
- var cssSections = require('../utils/cssSections');
- var range = require('../assets/range');
- var stringStream = require('../assets/stringStream');
- var tokenIterator = require('../assets/tokenIterator');
-
- var defaultOptions = {
- styleBefore: '\n\t',
- styleSeparator: ': ',
- offset: 0
- };
-
- var reSpaceStart = /^\s+/;
- var reSpaceEnd = /\s+$/;
- var WHITESPACE_REMOVE_FROM_START = 1;
- var WHITESPACE_REMOVE_FROM_END = 2;
-
- /**
- * Modifies given range to remove whitespace from beginning
- * and/or from the end
- * @param {Range} rng Range to modify
- * @param {String} text Text that range belongs to
- * @param {Number} mask Mask indicating from which end
- * whitespace should be removed
- * @return {Range}
- */
- function trimWhitespaceInRange(rng, text, mask) {
- mask = mask || (WHITESPACE_REMOVE_FROM_START | WHITESPACE_REMOVE_FROM_END);
- text = rng.substring(text);
- var m;
- if ((mask & WHITESPACE_REMOVE_FROM_START) && (m = text.match(reSpaceStart))) {
- rng.start += m[0].length;
- }
-
- if ((mask & WHITESPACE_REMOVE_FROM_END) && (m = text.match(reSpaceEnd))) {
- rng.end -= m[0].length;
- }
-
- // in case given range is just a whatespace
- if (rng.end < rng.start) {
- rng.end = rng.start;
- }
-
- return rng;
- }
-
- /**
- * Consumes CSS property and value from current token
- * iterator state. Offsets iterator pointer into token
- * that can be used for next value consmption
- * @param {TokenIterator} it
- * @param {String} text
- * @return {Object} Object with `name` and `value` properties
- * ar ranges. Value range can be zero-length.
- */
- function consumeSingleProperty(it, text) {
- var name, value, end;
- var token = it.current();
-
- if (!token) {
- return null;
- }
-
- // skip whitespace
- var ws = {'white': 1, 'line': 1, 'comment': 1};
- while ((token = it.current())) {
- if (!(token.type in ws)) {
- break;
- }
- it.next();
- }
-
- if (!it.hasNext()) {
- return null;
- }
-
- // consume property name
- token = it.current();
- name = range(token.start, token.value);
- var isAtProperty = token.value.charAt(0) == '@';
- while (token = it.next()) {
- name.end = token.end;
- if (token.type == ':' || token.type == 'white') {
- name.end = token.start;
- it.next();
- if (token.type == ':' || isAtProperty) {
- // XXX I really ashame of this hardcode, but I need
- // to stop parsing if this is an SCSS mixin call,
- // for example: @include border-radius(10px)
- break;
- }
- } else if (token.type == ';' || token.type == 'line') {
- // there’s no value, looks like a mixin
- // or a special use case:
- // user is writing a new property or abbreviation
- name.end = token.start;
- value = range(token.start, 0);
- it.next();
- break;
- }
- }
-
- token = it.current();
- if (!value && token) {
- if (token.type == 'line') {
- lastNewline = token;
- }
- // consume value
- value = range(token.start, token.value);
- var lastNewline;
- while ((token = it.next())) {
- value.end = token.end;
- if (token.type == 'line') {
- lastNewline = token;
- } else if (token.type == '}' || token.type == ';') {
- value.end = token.start;
- if (token.type == ';') {
- end = range(token.start, token.value);
- }
- it.next();
- break;
- } else if (token.type == ':' && lastNewline) {
- // A special case:
- // user is writing a value before existing
- // property, but didn’t inserted closing semi-colon.
- // In this case, limit value range to previous
- // newline
- value.end = lastNewline.start;
- it._i = it.tokens.indexOf(lastNewline);
- break;
- }
- }
- }
-
- if (!value) {
- value = range(name.end, 0);
- }
-
- return {
- name: trimWhitespaceInRange(name, text),
- value: trimWhitespaceInRange(value, text, WHITESPACE_REMOVE_FROM_START | (end ? WHITESPACE_REMOVE_FROM_END : 0)),
- end: end || range(value.end, 0)
- };
- }
-
- /**
- * Finds parts of complex CSS value
- * @param {String} str
- * @returns {Array} Returns list of
Range's
- */
- function findParts(str) {
- /** @type StringStream */
- var stream = stringStream.create(str);
- var ch;
- var result = [];
- var sep = /[\s\u00a0,;]/;
-
- var add = function() {
- stream.next();
- result.push(range(stream.start, stream.current()));
- stream.start = stream.pos;
- };
-
- // skip whitespace
- stream.eatSpace();
- stream.start = stream.pos;
-
- while ((ch = stream.next())) {
- if (ch == '"' || ch == "'") {
- stream.next();
- if (!stream.skipTo(ch)) break;
- add();
- } else if (ch == '(') {
- // function found, may have nested function
- stream.backUp(1);
- if (!stream.skipToPair('(', ')')) break;
- stream.backUp(1);
- add();
- } else {
- if (sep.test(ch)) {
- result.push(range(stream.start, stream.current().length - 1));
- stream.eatWhile(sep);
- stream.start = stream.pos;
- }
- }
- }
-
- add();
-
- return utils.unique(result.filter(function(item) {
- return !!item.length();
- }));
- }
-
- /**
- * Parses CSS properties from given CSS source
- * and adds them to CSSEditContainer node
- * @param {CSSEditContainer} node
- * @param {String} source CSS source
- * @param {Number} offset Offset of properties subset from original source
- */
- function consumeProperties(node, source, offset) {
- var list = extractPropertiesFromSource(source, offset);
-
- list.forEach(function(property) {
- node._children.push(new CSSEditElement(node,
- editTree.createToken(property.name.start, property.nameText),
- editTree.createToken(property.value.start, property.valueText),
- editTree.createToken(property.end.start, property.endText)
- ));
- });
- }
-
- /**
- * Parses given CSS source and returns list of ranges of located CSS properties.
- * Normally, CSS source must contain properties only, it must be,
- * for example, a content of CSS selector or text between nested
- * CSS sections
- * @param {String} source CSS source
- * @param {Number} offset Offset of properties subset from original source.
- * Used to provide proper ranges of locates items
- */
- function extractPropertiesFromSource(source, offset) {
- offset = offset || 0;
- source = source.replace(reSpaceEnd, '');
- var out = [];
-
- if (!source) {
- return out;
- }
-
- var tokens = cssParser.parse(source);
- var it = tokenIterator.create(tokens);
- var property;
-
- while ((property = consumeSingleProperty(it, source))) {
- out.push({
- nameText: property.name.substring(source),
- name: property.name.shift(offset),
-
- valueText: property.value.substring(source),
- value: property.value.shift(offset),
-
- endText: property.end.substring(source),
- end: property.end.shift(offset)
- });
- }
-
- return out;
- }
-
- /**
- * @class
- * @extends EditContainer
- */
- var CSSEditContainer = editTree.EditContainer.extend({
- initialize: function(source, options) {
- utils.extend(this.options, defaultOptions, options);
-
- if (Array.isArray(source)) {
- source = cssParser.toSource(source);
- }
-
- var allRules = cssSections.findAllRules(source);
- var currentRule = allRules.shift();
-
- // keep top-level rules only since they will
- // be parsed by nested CSSEditContainer call
- var topLevelRules = [];
- allRules.forEach(function(r) {
- var isTopLevel = !utils.find(topLevelRules, function(tr) {
- return tr.contains(r);
- });
-
- if (isTopLevel) {
- topLevelRules.push(r);
- }
- });
-
-
- var selectorRange = range.create2(currentRule.start, currentRule._selectorEnd);
- this._name = selectorRange.substring(source);
- this._positions.name = selectorRange.start;
- this._positions.contentStart = currentRule._contentStart + 1;
-
- var sectionOffset = currentRule._contentStart + 1;
- var sectionEnd = currentRule.end - 1;
-
- // parse properties between nested rules
- // and add nested rules as children
- var that = this;
- topLevelRules.forEach(function(r) {
- consumeProperties(that, source.substring(sectionOffset, r.start), sectionOffset);
- var opt = utils.extend({}, that.options, {offset: r.start + that.options.offset});
- // XXX I think I don’t need nested containers here
- // They should be handled separately
- // that._children.push(new CSSEditContainer(r.substring(source), opt));
- sectionOffset = r.end;
- });
-
- // consume the rest of data
- consumeProperties(this, source.substring(sectionOffset, currentRule.end - 1), sectionOffset);
- this._saveStyle();
- },
-
- /**
- * Remembers all styles of properties
- * @private
- */
- _saveStyle: function() {
- var start = this._positions.contentStart;
- var source = this.source;
-
- this.list().forEach(function(p) {
- if (p.type === 'container') {
- return;
- }
-
- p.styleBefore = source.substring(start, p.namePosition());
- // a small hack here:
- // Sometimes users add empty lines before properties to logically
- // separate groups of properties. In this case, a blind copy of
- // characters between rules may lead to undesired behavior,
- // especially when current rule is duplicated or used as a donor
- // to create new rule.
- // To solve this issue, we‘ll take only last newline indentation
- var lines = utils.splitByLines(p.styleBefore);
- if (lines.length > 1) {
- p.styleBefore = '\n' + lines[lines.length - 1];
- }
-
- p.styleSeparator = source.substring(p.nameRange().end, p.valuePosition());
-
- // graceful and naive comments removal
- var parts = p.styleBefore.split('*/');
- p.styleBefore = parts[parts.length - 1];
- p.styleSeparator = p.styleSeparator.replace(/\/\*.*?\*\//g, '');
-
- start = p.range().end;
- });
- },
-
- /**
- * Returns position of element name token
- * @param {Boolean} isAbsolute Return absolute position
- * @returns {Number}
- */
- namePosition: function(isAbsolute) {
- return this._pos(this._positions.name, isAbsolute);
- },
-
- /**
- * Returns position of element value token
- * @param {Boolean} isAbsolute Return absolute position
- * @returns {Number}
- */
- valuePosition: function(isAbsolute) {
- return this._pos(this._positions.contentStart, isAbsolute);
- },
-
- /**
- * Returns element value range
- * @param {Boolean} isAbsolute Return absolute range
- * @returns {Range}
- */
- valueRange: function(isAbsolute) {
- return range.create2(this.valuePosition(isAbsolute), this._pos(this.valueOf().length, isAbsolute) - 1);
- },
-
- /**
- * Adds new CSS property
- * @param {String} name Property name
- * @param {String} value Property value
- * @param {Number} pos Position at which to insert new property. By
- * default the property is inserted at the end of rule
- * @returns {CSSEditProperty}
- */
- add: function(name, value, pos) {
- var list = this.list();
- var start = this._positions.contentStart;
- var styles = utils.pick(this.options, 'styleBefore', 'styleSeparator');
-
- if (typeof pos === 'undefined') {
- pos = list.length;
- }
-
- /** @type CSSEditProperty */
- var donor = list[pos];
- if (donor) {
- start = donor.fullRange().start;
- } else if ((donor = list[pos - 1])) {
- // make sure that donor has terminating semicolon
- donor.end(';');
- start = donor.range().end;
- }
-
- if (donor) {
- styles = utils.pick(donor, 'styleBefore', 'styleSeparator');
- }
-
- var nameToken = editTree.createToken(start + styles.styleBefore.length, name);
- var valueToken = editTree.createToken(nameToken.end + styles.styleSeparator.length, value);
-
- var property = new CSSEditElement(this, nameToken, valueToken,
- editTree.createToken(valueToken.end, ';'));
-
- utils.extend(property, styles);
-
- // write new property into the source
- this._updateSource(property.styleBefore + property.toString(), start);
-
- // insert new property
- this._children.splice(pos, 0, property);
- return property;
- }
- });
-
- /**
- * @class
- * @type CSSEditElement
- * @constructor
- */
- var CSSEditElement = editTree.EditElement.extend({
- initialize: function(rule, name, value, end) {
- this.styleBefore = rule.options.styleBefore;
- this.styleSeparator = rule.options.styleSeparator;
-
- this._end = end.value;
- this._positions.end = end.start;
- },
-
- /**
- * Returns ranges of complex value parts
- * @returns {Array} Returns
null if value is not complex
- */
- valueParts: function(isAbsolute) {
- var parts = findParts(this.value());
- if (isAbsolute) {
- var offset = this.valuePosition(true);
- parts.forEach(function(p) {
- p.shift(offset);
- });
- }
-
- return parts;
- },
-
- /**
- * Sets of gets element value.
- * When setting value, this implementation will ensure that your have
- * proper name-value separator
- * @param {String} val New element value. If not passed, current
- * value is returned
- * @returns {String}
- */
- value: function(val) {
- var isUpdating = typeof val !== 'undefined';
- var allItems = this.parent.list();
- if (isUpdating && this.isIncomplete()) {
- var self = this;
- var donor = utils.find(allItems, function(item) {
- return item !== self && !item.isIncomplete();
- });
-
- this.styleSeparator = donor
- ? donor.styleSeparator
- : this.parent.options.styleSeparator;
- this.parent._updateSource(this.styleSeparator, range(this.valueRange().start, 0));
- }
-
- var value = this.constructor.__super__.value.apply(this, arguments);
- if (isUpdating) {
- // make sure current property has terminating semi-colon
- // if it’s not the last one
- var ix = allItems.indexOf(this);
- if (ix !== allItems.length - 1 && !this.end()) {
- this.end(';');
- }
- }
- return value;
- },
-
- /**
- * Test if current element is incomplete, e.g. has no explicit
- * name-value separator
- * @return {Boolean} [description]
- */
- isIncomplete: function() {
- return this.nameRange().end === this.valueRange().start;
- },
-
- /**
- * Sets of gets property end value (basically, it's a semicolon)
- * @param {String} val New end value. If not passed, current
- * value is returned
- */
- end: function(val) {
- if (typeof val !== 'undefined' && this._end !== val) {
- this.parent._updateSource(val, this._positions.end, this._positions.end + this._end.length);
- this._end = val;
- }
-
- return this._end;
- },
-
- /**
- * Returns full rule range, with indentation
- * @param {Boolean} isAbsolute Return absolute range (with respect of
- * rule offset)
- * @returns {Range}
- */
- fullRange: function(isAbsolute) {
- var r = this.range(isAbsolute);
- r.start -= this.styleBefore.length;
- return r;
- },
-
- /**
- * Returns item string representation
- * @returns {String}
- */
- valueOf: function() {
- return this.name() + this.styleSeparator + this.value() + this.end();
- }
- });
-
- return {
- /**
- * Parses CSS rule into editable tree
- * @param {String} source
- * @param {Object} options
- * @memberOf emmet.cssEditTree
- * @returns {EditContainer}
- */
- parse: function(source, options) {
- return new CSSEditContainer(source, options);
- },
-
- /**
- * Extract and parse CSS rule from specified position in
content
- * @param {String} content CSS source code
- * @param {Number} pos Character position where to start source code extraction
- * @returns {EditContainer}
- */
- parseFromPosition: function(content, pos, isBackward) {
- var bounds = cssSections.locateRule(content, pos, isBackward);
- if (!bounds || !bounds.inside(pos)) {
- // no matching CSS rule or caret outside rule bounds
- return null;
- }
-
- return this.parse(bounds.substring(content), {
- offset: bounds.start
- });
- },
-
- /**
- * Locates CSS property in given CSS code fragment under specified character position
- * @param {String} css CSS code or parsed CSSEditContainer
- * @param {Number} pos Character position where to search CSS property
- * @return {CSSEditElement}
- */
- propertyFromPosition: function(css, pos) {
- var cssProp = null;
- /** @type EditContainer */
- var cssRule = typeof css === 'string' ? this.parseFromPosition(css, pos, true) : css;
- if (cssRule) {
- cssProp = cssRule.itemFromPosition(pos, true);
- if (!cssProp) {
- // in case user just started writing CSS property
- // and didn't include semicolon–try another approach
- cssProp = utils.find(cssRule.list(), function(elem) {
- return elem.range(true).end == pos;
- });
- }
- }
-
- return cssProp;
- },
-
- /**
- * Removes vendor prefix from CSS property
- * @param {String} name CSS property
- * @return {String}
- */
- baseName: function(name) {
- return name.replace(/^\s*\-\w+\-/, '');
- },
-
- /**
- * Finds parts of complex CSS value
- * @param {String} str
- * @returns {Array}
- */
- findParts: findParts,
-
- extractPropertiesFromSource: extractPropertiesFromSource
- };
-});
-},{"../assets/range":"assets\\range.js","../assets/stringStream":"assets\\stringStream.js","../assets/tokenIterator":"assets\\tokenIterator.js","../parser/css":"parser\\css.js","../utils/common":"utils\\common.js","../utils/cssSections":"utils\\cssSections.js","./base":"editTree\\base.js"}],"editTree\\xml.js":[function(require,module,exports){
-/**
- * XML EditTree is a module that can parse an XML/HTML element into a tree with
- * convenient methods for adding, modifying and removing attributes. These
- * changes can be written back to string with respect of code formatting.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var editTree = require('./base');
- var xmlParser = require('../parser/xml');
- var range = require('../assets/range');
- var utils = require('../utils/common');
-
- var defaultOptions = {
- styleBefore: ' ',
- styleSeparator: '=',
- styleQuote: '"',
- offset: 0
- };
-
- var startTag = /^<([\w\:\-]+)((?:\s+[\w\-:]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)>/m;
-
- var XMLEditContainer = editTree.EditContainer.extend({
- initialize: function(source, options) {
- utils.defaults(this.options, defaultOptions);
- this._positions.name = 1;
-
- var attrToken = null;
- var tokens = xmlParser.parse(source);
-
- tokens.forEach(function(token) {
- token.value = range.create(token).substring(source);
- switch (token.type) {
- case 'tag':
- if (/^<[^\/]+/.test(token.value)) {
- this._name = token.value.substring(1);
- }
- break;
-
- case 'attribute':
- // add empty attribute
- if (attrToken) {
- this._children.push(new XMLEditElement(this, attrToken));
- }
-
- attrToken = token;
- break;
-
- case 'string':
- this._children.push(new XMLEditElement(this, attrToken, token));
- attrToken = null;
- break;
- }
- }, this);
-
- if (attrToken) {
- this._children.push(new XMLEditElement(this, attrToken));
- }
-
- this._saveStyle();
- },
-
- /**
- * Remembers all styles of properties
- * @private
- */
- _saveStyle: function() {
- var start = this.nameRange().end;
- var source = this.source;
-
- this.list().forEach(function(p) {
- p.styleBefore = source.substring(start, p.namePosition());
-
- if (p.valuePosition() !== -1) {
- p.styleSeparator = source.substring(p.namePosition() + p.name().length, p.valuePosition() - p.styleQuote.length);
- }
-
- start = p.range().end;
- });
- },
-
- /**
- * Adds new attribute
- * @param {String} name Property name
- * @param {String} value Property value
- * @param {Number} pos Position at which to insert new property. By
- * default the property is inserted at the end of rule
- */
- add: function(name, value, pos) {
- var list = this.list();
- var start = this.nameRange().end;
- var styles = utils.pick(this.options, 'styleBefore', 'styleSeparator', 'styleQuote');
-
- if (typeof pos === 'undefined') {
- pos = list.length;
- }
-
-
- /** @type XMLEditAttribute */
- var donor = list[pos];
- if (donor) {
- start = donor.fullRange().start;
- } else if ((donor = list[pos - 1])) {
- start = donor.range().end;
- }
-
- if (donor) {
- styles = utils.pick(donor, 'styleBefore', 'styleSeparator', 'styleQuote');
- }
-
- value = styles.styleQuote + value + styles.styleQuote;
-
- var attribute = new XMLEditElement(this,
- editTree.createToken(start + styles.styleBefore.length, name),
- editTree.createToken(start + styles.styleBefore.length + name.length
- + styles.styleSeparator.length, value)
- );
-
- utils.extend(attribute, styles);
-
- // write new attribute into the source
- this._updateSource(attribute.styleBefore + attribute.toString(), start);
-
- // insert new attribute
- this._children.splice(pos, 0, attribute);
- return attribute;
- },
-
- /**
- * A special case of attribute editing: adds class value to existing
- * `class` attribute
- * @param {String} value
- */
- addClass: function(value) {
- var attr = this.get('class');
- value = utils.trim(value);
- if (!attr) {
- return this.add('class', value);
- }
-
- var classVal = attr.value();
- var classList = ' ' + classVal.replace(/\n/g, ' ') + ' ';
- if (!~classList.indexOf(' ' + value + ' ')) {
- attr.value(classVal + ' ' + value);
- }
- },
-
- /**
- * A special case of attribute editing: removes class value from existing
- * `class` attribute
- * @param {String} value
- */
- removeClass: function(value) {
- var attr = this.get('class');
- value = utils.trim(value);
- if (!attr) {
- return;
- }
-
- var reClass = new RegExp('(^|\\s+)' + utils.escapeForRegexp(value));
- var classVal = attr.value().replace(reClass, '');
- if (!utils.trim(classVal)) {
- this.remove('class');
- } else {
- attr.value(classVal);
- }
- }
- });
-
- var XMLEditElement = editTree.EditElement.extend({
- initialize: function(parent, nameToken, valueToken) {
- this.styleBefore = parent.options.styleBefore;
- this.styleSeparator = parent.options.styleSeparator;
-
- var value = '', quote = parent.options.styleQuote;
- if (valueToken) {
- value = valueToken.value;
- quote = value.charAt(0);
- if (quote == '"' || quote == "'") {
- value = value.substring(1);
- } else {
- quote = '';
- }
-
- if (quote && value.charAt(value.length - 1) == quote) {
- value = value.substring(0, value.length - 1);
- }
- }
-
- this.styleQuote = quote;
-
- this._value = value;
- this._positions.value = valueToken ? valueToken.start + quote.length : -1;
- },
-
- /**
- * Returns full rule range, with indentation
- * @param {Boolean} isAbsolute Return absolute range (with respect of
- * rule offset)
- * @returns {Range}
- */
- fullRange: function(isAbsolute) {
- var r = this.range(isAbsolute);
- r.start -= this.styleBefore.length;
- return r;
- },
-
- valueOf: function() {
- return this.name() + this.styleSeparator
- + this.styleQuote + this.value() + this.styleQuote;
- }
- });
-
- return {
- /**
- * Parses HTML element into editable tree
- * @param {String} source
- * @param {Object} options
- * @memberOf emmet.htmlEditTree
- * @returns {EditContainer}
- */
- parse: function(source, options) {
- return new XMLEditContainer(source, options);
- },
-
- /**
- * Extract and parse HTML from specified position in
content
- * @param {String} content CSS source code
- * @param {Number} pos Character position where to start source code extraction
- * @returns {XMLEditElement}
- */
- parseFromPosition: function(content, pos, isBackward) {
- var bounds = this.extractTag(content, pos, isBackward);
- if (!bounds || !bounds.inside(pos))
- // no matching HTML tag or caret outside tag bounds
- return null;
-
- return this.parse(bounds.substring(content), {
- offset: bounds.start
- });
- },
-
- /**
- * Extracts nearest HTML tag range from
content, starting at
- *
pos position
- * @param {String} content
- * @param {Number} pos
- * @param {Boolean} isBackward
- * @returns {Range}
- */
- extractTag: function(content, pos, isBackward) {
- var len = content.length, i;
-
- // max extraction length. I don't think there may be tags larger
- // than 2000 characters length
- var maxLen = Math.min(2000, len);
-
- /** @type Range */
- var r = null;
-
- var match = function(pos) {
- var m;
- if (content.charAt(pos) == '<' && (m = content.substr(pos, maxLen).match(startTag)))
- return range.create(pos, m[0]);
- };
-
- // lookup backward, in case we are inside tag already
- for (i = pos; i >= 0; i--) {
- if ((r = match(i))) break;
- }
-
- if (r && (r.inside(pos) || isBackward))
- return r;
-
- if (!r && isBackward)
- return null;
-
- // search forward
- for (i = pos; i < len; i++) {
- if ((r = match(i)))
- return r;
- }
- }
- };
-});
-},{"../assets/range":"assets\\range.js","../parser/xml":"parser\\xml.js","../utils/common":"utils\\common.js","./base":"editTree\\base.js"}],"filter\\bem.js":[function(require,module,exports){
-/**
- * Filter for aiding of writing elements with complex class names as described
- * in Yandex's BEM (Block, Element, Modifier) methodology. This filter will
- * automatically inherit block and element names from parent elements and insert
- * them into child element classes
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var htmlFilter = require('./html');
- var prefs = require('../assets/preferences');
- var abbreviationUtils = require('../utils/abbreviation');
- var utils = require('../utils/common');
-
- prefs.define('bem.elementSeparator', '__', 'Class name’s element separator.');
- prefs.define('bem.modifierSeparator', '_', 'Class name’s modifier separator.');
- prefs.define('bem.shortElementPrefix', '-',
- 'Symbol for describing short “block-element” notation. Class names '
- + 'prefixed with this symbol will be treated as element name for parent‘s '
- + 'block name. Each symbol instance traverses one level up in parsed '
- + 'tree for block name lookup. Empty value will disable short notation.');
-
- var shouldRunHtmlFilter = false;
-
- function getSeparators() {
- return {
- element: prefs.get('bem.elementSeparator'),
- modifier: prefs.get('bem.modifierSeparator')
- };
- }
-
- /**
- * @param {AbbreviationNode} item
- */
- function bemParse(item) {
- if (abbreviationUtils.isSnippet(item))
- return item;
-
- // save BEM stuff in cache for faster lookups
- item.__bem = {
- block: '',
- element: '',
- modifier: ''
- };
-
- var classNames = normalizeClassName(item.attribute('class')).split(' ');
-
- // guess best match for block name
- var reBlockName = /^[a-z]\-/i;
- item.__bem.block = utils.find(classNames, function(name) {
- return reBlockName.test(name);
- });
-
- // guessing doesn't worked, pick first class name as block name
- if (!item.__bem.block) {
- reBlockName = /^[a-z]/i;
- item.__bem.block = utils.find(classNames, function(name) {
- return reBlockName.test(name);
- }) || '';
- }
-
- classNames = classNames.map(function(name) {
- return processClassName(name, item);
- });
-
- classNames = utils.unique(utils.flatten(classNames)).join(' ');
- if (classNames) {
- item.attribute('class', classNames);
- }
-
- return item;
- }
-
- /**
- * @param {String} className
- * @returns {String}
- */
- function normalizeClassName(className) {
- className = (' ' + (className || '') + ' ').replace(/\s+/g, ' ');
-
- var shortSymbol = prefs.get('bem.shortElementPrefix');
- if (shortSymbol) {
- var re = new RegExp('\\s(' + utils.escapeForRegexp(shortSymbol) + '+)', 'g');
- className = className.replace(re, function(str, p1) {
- return ' ' + utils.repeatString(getSeparators().element, p1.length);
- });
- }
-
- return utils.trim(className);
- }
-
- /**
- * Processes class name
- * @param {String} name Class name item to process
- * @param {AbbreviationNode} item Host node for provided class name
- * @returns Processed class name. May return
Array of
- * class names
- */
- function processClassName(name, item) {
- name = transformClassName(name, item, 'element');
- name = transformClassName(name, item, 'modifier');
-
- // expand class name
- // possible values:
- // * block__element
- // * block__element_modifier
- // * block__element_modifier1_modifier2
- // * block_modifier
- var block = '', element = '', modifier = '';
- var separators = getSeparators();
- if (~name.indexOf(separators.element)) {
- var elements = name.split(separators.element);
- block = elements.shift();
-
- var modifiers = elements.pop().split(separators.modifier);
- elements.push(modifiers.shift());
- element = elements.join(separators.element);
- modifier = modifiers.join(separators.modifier);
- } else if (~name.indexOf(separators.modifier)) {
- var blockModifiers = name.split(separators.modifier);
-
- block = blockModifiers.shift();
- modifier = blockModifiers.join(separators.modifier);
- }
-
- if (block || element || modifier) {
- if (!block) {
- block = item.__bem.block;
- }
-
- // inherit parent bem element, if exists
-// if (item.parent && item.parent.__bem && item.parent.__bem.element)
-// element = item.parent.__bem.element + separators.element + element;
-
- // produce multiple classes
- var prefix = block;
- var result = [];
-
- if (element) {
- prefix += separators.element + element;
- result.push(prefix);
- } else {
- result.push(prefix);
- }
-
- if (modifier) {
- result.push(prefix + separators.modifier + modifier);
- }
-
- if (!item.__bem.block || modifier) {
- item.__bem.block = block;
- }
-
- item.__bem.element = element;
- item.__bem.modifier = modifier;
-
- return result;
- }
-
- // ...otherwise, return processed or original class name
- return name;
- }
-
- /**
- * Low-level function to transform user-typed class name into full BEM class
- * @param {String} name Class name item to process
- * @param {AbbreviationNode} item Host node for provided class name
- * @param {String} entityType Type of entity to be tried to transform
- * ('element' or 'modifier')
- * @returns {String} Processed class name or original one if it can't be
- * transformed
- */
- function transformClassName(name, item, entityType) {
- var separators = getSeparators();
- var reSep = new RegExp('^(' + separators[entityType] + ')+', 'g');
- if (reSep.test(name)) {
- var depth = 0; // parent lookup depth
- var cleanName = name.replace(reSep, function(str) {
- depth = str.length / separators[entityType].length;
- return '';
- });
-
- // find donor element
- var donor = item;
- while (donor.parent && depth--) {
- donor = donor.parent;
- }
-
- if (!donor || !donor.__bem)
- donor = item;
-
- if (donor && donor.__bem) {
- var prefix = donor.__bem.block;
-
- // decide if we should inherit element name
-// if (entityType == 'element') {
-// var curElem = cleanName.split(separators.modifier, 1)[0];
-// if (donor.__bem.element && donor.__bem.element != curElem)
-// prefix += separators.element + donor.__bem.element;
-// }
-
- if (entityType == 'modifier' && donor.__bem.element)
- prefix += separators.element + donor.__bem.element;
-
- return prefix + separators[entityType] + cleanName;
- }
- }
-
- return name;
- }
-
- /**
- * Recursive function for processing tags, which extends class names
- * according to BEM specs: http://bem.github.com/bem-method/pages/beginning/beginning.ru.html
- *
- * It does several things:
- *
- * Expands complex class name (according to BEM symbol semantics):
- * .block__elem_modifier → .block.block__elem.block__elem_modifier
- *
- * Inherits block name on child elements:
- * .b-block > .__el > .__el → .b-block > .b-block__el > .b-block__el__el
- *
- * Treats first dash symbol as '__'
- * Double underscore (or typographic '–') is also treated as an element
- * level lookup, e.g. ____el will search for element definition in parent’s
- * parent element:
- * .b-block > .__el1 > .____el2 → .b-block > .b-block__el1 > .b-block__el2
- *
- *
- *
- * @param {AbbreviationNode} tree
- * @param {Object} profile
- */
- function process(tree, profile) {
- if (tree.name) {
- bemParse(tree, profile);
- }
-
- tree.children.forEach(function(item) {
- process(item, profile);
- if (!abbreviationUtils.isSnippet(item) && item.start) {
- shouldRunHtmlFilter = true;
- }
- });
-
- return tree;
- }
-
- return function(tree, profile) {
- shouldRunHtmlFilter = false;
- tree = process(tree, profile);
- // in case 'bem' filter is applied after 'html' filter: run it again
- // to update output
- if (shouldRunHtmlFilter) {
- tree = htmlFilter(tree, profile);
- }
-
- return tree;
- };
-});
-
-},{"../assets/preferences":"assets\\preferences.js","../utils/abbreviation":"utils\\abbreviation.js","../utils/common":"utils\\common.js","./html":"filter\\html.js"}],"filter\\comment.js":[function(require,module,exports){
-/**
- * Comment important tags (with 'id' and 'class' attributes)
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var prefs = require('../assets/preferences');
- var utils = require('../utils/common');
- var template = require('../utils/template');
- var abbrUtils = require('../utils/abbreviation');
- var filterCore = require('./main');
-
- prefs.define('filter.commentAfter',
- '\n',
- 'A definition of comment that should be placed
after matched '
- + 'element when
comment filter is applied. This definition '
- + 'is an ERB-style template passed to
_.template() '
- + 'function (see Underscore.js docs for details). In template context, '
- + 'the following properties and functions are availabe:\n'
- + '
'
-
- + 'attr(name, before, after) – a function that outputs'
- + 'specified attribute value concatenated with before '
- + 'and after strings. If attribute doesn\'t exists, the '
- + 'empty string will be returned. '
-
- + 'node – current node (instance of AbbreviationNode) '
-
- + 'name – name of current tag '
-
- + 'padding – current string padding, can be used '
- + 'for formatting '
-
- +' ');
-
- prefs.define('filter.commentBefore',
- '',
- 'A definition of comment that should be placed
before matched '
- + 'element when
comment filter is applied. '
- + 'For more info, read description of
filter.commentAfter '
- + 'property');
-
- prefs.define('filter.commentTrigger', 'id, class',
- 'A comma-separated list of attribute names that should exist in abbreviatoin '
- + 'where comment should be added. If you wish to add comment for '
- + 'every element, set this option to
*');
-
- /**
- * Add comments to tag
- * @param {AbbreviationNode} node
- */
- function addComments(node, templateBefore, templateAfter) {
- // check if comments should be added
- var trigger = prefs.get('filter.commentTrigger');
- if (trigger != '*') {
- var shouldAdd = utils.find(trigger.split(','), function(name) {
- return !!node.attribute(utils.trim(name));
- });
-
- if (!shouldAdd) {
- return;
- }
- }
-
- var ctx = {
- node: node,
- name: node.name(),
- padding: node.parent ? node.parent.padding : '',
- attr: function(name, before, after) {
- var attr = node.attribute(name);
- if (attr) {
- return (before || '') + attr + (after || '');
- }
-
- return '';
- }
- };
-
- var nodeBefore = templateBefore ? templateBefore(ctx) : '';
- var nodeAfter = templateAfter ? templateAfter(ctx) : '';
-
- node.start = node.start.replace(/, nodeBefore + '<');
- node.end = node.end.replace(/>/, '>' + nodeAfter);
- }
-
- function process(tree, before, after) {
- tree.children.forEach(function(item) {
- if (abbrUtils.isBlock(item)) {
- addComments(item, before, after);
- }
-
- process(item, before, after);
- });
-
- return tree;
- }
-
- return function(tree) {
- var templateBefore = template(prefs.get('filter.commentBefore'));
- var templateAfter = template(prefs.get('filter.commentAfter'));
-
- return process(tree, templateBefore, templateAfter);
- };
-});
-
-},{"../assets/preferences":"assets\\preferences.js","../utils/abbreviation":"utils\\abbreviation.js","../utils/common":"utils\\common.js","../utils/template":"utils\\template.js","./main":"filter\\main.js"}],"filter\\css.js":[function(require,module,exports){
-/**
- * Filter for outputting CSS and alike
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- /**
- * Test if passed item is very first child in parsed tree
- * @param {AbbreviationNode} item
- */
- function isVeryFirstChild(item) {
- return item.parent && !item.parent.parent && !item.index();
- }
-
- return function process(tree, profile, level) {
- level = level || 0;
-
- tree.children.forEach(function(item) {
- if (!isVeryFirstChild(item) && profile.tag_nl !== false) {
- item.start = '\n' + item.start;
- }
- process(item, profile, level + 1);
- });
-
- return tree;
- };
-});
-},{}],"filter\\escape.js":[function(require,module,exports){
-/**
- * Filter for escaping unsafe XML characters: <, >, &
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var charMap = {
- '<': '<',
- '>': '>',
- '&': '&'
- };
-
- function escapeChars(str) {
- return str.replace(/([<>&])/g, function(str, p1){
- return charMap[p1];
- });
- }
-
- return function process(tree) {
- tree.children.forEach(function(item) {
- item.start = escapeChars(item.start);
- item.end = escapeChars(item.end);
- item.content = escapeChars(item.content);
- process(item);
- });
-
- return tree;
- };
-});
-},{}],"filter\\format.js":[function(require,module,exports){
-/**
- * Generic formatting filter: creates proper indentation for each tree node,
- * placing "%s" placeholder where the actual output should be. You can use
- * this filter to preformat tree and then replace %s placeholder to whatever you
- * need. This filter should't be called directly from editor as a part
- * of abbreviation.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../utils/common');
- var abbrUtils = require('../utils/abbreviation');
- var prefs = require('../assets/preferences');
- var resources = require('../assets/resources');
-
- prefs.define('format.noIndentTags', 'html',
- 'A comma-separated list of tag names that should not get inner indentation.');
-
- prefs.define('format.forceIndentationForTags', 'body',
- 'A comma-separated list of tag names that should
always get inner indentation.');
-
- var placeholder = '%s';
-
- /**
- * Get indentation for given node
- * @param {AbbreviationNode} node
- * @returns {String}
- */
- function getIndentation(node) {
- var items = prefs.getArray('format.noIndentTags') || [];
- if (~items.indexOf(node.name())) {
- return '';
- }
-
- return '\t';
- }
-
- /**
- * Test if passed node has block-level sibling element
- * @param {AbbreviationNode} item
- * @return {Boolean}
- */
- function hasBlockSibling(item) {
- return item.parent && abbrUtils.hasBlockChildren(item.parent);
- }
-
- /**
- * Test if passed item is very first child in parsed tree
- * @param {AbbreviationNode} item
- */
- function isVeryFirstChild(item) {
- return item.parent && !item.parent.parent && !item.index();
- }
-
- /**
- * Check if a newline should be added before element
- * @param {AbbreviationNode} node
- * @param {OutputProfile} profile
- * @return {Boolean}
- */
- function shouldAddLineBreak(node, profile) {
- if (profile.tag_nl === true || abbrUtils.isBlock(node))
- return true;
-
- if (!node.parent || !profile.inline_break)
- return false;
-
- // check if there are required amount of adjacent inline element
- return shouldFormatInline(node.parent, profile);
-}
-
- /**
- * Need to add newline because
item has too many inline children
- * @param {AbbreviationNode} node
- * @param {OutputProfile} profile
- */
- function shouldBreakChild(node, profile) {
- // we need to test only one child element, because
- // hasBlockChildren() method will do the rest
- return node.children.length && shouldAddLineBreak(node.children[0], profile);
- }
-
- function shouldFormatInline(node, profile) {
- var nodeCount = 0;
- return !!utils.find(node.children, function(child) {
- if (child.isTextNode() || !abbrUtils.isInline(child))
- nodeCount = 0;
- else if (abbrUtils.isInline(child))
- nodeCount++;
-
- if (nodeCount >= profile.inline_break)
- return true;
- });
- }
-
- function isRoot(item) {
- return !item.parent;
- }
-
- /**
- * Processes element with matched resource of type
snippet
- * @param {AbbreviationNode} item
- * @param {OutputProfile} profile
- */
- function processSnippet(item, profile) {
- item.start = item.end = '';
- if (!isVeryFirstChild(item) && profile.tag_nl !== false && shouldAddLineBreak(item, profile)) {
- // check if we’re not inside inline element
- if (isRoot(item.parent) || !abbrUtils.isInline(item.parent)) {
- item.start = '\n' + item.start;
- }
- }
-
- return item;
- }
-
- /**
- * Check if we should add line breaks inside inline element
- * @param {AbbreviationNode} node
- * @param {OutputProfile} profile
- * @return {Boolean}
- */
- function shouldBreakInsideInline(node, profile) {
- var hasBlockElems = node.children.some(function(child) {
- if (abbrUtils.isSnippet(child))
- return false;
-
- return !abbrUtils.isInline(child);
- });
-
- if (!hasBlockElems) {
- return shouldFormatInline(node, profile);
- }
-
- return true;
- }
-
- /**
- * Processes element with
tag type
- * @param {AbbreviationNode} item
- * @param {OutputProfile} profile
- */
- function processTag(item, profile) {
- item.start = item.end = placeholder;
- var isUnary = abbrUtils.isUnary(item);
- var nl = '\n';
- var indent = getIndentation(item);
-
- // formatting output
- if (profile.tag_nl !== false) {
- var forceNl = profile.tag_nl === true && (profile.tag_nl_leaf || item.children.length);
- if (!forceNl) {
- var forceIndentTags = prefs.getArray('format.forceIndentationForTags') || [];
- forceNl = ~forceIndentTags.indexOf(item.name());
- }
-
- // formatting block-level elements
- if (!item.isTextNode()) {
- if (shouldAddLineBreak(item, profile)) {
- // - do not indent the very first element
- // - do not indent first child of a snippet
- if (!isVeryFirstChild(item) && (!abbrUtils.isSnippet(item.parent) || item.index()))
- item.start = nl + item.start;
-
- if (abbrUtils.hasBlockChildren(item) || shouldBreakChild(item, profile) || (forceNl && !isUnary))
- item.end = nl + item.end;
-
- if (abbrUtils.hasTagsInContent(item) || (forceNl && !item.children.length && !isUnary))
- item.start += nl + indent;
- } else if (abbrUtils.isInline(item) && hasBlockSibling(item) && !isVeryFirstChild(item)) {
- item.start = nl + item.start;
- } else if (abbrUtils.isInline(item) && shouldBreakInsideInline(item, profile)) {
- item.end = nl + item.end;
- }
-
- item.padding = indent;
- }
- }
-
- return item;
- }
-
- /**
- * Processes simplified tree, making it suitable for output as HTML structure
- * @param {AbbreviationNode} tree
- * @param {OutputProfile} profile
- * @param {Number} level Depth level
- */
- return function process(tree, profile, level) {
- level = level || 0;
-
- tree.children.forEach(function(item) {
- if (abbrUtils.isSnippet(item)) {
- processSnippet(item, profile, level);
- } else {
- processTag(item, profile, level);
- }
-
- process(item, profile, level + 1);
- });
-
- return tree;
- };
-});
-},{"../assets/preferences":"assets\\preferences.js","../assets/resources":"assets\\resources.js","../utils/abbreviation":"utils\\abbreviation.js","../utils/common":"utils\\common.js"}],"filter\\haml.js":[function(require,module,exports){
-/**
- * Filter for producing HAML code from abbreviation.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../utils/common');
- var abbrUtils = require('../utils/abbreviation');
- var formatFilter = require('./format');
-
- function transformClassName(className) {
- return utils.trim(className).replace(/\s+/g, '.');
- }
-
- /**
- * Condenses all "data-" attributes into a single entry.
- * HAML allows data attributes to be ouputted as a sub-hash
- * of `:data` key
- * @param {Array} attrs
- * @return {Array}
- */
- function condenseDataAttrs(attrs) {
- var out = [], data = null;
- var reData = /^data-/i;
- attrs.forEach(function(attr) {
- if (reData.test(attr.name)) {
- if (!data) {
- data = [];
- out.push({
- name: 'data',
- value: data
- });
- }
-
- data.push(utils.extend({}, attr, {name: attr.name.replace(reData, '')}));
- } else {
- out.push(attr);
- }
- });
-
- return out;
- }
-
- function stringifyAttrs(attrs, profile) {
- var attrQuote = profile.attributeQuote();
- return '{' + attrs.map(function(attr) {
- var value = attrQuote + attr.value + attrQuote;
- if (Array.isArray(attr.value)) {
- value = stringifyAttrs(attr.value, profile);
- } else if (attr.isBoolean) {
- value = 'true';
- }
-
- return ':' + attr.name + ' => ' + value
- }).join(', ') + '}';
- }
-
- /**
- * Creates HAML attributes string from tag according to profile settings
- * @param {AbbreviationNode} tag
- * @param {Object} profile
- */
- function makeAttributesString(tag, profile) {
- var attrs = '';
- var otherAttrs = [];
- var attrQuote = profile.attributeQuote();
- var cursor = profile.cursor();
-
- tag.attributeList().forEach(function(a) {
- var attrName = profile.attributeName(a.name);
- switch (attrName.toLowerCase()) {
- // use short notation for ID and CLASS attributes
- case 'id':
- attrs += '#' + (a.value || cursor);
- break;
- case 'class':
- attrs += '.' + transformClassName(a.value || cursor);
- break;
- // process other attributes
- default:
- otherAttrs.push({
- name: attrName,
- value: a.value || cursor,
- isBoolean: profile.isBoolean(a.name, a.value)
- });
- }
- });
-
- if (otherAttrs.length) {
- attrs += stringifyAttrs(condenseDataAttrs(otherAttrs), profile);
- }
-
- return attrs;
- }
-
- /**
- * Processes element with
tag type
- * @param {AbbreviationNode} item
- * @param {OutputProfile} profile
- */
- function processTag(item, profile) {
- if (!item.parent)
- // looks like it's root element
- return item;
-
- var attrs = makeAttributesString(item, profile);
- var cursor = profile.cursor();
- var isUnary = abbrUtils.isUnary(item);
- var selfClosing = profile.self_closing_tag && isUnary ? '/' : '';
- var start= '';
-
- // define tag name
- var tagName = '%' + profile.tagName(item.name());
- if (tagName.toLowerCase() == '%div' && attrs && attrs.indexOf('{') == -1)
- // omit div tag
- tagName = '';
-
- item.end = '';
- start = tagName + attrs + selfClosing;
- if (item.content && !/^\s/.test(item.content)) {
- item.content = ' ' + item.content;
- }
-
- var placeholder = '%s';
- // We can't just replace placeholder with new value because
- // JavaScript will treat double $ character as a single one, assuming
- // we're using RegExp literal.
- item.start = utils.replaceSubstring(item.start, start, item.start.indexOf(placeholder), placeholder);
-
- if (!item.children.length && !isUnary)
- item.start += cursor;
-
- return item;
- }
-
- return function process(tree, profile, level) {
- level = level || 0;
-
- if (!level) {
- tree = formatFilter(tree, '_format', profile);
- }
-
- tree.children.forEach(function(item) {
- if (!abbrUtils.isSnippet(item)) {
- processTag(item, profile, level);
- }
-
- process(item, profile, level + 1);
- });
-
- return tree;
- };
-});
-},{"../utils/abbreviation":"utils\\abbreviation.js","../utils/common":"utils\\common.js","./format":"filter\\format.js"}],"filter\\html.js":[function(require,module,exports){
-/**
- * Filter that produces HTML tree
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var abbrUtils = require('../utils/abbreviation');
- var utils = require('../utils/common');
- var tabStops = require('../assets/tabStops');
- var formatFilter = require('./format');
-
- /**
- * Creates HTML attributes string from tag according to profile settings
- * @param {AbbreviationNode} node
- * @param {OutputProfile} profile
- */
- function makeAttributesString(node, profile) {
- var attrQuote = profile.attributeQuote();
- var cursor = profile.cursor();
-
- return node.attributeList().map(function(a) {
- var isBoolean = profile.isBoolean(a.name, a.value);
- var attrName = profile.attributeName(a.name);
- var attrValue = isBoolean ? attrName : a.value;
- if (isBoolean && profile.allowCompactBoolean()) {
- return ' ' + attrName;
- }
- return ' ' + attrName + '=' + attrQuote + (attrValue || cursor) + attrQuote;
- }).join('');
- }
-
- /**
- * Processes element with
tag type
- * @param {AbbreviationNode} item
- * @param {OutputProfile} profile
- */
- function processTag(item, profile) {
- if (!item.parent) { // looks like it's root element
- return item;
- }
-
- var attrs = makeAttributesString(item, profile);
- var cursor = profile.cursor();
- var isUnary = abbrUtils.isUnary(item);
- var start = '';
- var end = '';
-
- // define opening and closing tags
- if (!item.isTextNode()) {
- var tagName = profile.tagName(item.name());
- if (isUnary) {
- start = '<' + tagName + attrs + profile.selfClosing() + '>';
- item.end = '';
- } else {
- start = '<' + tagName + attrs + '>';
- end = '' + tagName + '>';
- }
- }
-
- var placeholder = '%s';
- // We can't just replace placeholder with new value because
- // JavaScript will treat double $ character as a single one, assuming
- // we're using RegExp literal.
- item.start = utils.replaceSubstring(item.start, start, item.start.indexOf(placeholder), placeholder);
- item.end = utils.replaceSubstring(item.end, end, item.end.indexOf(placeholder), placeholder);
-
- // should we put caret placeholder after opening tag?
- if (
- !item.children.length
- && !isUnary
- && !~item.content.indexOf(cursor)
- && !tabStops.extract(item.content).tabstops.length
- ) {
- item.start += cursor;
- }
-
- return item;
- }
-
- return function process(tree, profile, level) {
- level = level || 0;
-
- if (!level) {
- tree = formatFilter(tree, profile, level)
- }
-
- tree.children.forEach(function(item) {
- if (!abbrUtils.isSnippet(item)) {
- processTag(item, profile, level);
- }
-
- process(item, profile, level + 1);
- });
-
- return tree;
- };
-});
-},{"../assets/tabStops":"assets\\tabStops.js","../utils/abbreviation":"utils\\abbreviation.js","../utils/common":"utils\\common.js","./format":"filter\\format.js"}],"filter\\jade.js":[function(require,module,exports){
-/**
- * Filter for producing Jade code from abbreviation.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../utils/common');
- var abbrUtils = require('../utils/abbreviation');
- var formatFilter = require('./format');
- var tabStops = require('../assets/tabStops');
- var profile = require('../assets/profile');
-
- var reNl = /[\n\r]/;
- var reIndentedText = /^\s*\|/;
- var reSpace = /^\s/;
-
- function transformClassName(className) {
- return utils.trim(className).replace(/\s+/g, '.');
- }
-
- function stringifyAttrs(attrs, profile) {
- var attrQuote = profile.attributeQuote();
- return '(' + attrs.map(function(attr) {
- if (attr.isBoolean) {
- return attr.name;
- }
-
- return attr.name + '=' + attrQuote + attr.value + attrQuote;
- }).join(', ') + ')';
- }
-
- /**
- * Creates HAML attributes string from tag according to profile settings
- * @param {AbbreviationNode} tag
- * @param {Object} profile
- */
- function makeAttributesString(tag, profile) {
- var attrs = '';
- var otherAttrs = [];
- var attrQuote = profile.attributeQuote();
- var cursor = profile.cursor();
-
- tag.attributeList().forEach(function(a) {
- var attrName = profile.attributeName(a.name);
- switch (attrName.toLowerCase()) {
- // use short notation for ID and CLASS attributes
- case 'id':
- attrs += '#' + (a.value || cursor);
- break;
- case 'class':
- attrs += '.' + transformClassName(a.value || cursor);
- break;
- // process other attributes
- default:
- otherAttrs.push({
- name: attrName,
- value: a.value || cursor,
- isBoolean: profile.isBoolean(a.name, a.value)
- });
- }
- });
-
- if (otherAttrs.length) {
- attrs += stringifyAttrs(otherAttrs, profile);
- }
-
- return attrs;
- }
-
- function processTagContent(item) {
- if (!item.content) {
- return;
- }
-
- var content = tabStops.replaceVariables(item.content, function(str, name) {
- if (name === 'nl' || name === 'newline') {
- return '\n';
- }
- return str;
- });
-
- if (reNl.test(content) && !reIndentedText.test(content)) {
- // multiline content: pad it with indentation and pipe
- var pad = '| ';
- item.content = '\n' + pad + utils.padString(content, pad);
- } else if (!reSpace.test(content)) {
- item.content = ' ' + content;
- }
- }
-
- /**
- * Processes element with
tag type
- * @param {AbbreviationNode} item
- * @param {OutputProfile} profile
- */
- function processTag(item, profile) {
- if (!item.parent)
- // looks like it's a root (empty) element
- return item;
-
- var attrs = makeAttributesString(item, profile);
- var cursor = profile.cursor();
- var isUnary = abbrUtils.isUnary(item);
-
- // define tag name
- var tagName = profile.tagName(item.name());
- if (tagName.toLowerCase() == 'div' && attrs && attrs.charAt(0) != '(')
- // omit div tag
- tagName = '';
-
- item.end = '';
- var start = tagName + attrs;
- processTagContent(item);
-
- var placeholder = '%s';
- // We can't just replace placeholder with new value because
- // JavaScript will treat double $ character as a single one, assuming
- // we're using RegExp literal.
- item.start = utils.replaceSubstring(item.start, start, item.start.indexOf(placeholder), placeholder);
-
- if (!item.children.length && !isUnary)
- item.start += cursor;
-
- return item;
- }
-
- return function process(tree, curProfile, level) {
- level = level || 0;
-
- if (!level) {
- // always format with `xml` profile since
- // Jade requires all tags to be on separate lines
- tree = formatFilter(tree, profile.get('xml'));
- }
-
- tree.children.forEach(function(item) {
- if (!abbrUtils.isSnippet(item)) {
- processTag(item, curProfile, level);
- }
-
- process(item, curProfile, level + 1);
- });
-
- return tree;
- };
-});
-},{"../assets/profile":"assets\\profile.js","../assets/tabStops":"assets\\tabStops.js","../utils/abbreviation":"utils\\abbreviation.js","../utils/common":"utils\\common.js","./format":"filter\\format.js"}],"filter\\jsx.js":[function(require,module,exports){
-/**
- * A filter for React.js (JSX):
- * ranames attributes like `class` and `for`
- * for proper representation in JSX
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var attrMap = {
- 'class': 'className',
- 'for': 'htmlFor'
- };
-
- return function process(tree) {
- tree.children.forEach(function(item) {
- item._attributes.forEach(function(attr) {
- if (attr.name in attrMap) {
- attr.name = attrMap[attr.name]
- }
- });
- process(item);
- });
-
- return tree;
- };
-});
-},{}],"filter\\main.js":[function(require,module,exports){
-/**
- * Module for handling filters
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../utils/common');
- var profile = require('../assets/profile');
- var resources = require('../assets/resources');
-
- /** List of registered filters */
- var registeredFilters = {
- html: require('./html'),
- haml: require('./haml'),
- jade: require('./jade'),
- jsx: require('./jsx'),
- slim: require('./slim'),
- xsl: require('./xsl'),
- css: require('./css'),
- bem: require('./bem'),
- c: require('./comment'),
- e: require('./escape'),
- s: require('./singleLine'),
- t: require('./trim')
- };
-
- /** Filters that will be applied for unknown syntax */
- var basicFilters = 'html';
-
- function list(filters) {
- if (!filters)
- return [];
-
- if (typeof filters === 'string') {
- return filters.split(/[\|,]/g);
- }
-
- return filters;
- }
-
- return {
- /**
- * Register new filter
- * @param {String} name Filter name
- * @param {Function} fn Filter function
- */
- add: function(name, fn) {
- registeredFilters[name] = fn;
- },
-
- /**
- * Apply filters for final output tree
- * @param {AbbreviationNode} tree Output tree
- * @param {Array} filters List of filters to apply. Might be a
- *
String
- * @param {Object} profile Output profile, defined in
profile
- * module. Filters defined it profile are not used,
profile
- * is passed to filter function
- * @memberOf emmet.filters
- * @returns {AbbreviationNode}
- */
- apply: function(tree, filters, profileName) {
- profileName = profile.get(profileName);
-
- list(filters).forEach(function(filter) {
- var name = utils.trim(filter.toLowerCase());
- if (name && name in registeredFilters) {
- tree = registeredFilters[name](tree, profileName);
- }
- });
-
- return tree;
- },
-
- /**
- * Composes list of filters that should be applied to a tree, based on
- * passed data
- * @param {String} syntax Syntax name ('html', 'css', etc.)
- * @param {Object} profile Output profile
- * @param {String} additionalFilters List or pipe-separated
- * string of additional filters to apply
- * @returns {Array}
- */
- composeList: function(syntax, profileName, additionalFilters) {
- profileName = profile.get(profileName);
- var filters = list(profileName.filters || resources.findItem(syntax, 'filters') || basicFilters);
-
- if (profileName.extraFilters) {
- filters = filters.concat(list(profileName.extraFilters));
- }
-
- if (additionalFilters) {
- filters = filters.concat(list(additionalFilters));
- }
-
- if (!filters || !filters.length) {
- // looks like unknown syntax, apply basic filters
- filters = list(basicFilters);
- }
-
- return filters;
- },
-
- /**
- * Extracts filter list from abbreviation
- * @param {String} abbr
- * @returns {Array} Array with cleaned abbreviation and list of
- * extracted filters
- */
- extract: function(abbr) {
- var filters = '';
- abbr = abbr.replace(/\|([\w\|\-]+)$/, function(str, p1){
- filters = p1;
- return '';
- });
-
- return [abbr, list(filters)];
- }
- };
-});
-},{"../assets/profile":"assets\\profile.js","../assets/resources":"assets\\resources.js","../utils/common":"utils\\common.js","./bem":"filter\\bem.js","./comment":"filter\\comment.js","./css":"filter\\css.js","./escape":"filter\\escape.js","./haml":"filter\\haml.js","./html":"filter\\html.js","./jade":"filter\\jade.js","./jsx":"filter\\jsx.js","./singleLine":"filter\\singleLine.js","./slim":"filter\\slim.js","./trim":"filter\\trim.js","./xsl":"filter\\xsl.js"}],"filter\\singleLine.js":[function(require,module,exports){
-/**
- * Output abbreviation on a single line (i.e. no line breaks)
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var abbrUtils = require('../utils/abbreviation');
- var rePad = /^\s+/;
- var reNl = /[\n\r]/g;
-
- return function process(tree) {
- tree.children.forEach(function(item) {
- if (!abbrUtils.isSnippet(item)) {
- // remove padding from item
- item.start = item.start.replace(rePad, '');
- item.end = item.end.replace(rePad, '');
- }
-
- // remove newlines
- item.start = item.start.replace(reNl, '');
- item.end = item.end.replace(reNl, '');
- item.content = item.content.replace(reNl, '');
-
- process(item);
- });
-
- return tree;
- };
-});
-
-},{"../utils/abbreviation":"utils\\abbreviation.js"}],"filter\\slim.js":[function(require,module,exports){
-/**
- * Filter for producing Jade code from abbreviation.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../utils/common');
- var abbrUtils = require('../utils/abbreviation');
- var formatFilter = require('./format');
- var tabStops = require('../assets/tabStops');
- var prefs = require('../assets/preferences');
- var profile = require('../assets/profile');
-
- var reNl = /[\n\r]/;
- var reIndentedText = /^\s*\|/;
- var reSpace = /^\s/;
-
- prefs.define('slim.attributesWrapper', 'none',
- 'Defines how attributes will be wrapped:' +
- '
' +
- 'none – no wrapping; ' +
- 'round — wrap attributes with round braces; ' +
- 'square — wrap attributes with round braces; ' +
- 'curly — wrap attributes with curly braces. ' +
- ' ');
-
- function transformClassName(className) {
- return utils.trim(className).replace(/\s+/g, '.');
- }
-
- function getAttrWrapper() {
- var start = ' ', end = '';
- switch (prefs.get('slim.attributesWrapper')) {
- case 'round':
- start = '(';
- end = ')';
- break;
- case 'square':
- start = '[';
- end = ']';
- break;
- case 'curly':
- start = '{';
- end = '}';
- break;
- }
-
- return {
- start: start,
- end: end
- };
- }
-
- function stringifyAttrs(attrs, profile) {
- var attrQuote = profile.attributeQuote();
- var attrWrap = getAttrWrapper();
- return attrWrap.start + attrs.map(function(attr) {
- var value = attrQuote + attr.value + attrQuote;
- if (attr.isBoolean) {
- if (!attrWrap.end) {
- value = 'true';
- } else {
- return attr.name;
- }
- }
-
- return attr.name + '=' + value;
- }).join(' ') + attrWrap.end;
- }
-
- /**
- * Creates HAML attributes string from tag according to profile settings
- * @param {AbbreviationNode} tag
- * @param {Object} profile
- */
- function makeAttributesString(tag, profile) {
- var attrs = '';
- var otherAttrs = [];
- var attrQuote = profile.attributeQuote();
- var cursor = profile.cursor();
-
- tag.attributeList().forEach(function(a) {
- var attrName = profile.attributeName(a.name);
- switch (attrName.toLowerCase()) {
- // use short notation for ID and CLASS attributes
- case 'id':
- attrs += '#' + (a.value || cursor);
- break;
- case 'class':
- attrs += '.' + transformClassName(a.value || cursor);
- break;
- // process other attributes
- default:
- otherAttrs.push({
- name: attrName,
- value: a.value || cursor,
- isBoolean: profile.isBoolean(a.name, a.value)
- });
- }
- });
-
- if (otherAttrs.length) {
- attrs += stringifyAttrs(otherAttrs, profile);
- }
-
- return attrs;
- }
-
- function processTagContent(item) {
- if (!item.content) {
- return;
- }
-
- var content = tabStops.replaceVariables(item.content, function(str, name) {
- if (name === 'nl' || name === 'newline') {
- return '\n';
- }
- return str;
- });
-
- if (reNl.test(content) && !reIndentedText.test(content)) {
- // multiline content: pad it with indentation and pipe
- var pad = ' ';
- item.content = '\n| ' + utils.padString(content, pad);
- } else if (!reSpace.test(content)) {
- item.content = ' ' + content;
- }
- }
-
- /**
- * Processes element with
tag type
- * @param {AbbreviationNode} item
- * @param {OutputProfile} profile
- */
- function processTag(item, profile) {
- if (!item.parent)
- // looks like it's a root (empty) element
- return item;
-
- var attrs = makeAttributesString(item, profile);
- var cursor = profile.cursor();
- var isUnary = abbrUtils.isUnary(item);
- var selfClosing = profile.self_closing_tag && isUnary ? '/' : '';
-
- // define tag name
- var tagName = profile.tagName(item.name());
- if (tagName.toLowerCase() == 'div' && attrs && '([{'.indexOf(attrs.charAt(0)) == -1)
- // omit div tag
- tagName = '';
-
- item.end = '';
- var start = tagName + attrs + selfClosing;
- processTagContent(item);
-
- var placeholder = '%s';
- // We can't just replace placeholder with new value because
- // JavaScript will treat double $ character as a single one, assuming
- // we're using RegExp literal.
- item.start = utils.replaceSubstring(item.start, start, item.start.indexOf(placeholder), placeholder);
-
- if (!item.children.length && !isUnary)
- item.start += cursor;
-
- return item;
- }
-
- return function process(tree, curProfile, level) {
- level = level || 0;
-
- if (!level) {
- // always format with `xml` profile since
- // Slim requires all tags to be on separate lines
- tree = formatFilter(tree, profile.get('xml'));
- }
-
- tree.children.forEach(function(item) {
- if (!abbrUtils.isSnippet(item)) {
- processTag(item, curProfile, level);
- }
-
- process(item, curProfile, level + 1);
- });
-
- return tree;
- };
-});
-},{"../assets/preferences":"assets\\preferences.js","../assets/profile":"assets\\profile.js","../assets/tabStops":"assets\\tabStops.js","../utils/abbreviation":"utils\\abbreviation.js","../utils/common":"utils\\common.js","./format":"filter\\format.js"}],"filter\\trim.js":[function(require,module,exports){
-/**
- * Trim filter: removes characters at the beginning of the text
- * content that indicates lists: numbers, #, *, -, etc.
- *
- * Useful for wrapping lists with abbreviation.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var prefs = require('../assets/preferences');
- prefs.define('filter.trimRegexp',
- '[\\s|\\u00a0]*[\\d|#|\\-|\*|\\u2022]+\\.?\\s*',
- 'Regular expression used to remove list markers (numbers, dashes, '
- + 'bullets, etc.) in
t (trim) filter. The trim filter '
- + 'is useful for wrapping with abbreviation lists, pased from other '
- + 'documents (for example, Word documents).');
-
- function process(tree, re) {
- tree.children.forEach(function(item) {
- if (item.content) {
- item.content = item.content.replace(re, '');
- }
-
- process(item, re);
- });
-
- return tree;
- }
-
- return function(tree) {
- var re = new RegExp(prefs.get('filter.trimRegexp'));
- return process(tree, re);
- };
-});
-
-},{"../assets/preferences":"assets\\preferences.js"}],"filter\\xsl.js":[function(require,module,exports){
-/**
- * Filter for trimming "select" attributes from some tags that contains
- * child elements
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var abbrUtils = require('../utils/abbreviation');
-
- var tags = {
- 'xsl:variable': 1,
- 'xsl:with-param': 1
- };
-
- /**
- * Removes "select" attribute from node
- * @param {AbbreviationNode} node
- */
- function trimAttribute(node) {
- node.start = node.start.replace(/\s+select\s*=\s*(['"]).*?\1/, '');
- }
-
- return function process(tree) {
- tree.children.forEach(function(item) {
- if (!abbrUtils.isSnippet(item)
- && (item.name() || '').toLowerCase() in tags
- && item.children.length)
- trimAttribute(item);
- process(item);
- });
-
- return tree;
- };
-});
-},{"../utils/abbreviation":"utils\\abbreviation.js"}],"generator\\lorem.js":[function(require,module,exports){
-/**
- * "Lorem ipsum" text generator. Matches
lipsum(num)? or
- *
lorem(num)? abbreviation.
- * This code is based on Django's contribution:
- * https://code.djangoproject.com/browser/django/trunk/django/contrib/webdesign/lorem_ipsum.py
- *
- * Examples to test:
- *
lipsum – generates 30 words text.
- *
lipsum*6 – generates 6 paragraphs (autowrapped with <p> element) of text.
- *
ol>lipsum10*5 — generates ordered list with 5 list items (autowrapped with <li> tag)
- * with text of 10 words on each line.
- *
span*3>lipsum20 – generates 3 paragraphs of 20-words text, each wrapped with <span> element.
- * Each paragraph phrase is unique.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var prefs = require('../assets/preferences');
-
- var langs = {
- en: {
- common: ['lorem', 'ipsum', 'dolor', 'sit', 'amet', 'consectetur', 'adipisicing', 'elit'],
- words: ['exercitationem', 'perferendis', 'perspiciatis', 'laborum', 'eveniet',
- 'sunt', 'iure', 'nam', 'nobis', 'eum', 'cum', 'officiis', 'excepturi',
- 'odio', 'consectetur', 'quasi', 'aut', 'quisquam', 'vel', 'eligendi',
- 'itaque', 'non', 'odit', 'tempore', 'quaerat', 'dignissimos',
- 'facilis', 'neque', 'nihil', 'expedita', 'vitae', 'vero', 'ipsum',
- 'nisi', 'animi', 'cumque', 'pariatur', 'velit', 'modi', 'natus',
- 'iusto', 'eaque', 'sequi', 'illo', 'sed', 'ex', 'et', 'voluptatibus',
- 'tempora', 'veritatis', 'ratione', 'assumenda', 'incidunt', 'nostrum',
- 'placeat', 'aliquid', 'fuga', 'provident', 'praesentium', 'rem',
- 'necessitatibus', 'suscipit', 'adipisci', 'quidem', 'possimus',
- 'voluptas', 'debitis', 'sint', 'accusantium', 'unde', 'sapiente',
- 'voluptate', 'qui', 'aspernatur', 'laudantium', 'soluta', 'amet',
- 'quo', 'aliquam', 'saepe', 'culpa', 'libero', 'ipsa', 'dicta',
- 'reiciendis', 'nesciunt', 'doloribus', 'autem', 'impedit', 'minima',
- 'maiores', 'repudiandae', 'ipsam', 'obcaecati', 'ullam', 'enim',
- 'totam', 'delectus', 'ducimus', 'quis', 'voluptates', 'dolores',
- 'molestiae', 'harum', 'dolorem', 'quia', 'voluptatem', 'molestias',
- 'magni', 'distinctio', 'omnis', 'illum', 'dolorum', 'voluptatum', 'ea',
- 'quas', 'quam', 'corporis', 'quae', 'blanditiis', 'atque', 'deserunt',
- 'laboriosam', 'earum', 'consequuntur', 'hic', 'cupiditate',
- 'quibusdam', 'accusamus', 'ut', 'rerum', 'error', 'minus', 'eius',
- 'ab', 'ad', 'nemo', 'fugit', 'officia', 'at', 'in', 'id', 'quos',
- 'reprehenderit', 'numquam', 'iste', 'fugiat', 'sit', 'inventore',
- 'beatae', 'repellendus', 'magnam', 'recusandae', 'quod', 'explicabo',
- 'doloremque', 'aperiam', 'consequatur', 'asperiores', 'commodi',
- 'optio', 'dolor', 'labore', 'temporibus', 'repellat', 'veniam',
- 'architecto', 'est', 'esse', 'mollitia', 'nulla', 'a', 'similique',
- 'eos', 'alias', 'dolore', 'tenetur', 'deleniti', 'porro', 'facere',
- 'maxime', 'corrupti']
- },
- sp: {
- common: ['mujer', 'uno', 'dolor', 'más', 'de', 'poder', 'mismo', 'si'],
- words: ['ejercicio', 'preferencia', 'perspicacia', 'laboral', 'paño',
- 'suntuoso', 'molde', 'namibia', 'planeador', 'mirar', 'demás', 'oficinista', 'excepción',
- 'odio', 'consecuencia', 'casi', 'auto', 'chicharra', 'velo', 'elixir',
- 'ataque', 'no', 'odio', 'temporal', 'cuórum', 'dignísimo',
- 'facilismo', 'letra', 'nihilista', 'expedición', 'alma', 'alveolar', 'aparte',
- 'león', 'animal', 'como', 'paria', 'belleza', 'modo', 'natividad',
- 'justo', 'ataque', 'séquito', 'pillo', 'sed', 'ex', 'y', 'voluminoso',
- 'temporalidad', 'verdades', 'racional', 'asunción', 'incidente', 'marejada',
- 'placenta', 'amanecer', 'fuga', 'previsor', 'presentación', 'lejos',
- 'necesariamente', 'sospechoso', 'adiposidad', 'quindío', 'pócima',
- 'voluble', 'débito', 'sintió', 'accesorio', 'falda', 'sapiencia',
- 'volutas', 'queso', 'permacultura', 'laudo', 'soluciones', 'entero',
- 'pan', 'litro', 'tonelada', 'culpa', 'libertario', 'mosca', 'dictado',
- 'reincidente', 'nascimiento', 'dolor', 'escolar', 'impedimento', 'mínima',
- 'mayores', 'repugnante', 'dulce', 'obcecado', 'montaña', 'enigma',
- 'total', 'deletéreo', 'décima', 'cábala', 'fotografía', 'dolores',
- 'molesto', 'olvido', 'paciencia', 'resiliencia', 'voluntad', 'molestias',
- 'magnífico', 'distinción', 'ovni', 'marejada', 'cerro', 'torre', 'y',
- 'abogada', 'manantial', 'corporal', 'agua', 'crepúsculo', 'ataque', 'desierto',
- 'laboriosamente', 'angustia', 'afortunado', 'alma', 'encefalograma',
- 'materialidad', 'cosas', 'o', 'renuncia', 'error', 'menos', 'conejo',
- 'abadía', 'analfabeto', 'remo', 'fugacidad', 'oficio', 'en', 'almácigo', 'vos', 'pan',
- 'represión', 'números', 'triste', 'refugiado', 'trote', 'inventor',
- 'corchea', 'repelente', 'magma', 'recusado', 'patrón', 'explícito',
- 'paloma', 'síndrome', 'inmune', 'autoinmune', 'comodidad',
- 'ley', 'vietnamita', 'demonio', 'tasmania', 'repeler', 'apéndice',
- 'arquitecto', 'columna', 'yugo', 'computador', 'mula', 'a', 'propósito',
- 'fantasía', 'alias', 'rayo', 'tenedor', 'deleznable', 'ventana', 'cara',
- 'anemia', 'corrupto']
- },
- ru: {
- common: ['далеко-далеко', 'за', 'словесными', 'горами', 'в стране', 'гласных', 'и согласных', 'живут', 'рыбные', 'тексты'],
- words: ['вдали', 'от всех', 'они', 'буквенных', 'домах', 'на берегу', 'семантика',
- 'большого', 'языкового', 'океана', 'маленький', 'ручеек', 'даль',
- 'журчит', 'по всей', 'обеспечивает', 'ее','всеми', 'необходимыми',
- 'правилами', 'эта', 'парадигматическая', 'страна', 'которой', 'жаренные',
- 'предложения', 'залетают', 'прямо', 'рот', 'даже', 'всемогущая',
- 'пунктуация', 'не', 'имеет', 'власти', 'над', 'рыбными', 'текстами',
- 'ведущими', 'безорфографичный', 'образ', 'жизни', 'однажды', 'одна',
- 'маленькая', 'строчка','рыбного', 'текста', 'имени', 'lorem', 'ipsum',
- 'решила', 'выйти', 'большой', 'мир', 'грамматики', 'великий', 'оксмокс',
- 'предупреждал', 'о', 'злых', 'запятых', 'диких', 'знаках', 'вопроса',
- 'коварных', 'точках', 'запятой', 'но', 'текст', 'дал', 'сбить',
- 'себя', 'толку', 'он', 'собрал', 'семь', 'своих', 'заглавных', 'букв',
- 'подпоясал', 'инициал', 'за', 'пояс', 'пустился', 'дорогу',
- 'взобравшись', 'первую', 'вершину', 'курсивных', 'гор', 'бросил',
- 'последний', 'взгляд', 'назад', 'силуэт', 'своего', 'родного', 'города',
- 'буквоград', 'заголовок', 'деревни', 'алфавит', 'подзаголовок', 'своего',
- 'переулка', 'грустный', 'реторический', 'вопрос', 'скатился', 'его',
- 'щеке', 'продолжил', 'свой', 'путь', 'дороге', 'встретил', 'рукопись',
- 'она', 'предупредила', 'моей', 'все', 'переписывается', 'несколько',
- 'раз', 'единственное', 'что', 'меня', 'осталось', 'это', 'приставка',
- 'возвращайся', 'ты', 'лучше', 'свою', 'безопасную', 'страну', 'послушавшись',
- 'рукописи', 'наш', 'продолжил', 'свой', 'путь', 'вскоре', 'ему',
- 'повстречался', 'коварный', 'составитель', 'рекламных', 'текстов',
- 'напоивший', 'языком', 'речью', 'заманивший', 'свое', 'агентство',
- 'которое', 'использовало', 'снова', 'снова', 'своих', 'проектах',
- 'если', 'переписали', 'то', 'живет', 'там', 'до', 'сих', 'пор']
- }
- };
-
-
- prefs.define('lorem.defaultLang', 'en',
- 'Default language of generated dummy text. Currently,
en\
- and
ru are supported, but users can add their own syntaxes\
- see
docs .');
- prefs.define('lorem.omitCommonPart', false,
- 'Omit commonly used part (e.g. “Lorem ipsum dolor sit amet“) from generated text.');
-
- /**
- * Returns random integer between
from and
to values
- * @param {Number} from
- * @param {Number} to
- * @returns {Number}
- */
- function randint(from, to) {
- return Math.round(Math.random() * (to - from) + from);
- }
-
- /**
- * @param {Array} arr
- * @param {Number} count
- * @returns {Array}
- */
- function sample(arr, count) {
- var len = arr.length;
- var iterations = Math.min(len, count);
- var result = [];
- while (result.length < iterations) {
- var randIx = randint(0, len - 1);
- if (!~result.indexOf(randIx)) {
- result.push(randIx);
- }
- }
-
- return result.map(function(ix) {
- return arr[ix];
- });
- }
-
- function choice(val) {
- if (typeof val === 'string')
- return val.charAt(randint(0, val.length - 1));
-
- return val[randint(0, val.length - 1)];
- }
-
- function sentence(words, end) {
- if (words.length) {
- words[0] = words[0].charAt(0).toUpperCase() + words[0].substring(1);
- }
-
- return words.join(' ') + (end || choice('?!...')); // more dots than question marks
- }
-
- /**
- * Insert commas at randomly selected words. This function modifies values
- * inside
words array
- * @param {Array} words
- */
- function insertCommas(words) {
- var len = words.length;
-
- if (len < 2) {
- return;
- }
-
- var totalCommas = 0;
- if (len > 3 && len <= 6) {
- totalCommas = randint(0, 1);
- } else if (len > 6 && len <= 12) {
- totalCommas = randint(0, 2);
- } else {
- totalCommas = randint(1, 4);
- }
-
- for (var i = 0, pos, word; i < totalCommas; i++) {
- pos = randint(0, words.length - 2);
- word = words[pos];
- if (word.charAt(word.length - 1) !== ',') {
- words[pos] += ',';
- }
- }
- }
-
- /**
- * Generate a paragraph of "Lorem ipsum" text
- * @param {Number} wordCount Words count in paragraph
- * @param {Boolean} startWithCommon Should paragraph start with common
- * "lorem ipsum" sentence.
- * @returns {String}
- */
- function paragraph(lang, wordCount, startWithCommon) {
- var data = langs[lang];
- if (!data) {
- return '';
- }
-
- var result = [];
- var totalWords = 0;
- var words;
-
- wordCount = parseInt(wordCount, 10);
-
- if (startWithCommon && data.common) {
- words = data.common.slice(0, wordCount);
- if (words.length > 5) {
- words[4] += ',';
- }
- totalWords += words.length;
- result.push(sentence(words, '.'));
- }
-
- while (totalWords < wordCount) {
- words = sample(data.words, Math.min(randint(2, 30), wordCount - totalWords));
- totalWords += words.length;
- insertCommas(words);
- result.push(sentence(words));
- }
-
- return result.join(' ');
- }
-
- return {
- /**
- * Adds new language words for Lorem Ipsum generator
- * @param {String} lang Two-letter lang definition
- * @param {Object} data Words for language. Maight be either a space-separated
- * list of words (String), Array of words or object with
text and
- *
common properties
- */
- addLang: function(lang, data) {
- if (typeof data === 'string') {
- data = {
- words: data.split(' ').filter(function(item) {
- return !!item;
- })
- };
- } else if (Array.isArray(data)) {
- data = {words: data};
- }
-
- langs[lang] = data;
- },
- preprocessor: function(tree) {
- var re = /^(?:lorem|lipsum)([a-z]{2})?(\d*)$/i, match;
- var allowCommon = !prefs.get('lorem.omitCommonPart');
-
- /** @param {AbbreviationNode} node */
- tree.findAll(function(node) {
- if (node._name && (match = node._name.match(re))) {
- var wordCound = match[2] || 30;
- var lang = match[1] || prefs.get('lorem.defaultLang') || 'en';
-
- // force node name resolving if node should be repeated
- // or contains attributes. In this case, node should be outputed
- // as tag, otherwise as text-only node
- node._name = '';
- node.data('forceNameResolving', node.isRepeating() || node.attributeList().length);
- node.data('pasteOverwrites', true);
- node.data('paste', function(i) {
- return paragraph(lang, wordCound, !i && allowCommon);
- });
- }
- });
- }
- };
-});
-
-},{"../assets/preferences":"assets\\preferences.js"}],"parser\\abbreviation.js":[function(require,module,exports){
-/**
- * Emmet abbreviation parser.
- * Takes string abbreviation and recursively parses it into a tree. The parsed
- * tree can be transformed into a string representation with
- *
toString() method. Note that string representation is defined
- * by custom processors (called
filters ), not by abbreviation parser
- * itself.
- *
- * This module can be extended with custom pre-/post-processors to shape-up
- * final tree or its representation. Actually, many features of abbreviation
- * engine are defined in other modules as tree processors
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var tabStops = require('../assets/tabStops');
- var profile = require('../assets/profile');
- var filters = require('../filter/main');
- var utils = require('../utils/common');
- var abbreviationUtils = require('../utils/abbreviation');
- var stringStream = require('../assets/stringStream');
-
- // pre- and post-processorcs
- var lorem = require('../generator/lorem');
- var procPastedContent = require('./processor/pastedContent');
- var procTagName = require('./processor/tagName');
- var procResourceMatcher = require('./processor/resourceMatcher');
- var procAttributes = require('./processor/attributes');
- var procHref = require('./processor/href');
-
- var reValidName = /^[\w\-\$\:@\!%]+\+?$/i;
- var reWord = /[\w\-:\$@]/;
- var DEFAULT_ATTR_NAME = '%default';
-
- var pairs = {
- '[': ']',
- '(': ')',
- '{': '}'
- };
-
- var spliceFn = Array.prototype.splice;
-
- var preprocessors = [];
- var postprocessors = [];
- var outputProcessors = [];
-
- /**
- * @type AbbreviationNode
- */
- function AbbreviationNode(parent) {
- /** @type AbbreviationNode */
- this.parent = null;
- this.children = [];
- this._attributes = [];
-
- /** @type String Raw abbreviation for current node */
- this.abbreviation = '';
- this.counter = 1;
- this._name = null;
- this._text = '';
- this.repeatCount = 1;
- this.hasImplicitRepeat = false;
-
- /** Custom data dictionary */
- this._data = {};
-
- // output properties
- this.start = '';
- this.end = '';
- this.content = '';
- this.padding = '';
- }
-
- AbbreviationNode.prototype = {
- /**
- * Adds passed node as child or creates new child
- * @param {AbbreviationNode} child
- * @param {Number} position Index in children array where child should
- * be inserted
- * @return {AbbreviationNode}
- */
- addChild: function(child, position) {
- child = child || new AbbreviationNode();
- child.parent = this;
-
- if (typeof position === 'undefined') {
- this.children.push(child);
- } else {
- this.children.splice(position, 0, child);
- }
-
- return child;
- },
-
- /**
- * Creates a deep copy of current node
- * @returns {AbbreviationNode}
- */
- clone: function() {
- var node = new AbbreviationNode();
- var attrs = ['abbreviation', 'counter', '_name', '_text', 'repeatCount', 'hasImplicitRepeat', 'start', 'end', 'content', 'padding'];
- attrs.forEach(function(a) {
- node[a] = this[a];
- }, this);
-
- // clone attributes
- node._attributes = this._attributes.map(function(attr) {
- return utils.extend({}, attr);
- });
-
- node._data = utils.extend({}, this._data);
-
- // clone children
- node.children = this.children.map(function(child) {
- child = child.clone();
- child.parent = node;
- return child;
- });
-
- return node;
- },
-
- /**
- * Removes current node from parent‘s child list
- * @returns {AbbreviationNode} Current node itself
- */
- remove: function() {
- if (this.parent) {
- var ix = this.parent.children.indexOf(this);
- if (~ix) {
- this.parent.children.splice(ix, 1);
- }
- }
-
- return this;
- },
-
- /**
- * Replaces current node in parent‘s children list with passed nodes
- * @param {AbbreviationNode} node Replacement node or array of nodes
- */
- replace: function() {
- var parent = this.parent;
- var ix = parent.children.indexOf(this);
- var items = utils.flatten(arguments);
- spliceFn.apply(parent.children, [ix, 1].concat(items));
-
- // update parent
- items.forEach(function(item) {
- item.parent = parent;
- });
- },
-
- /**
- * Recursively sets
property to
value of current
- * node and its children
- * @param {String} name Property to update
- * @param {Object} value New property value
- */
- updateProperty: function(name, value) {
- this[name] = value;
- this.children.forEach(function(child) {
- child.updateProperty(name, value);
- });
-
- return this;
- },
-
- /**
- * Finds first child node that matches truth test for passed
- *
fn function
- * @param {Function} fn
- * @returns {AbbreviationNode}
- */
- find: function(fn) {
- return this.findAll(fn, {amount: 1})[0];
- },
-
- /**
- * Finds all child nodes that matches truth test for passed
- *
fn function
- * @param {Function} fn
- * @returns {Array}
- */
- findAll: function(fn, state) {
- state = utils.extend({amount: 0, found: 0}, state || {});
-
- if (typeof fn !== 'function') {
- var elemName = fn.toLowerCase();
- fn = function(item) {return item.name().toLowerCase() == elemName;};
- }
-
- var result = [];
- this.children.forEach(function(child) {
- if (fn(child)) {
- result.push(child);
- state.found++;
- if (state.amount && state.found >= state.amount) {
- return;
- }
- }
-
- result = result.concat(child.findAll(fn));
- });
-
- return result.filter(function(item) {
- return !!item;
- });
- },
-
- /**
- * Sets/gets custom data
- * @param {String} name
- * @param {Object} value
- * @returns {Object}
- */
- data: function(name, value) {
- if (arguments.length == 2) {
- this._data[name] = value;
- }
-
- return this._data[name];
- },
-
- /**
- * Returns name of current node
- * @returns {String}
- */
- name: function() {
- return this._name;
- },
-
- /**
- * Returns list of attributes for current node
- * @returns {Array}
- */
- attributeList: function() {
- return optimizeAttributes(this._attributes.slice(0));
- },
-
- /**
- * Returns or sets attribute value
- * @param {String} name Attribute name
- * @param {String} value New attribute value. `Null` value
- * will remove attribute
- * @returns {String}
- */
- attribute: function(name, value) {
- if (arguments.length == 2) {
- if (value === null) {
- // remove attribute
- var vals = this._attributes.filter(function(attr) {
- return attr.name === name;
- });
-
- var that = this;
- vals.forEach(function(attr) {
- var ix = that._attributes.indexOf(attr);
- if (~ix) {
- that._attributes.splice(ix, 1);
- }
- });
-
- return;
- }
-
- // modify attribute
- var attrNames = this._attributes.map(function(attr) {
- return attr.name;
- });
- var ix = attrNames.indexOf(name.toLowerCase());
- if (~ix) {
- this._attributes[ix].value = value;
- } else {
- this._attributes.push({
- name: name,
- value: value
- });
- }
- }
-
- return (utils.find(this.attributeList(), function(attr) {
- return attr.name == name;
- }) || {}).value;
- },
-
- /**
- * Returns index of current node in parent‘s children list
- * @returns {Number}
- */
- index: function() {
- return this.parent ? this.parent.children.indexOf(this) : -1;
- },
-
- /**
- * Sets how many times current element should be repeated
- * @private
- */
- _setRepeat: function(count) {
- if (count) {
- this.repeatCount = parseInt(count, 10) || 1;
- } else {
- this.hasImplicitRepeat = true;
- }
- },
-
- /**
- * Sets abbreviation that belongs to current node
- * @param {String} abbr
- */
- setAbbreviation: function(abbr) {
- abbr = abbr || '';
-
- var that = this;
-
- // find multiplier
- abbr = abbr.replace(/\*(\d+)?$/, function(str, repeatCount) {
- that._setRepeat(repeatCount);
- return '';
- });
-
- this.abbreviation = abbr;
-
- var abbrText = extractText(abbr);
- if (abbrText) {
- abbr = abbrText.element;
- this.content = this._text = abbrText.text;
- }
-
- var abbrAttrs = parseAttributes(abbr);
- if (abbrAttrs) {
- abbr = abbrAttrs.element;
- this._attributes = abbrAttrs.attributes;
- }
-
- this._name = abbr;
-
- // validate name
- if (this._name && !reValidName.test(this._name)) {
- throw new Error('Invalid abbreviation');
- }
- },
-
- /**
- * Returns string representation of current node
- * @return {String}
- */
- valueOf: function() {
- var start = this.start;
- var end = this.end;
- var content = this.content;
-
- // apply output processors
- var node = this;
- outputProcessors.forEach(function(fn) {
- start = fn(start, node, 'start');
- content = fn(content, node, 'content');
- end = fn(end, node, 'end');
- });
-
-
- var innerContent = this.children.map(function(child) {
- return child.valueOf();
- }).join('');
-
- content = abbreviationUtils.insertChildContent(content, innerContent, {
- keepVariable: false
- });
-
- return start + utils.padString(content, this.padding) + end;
- },
-
- toString: function() {
- return this.valueOf();
- },
-
- /**
- * Check if current node contains children with empty
expr
- * property
- * @return {Boolean}
- */
- hasEmptyChildren: function() {
- return !!utils.find(this.children, function(child) {
- return child.isEmpty();
- });
- },
-
- /**
- * Check if current node has implied name that should be resolved
- * @returns {Boolean}
- */
- hasImplicitName: function() {
- return !this._name && !this.isTextNode();
- },
-
- /**
- * Indicates that current element is a grouping one, e.g. has no
- * representation but serves as a container for other nodes
- * @returns {Boolean}
- */
- isGroup: function() {
- return !this.abbreviation;
- },
-
- /**
- * Indicates empty node (i.e. without abbreviation). It may be a
- * grouping node and should not be outputted
- * @return {Boolean}
- */
- isEmpty: function() {
- return !this.abbreviation && !this.children.length;
- },
-
- /**
- * Indicates that current node should be repeated
- * @returns {Boolean}
- */
- isRepeating: function() {
- return this.repeatCount > 1 || this.hasImplicitRepeat;
- },
-
- /**
- * Check if current node is a text-only node
- * @return {Boolean}
- */
- isTextNode: function() {
- return !this.name() && !this.attributeList().length;
- },
-
- /**
- * Indicates whether this node may be used to build elements or snippets
- * @returns {Boolean}
- */
- isElement: function() {
- return !this.isEmpty() && !this.isTextNode();
- },
-
- /**
- * Returns latest and deepest child of current tree
- * @returns {AbbreviationNode}
- */
- deepestChild: function() {
- if (!this.children.length)
- return null;
-
- var deepestChild = this;
- while (deepestChild.children.length) {
- deepestChild = deepestChild.children[deepestChild.children.length - 1];
- }
-
- return deepestChild;
- }
- };
-
- /**
- * Returns stripped string: a string without first and last character.
- * Used for “unquoting” strings
- * @param {String} str
- * @returns {String}
- */
- function stripped(str) {
- return str.substring(1, str.length - 1);
- }
-
- function consumeQuotedValue(stream, quote) {
- var ch;
- while ((ch = stream.next())) {
- if (ch === quote)
- return true;
-
- if (ch == '\\')
- continue;
- }
-
- return false;
- }
-
- /**
- * Parses abbreviation into a tree
- * @param {String} abbr
- * @returns {AbbreviationNode}
- */
- function parseAbbreviation(abbr) {
- abbr = utils.trim(abbr);
-
- var root = new AbbreviationNode();
- var context = root.addChild(), ch;
-
- /** @type StringStream */
- var stream = stringStream.create(abbr);
- var loopProtector = 1000, multiplier;
- var addChild = function(child) {
- context.addChild(child);
- };
-
- var consumeAbbr = function() {
- stream.start = stream.pos;
- stream.eatWhile(function(c) {
- if (c == '[' || c == '{') {
- if (stream.skipToPair(c, pairs[c])) {
- stream.backUp(1);
- return true;
- }
-
- throw new Error('Invalid abbreviation: mo matching "' + pairs[c] + '" found for character at ' + stream.pos);
- }
-
- if (c == '+') {
- // let's see if this is an expando marker
- stream.next();
- var isMarker = stream.eol() || ~'+>^*'.indexOf(stream.peek());
- stream.backUp(1);
- return isMarker;
- }
-
- return c != '(' && isAllowedChar(c);
- });
- };
-
- while (!stream.eol() && --loopProtector > 0) {
- ch = stream.peek();
-
- switch (ch) {
- case '(': // abbreviation group
- stream.start = stream.pos;
- if (stream.skipToPair('(', ')')) {
- var inner = parseAbbreviation(stripped(stream.current()));
- if ((multiplier = stream.match(/^\*(\d+)?/, true))) {
- context._setRepeat(multiplier[1]);
- }
-
- inner.children.forEach(addChild);
- } else {
- throw new Error('Invalid abbreviation: mo matching ")" found for character at ' + stream.pos);
- }
- break;
-
- case '>': // child operator
- context = context.addChild();
- stream.next();
- break;
-
- case '+': // sibling operator
- context = context.parent.addChild();
- stream.next();
- break;
-
- case '^': // climb up operator
- var parent = context.parent || context;
- context = (parent.parent || parent).addChild();
- stream.next();
- break;
-
- default: // consume abbreviation
- consumeAbbr();
- context.setAbbreviation(stream.current());
- stream.start = stream.pos;
- }
- }
-
- if (loopProtector < 1) {
- throw new Error('Endless loop detected');
- }
-
- return root;
- }
-
- /**
- * Splits attribute set into a list of attributes string
- * @param {String} attrSet
- * @return {Array}
- */
- function splitAttributes(attrSet) {
- attrSet = utils.trim(attrSet);
- var parts = [];
-
- // split attribute set by spaces
- var stream = stringStream(attrSet), ch;
- while ((ch = stream.next())) {
- if (ch == ' ') {
- parts.push(utils.trim(stream.current()));
- // skip spaces
- while (stream.peek() == ' ') {
- stream.next();
- }
-
- stream.start = stream.pos;
- } else if (ch == '"' || ch == "'") {
- // skip values in strings
- if (!stream.skipString(ch)) {
- throw new Error('Invalid attribute set');
- }
- }
- }
-
- parts.push(utils.trim(stream.current()));
- return parts;
- }
-
- /**
- * Removes opening and closing quotes from given string
- * @param {String} str
- * @return {String}
- */
- function unquote(str) {
- var ch = str.charAt(0);
- if (ch == '"' || ch == "'") {
- str = str.substr(1);
- var last = str.charAt(str.length - 1);
- if (last === ch) {
- str = str.substr(0, str.length - 1);
- }
- }
-
- return str;
- }
-
- /**
- * Extract attributes and their values from attribute set:
- *
[attr col=3 title="Quoted string"] (without square braces)
- * @param {String} attrSet
- * @returns {Array}
- */
- function extractAttributes(attrSet) {
- var reAttrName = /^[\w\-:\$@]+\.?$/;
- return splitAttributes(attrSet).map(function(attr) {
- // attribute name: [attr]
- if (reAttrName.test(attr)) {
- var value = '';
- if (attr.charAt(attr.length - 1) == '.') {
- // a boolean attribute
- attr = attr.substr(0, attr.length - 1);
- value = attr;
- }
- return {
- name: attr,
- value: value
- };
- }
-
- // attribute with value: [name=val], [name="val"]
- if (~attr.indexOf('=')) {
- var parts = attr.split('=');
- return {
- name: parts.shift(),
- value: unquote(parts.join('='))
- };
- }
-
- // looks like it’s implied attribute
- return {
- name: DEFAULT_ATTR_NAME,
- value: unquote(attr)
- };
- });
- }
-
- /**
- * Parses tag attributes extracted from abbreviation. If attributes found,
- * returns object with
element and
attributes
- * properties
- * @param {String} abbr
- * @returns {Object} Returns
null if no attributes found in
- * abbreviation
- */
- function parseAttributes(abbr) {
- /*
- * Example of incoming data:
- * #header
- * .some.data
- * .some.data#header
- * [attr]
- * #item[attr=Hello other="World"].class
- */
- var result = [];
- var attrMap = {'#': 'id', '.': 'class'};
- var nameEnd = null;
-
- /** @type StringStream */
- var stream = stringStream.create(abbr);
- while (!stream.eol()) {
- switch (stream.peek()) {
- case '#': // id
- case '.': // class
- if (nameEnd === null)
- nameEnd = stream.pos;
-
- var attrName = attrMap[stream.peek()];
-
- stream.next();
- stream.start = stream.pos;
- stream.eatWhile(reWord);
- result.push({
- name: attrName,
- value: stream.current()
- });
- break;
- case '[': //begin attribute set
- if (nameEnd === null)
- nameEnd = stream.pos;
-
- stream.start = stream.pos;
- if (!stream.skipToPair('[', ']')) {
- throw new Error('Invalid attribute set definition');
- }
-
- result = result.concat(
- extractAttributes(stripped(stream.current()))
- );
- break;
- default:
- stream.next();
- }
- }
-
- if (!result.length)
- return null;
-
- return {
- element: abbr.substring(0, nameEnd),
- attributes: optimizeAttributes(result)
- };
- }
-
- /**
- * Optimize attribute set: remove duplicates and merge class attributes
- * @param attrs
- */
- function optimizeAttributes(attrs) {
- // clone all attributes to make sure that original objects are
- // not modified
- attrs = attrs.map(function(attr) {
- return utils.clone(attr);
- });
-
- var lookup = {};
-
- return attrs.filter(function(attr) {
- if (!(attr.name in lookup)) {
- return lookup[attr.name] = attr;
- }
-
- var la = lookup[attr.name];
-
- if (attr.name.toLowerCase() == 'class') {
- la.value += (la.value.length ? ' ' : '') + attr.value;
- } else {
- la.value = attr.value;
- la.isImplied = !!attr.isImplied;
- }
-
- return false;
- });
- }
-
- /**
- * Extract text data from abbreviation: if
a{hello} abbreviation
- * is passed, returns object
{element: 'a', text: 'hello'}.
- * If nothing found, returns
null
- * @param {String} abbr
- *
- */
- function extractText(abbr) {
- if (!~abbr.indexOf('{'))
- return null;
-
- /** @type StringStream */
- var stream = stringStream.create(abbr);
- while (!stream.eol()) {
- switch (stream.peek()) {
- case '[':
- case '(':
- stream.skipToPair(stream.peek(), pairs[stream.peek()]); break;
-
- case '{':
- stream.start = stream.pos;
- stream.skipToPair('{', '}');
- return {
- element: abbr.substring(0, stream.start),
- text: stripped(stream.current())
- };
-
- default:
- stream.next();
- }
- }
- }
-
- /**
- * “Un-rolls“ contents of current node: recursively replaces all repeating
- * children with their repeated clones
- * @param {AbbreviationNode} node
- * @returns {AbbreviationNode}
- */
- function unroll(node) {
- for (var i = node.children.length - 1, j, child, maxCount; i >= 0; i--) {
- child = node.children[i];
-
- if (child.isRepeating()) {
- maxCount = j = child.repeatCount;
- child.repeatCount = 1;
- child.updateProperty('counter', 1);
- child.updateProperty('maxCount', maxCount);
- while (--j > 0) {
- child.parent.addChild(child.clone(), i + 1)
- .updateProperty('counter', j + 1)
- .updateProperty('maxCount', maxCount);
- }
- }
- }
-
- // to keep proper 'counter' property, we need to walk
- // on children once again
- node.children.forEach(unroll);
-
- return node;
- }
-
- /**
- * Optimizes tree node: replaces empty nodes with their children
- * @param {AbbreviationNode} node
- * @return {AbbreviationNode}
- */
- function squash(node) {
- for (var i = node.children.length - 1; i >= 0; i--) {
- /** @type AbbreviationNode */
- var n = node.children[i];
- if (n.isGroup()) {
- n.replace(squash(n).children);
- } else if (n.isEmpty()) {
- n.remove();
- }
- }
-
- node.children.forEach(squash);
-
- return node;
- }
-
- function isAllowedChar(ch) {
- var charCode = ch.charCodeAt(0);
- var specialChars = '#.*:$-_!@|%';
-
- return (charCode > 64 && charCode < 91) // uppercase letter
- || (charCode > 96 && charCode < 123) // lowercase letter
- || (charCode > 47 && charCode < 58) // number
- || specialChars.indexOf(ch) != -1; // special character
- }
-
- // XXX add counter replacer function as output processor
- outputProcessors.push(function(text, node) {
- return utils.replaceCounter(text, node.counter, node.maxCount);
- });
-
- // XXX add tabstop updater
- outputProcessors.push(tabStops.abbrOutputProcessor.bind(tabStops));
-
- // include default pre- and postprocessors
- [lorem, procResourceMatcher, procAttributes, procPastedContent, procTagName, procHref].forEach(function(mod) {
- if (mod.preprocessor) {
- preprocessors.push(mod.preprocessor.bind(mod));
- }
-
- if (mod.postprocessor) {
- postprocessors.push(mod.postprocessor.bind(mod));
- }
- });
-
- return {
- DEFAULT_ATTR_NAME: DEFAULT_ATTR_NAME,
-
- /**
- * Parses abbreviation into tree with respect of groups,
- * text nodes and attributes. Each node of the tree is a single
- * abbreviation. Tree represents actual structure of the outputted
- * result
- * @memberOf abbreviationParser
- * @param {String} abbr Abbreviation to parse
- * @param {Object} options Additional options for parser and processors
- *
- * @return {AbbreviationNode}
- */
- parse: function(abbr, options) {
- options = options || {};
-
- var tree = parseAbbreviation(abbr);
- var that = this;
-
- if (options.contextNode) {
- // add info about context node –
- // a parent XHTML node in editor inside which abbreviation is
- // expanded
- tree._name = options.contextNode.name;
- var attrLookup = {};
- tree._attributes.forEach(function(attr) {
- attrLookup[attr.name] = attr;
- });
-
- options.contextNode.attributes.forEach(function(attr) {
- if (attr.name in attrLookup) {
- attrLookup[attr.name].value = attr.value;
- } else {
- attr = utils.clone(attr);
- tree._attributes.push(attr);
- attrLookup[attr.name] = attr;
- }
- });
- }
-
- // apply preprocessors
- preprocessors.forEach(function(fn) {
- fn(tree, options, that);
- });
-
- if ('counter' in options) {
- tree.updateProperty('counter', options.counter);
- }
-
- tree = squash(unroll(tree));
-
- // apply postprocessors
- postprocessors.forEach(function(fn) {
- fn(tree, options, that);
- });
-
- return tree;
- },
-
- /**
- * Expands given abbreviation into a formatted code structure.
- * This is the main method that is used for expanding abbreviation
- * @param {String} abbr Abbreviation to expand
- * @param {Options} options Additional options for abbreviation
- * expanding and transformation: `syntax`, `profile`, `contextNode` etc.
- * @return {String}
- */
- expand: function(abbr, options) {
- if (!abbr) return '';
- if (typeof options == 'string') {
- throw new Error('Deprecated use of `expand` method: `options` must be object');
- }
-
- options = options || {};
-
- if (!options.syntax) {
- options.syntax = utils.defaultSyntax();
- }
-
- var p = profile.get(options.profile, options.syntax);
- tabStops.resetTabstopIndex();
-
- var data = filters.extract(abbr);
- var outputTree = this.parse(data[0], options);
-
- var filtersList = filters.composeList(options.syntax, p, data[1]);
- filters.apply(outputTree, filtersList, p);
-
- return outputTree.valueOf();
- },
-
- AbbreviationNode: AbbreviationNode,
-
- /**
- * Add new abbreviation preprocessor.
Preprocessor is a function
- * that applies to a parsed abbreviation tree right after it get parsed.
- * The passed tree is in unoptimized state.
- * @param {Function} fn Preprocessor function. This function receives
- * two arguments: parsed abbreviation tree (
AbbreviationNode)
- * and
options hash that was passed to
parse
- * method
- */
- addPreprocessor: function(fn) {
- if (!~preprocessors.indexOf(fn)) {
- preprocessors.push(fn);
- }
- },
-
- /**
- * Removes registered preprocessor
- */
- removeFilter: function(fn) {
- var ix = preprocessors.indexOf(fn);
- if (~ix) {
- preprocessors.splice(ix, 1);
- }
- },
-
- /**
- * Adds new abbreviation postprocessor.
Postprocessor is a
- * functinon that applies to
optimized parsed abbreviation tree
- * right before it returns from
parse() method
- * @param {Function} fn Postprocessor function. This function receives
- * two arguments: parsed abbreviation tree (
AbbreviationNode)
- * and
options hash that was passed to
parse
- * method
- */
- addPostprocessor: function(fn) {
- if (!~postprocessors.indexOf(fn)) {
- postprocessors.push(fn);
- }
- },
-
- /**
- * Removes registered postprocessor function
- */
- removePostprocessor: function(fn) {
- var ix = postprocessors.indexOf(fn);
- if (~ix) {
- postprocessors.splice(ix, 1);
- }
- },
-
- /**
- * Registers output postprocessor.
Output processor is a
- * function that applies to output part (
start,
- *
end and
content) when
- *
AbbreviationNode.toString() method is called
- */
- addOutputProcessor: function(fn) {
- if (!~outputProcessors.indexOf(fn)) {
- outputProcessors.push(fn);
- }
- },
-
- /**
- * Removes registered output processor
- */
- removeOutputProcessor: function(fn) {
- var ix = outputProcessors.indexOf(fn);
- if (~ix) {
- outputProcessors.splice(ix, 1);
- }
- },
-
- /**
- * Check if passed symbol is valid symbol for abbreviation expression
- * @param {String} ch
- * @return {Boolean}
- */
- isAllowedChar: function(ch) {
- ch = String(ch); // convert Java object to JS
- return isAllowedChar(ch) || ~'>+^[](){}'.indexOf(ch);
- }
- };
-});
-},{"../assets/profile":"assets\\profile.js","../assets/stringStream":"assets\\stringStream.js","../assets/tabStops":"assets\\tabStops.js","../filter/main":"filter\\main.js","../generator/lorem":"generator\\lorem.js","../utils/abbreviation":"utils\\abbreviation.js","../utils/common":"utils\\common.js","./processor/attributes":"parser\\processor\\attributes.js","./processor/href":"parser\\processor\\href.js","./processor/pastedContent":"parser\\processor\\pastedContent.js","./processor/resourceMatcher":"parser\\processor\\resourceMatcher.js","./processor/tagName":"parser\\processor\\tagName.js"}],"parser\\css.js":[function(require,module,exports){
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var session = {tokens: null};
-
- // walks around the source
- var walker = {
- init: function (source) {
- // this.source = source.replace(/\r\n?/g, '\n');
- this.source = source;
- this.ch = '';
- this.chnum = -1;
-
- // advance
- this.nextChar();
- },
- nextChar: function () {
- return this.ch = this.source.charAt(++this.chnum);
- },
- peek: function() {
- return this.source.charAt(this.chnum + 1);
- }
- };
-
- // utility helpers
- function isNameChar(c, cc) {
- cc = cc || c.charCodeAt(0);
- return (
- (cc >= 97 && cc <= 122 /* a-z */) ||
- (cc >= 65 && cc <= 90 /* A-Z */) ||
- /*
- Experimental: include cyrillic ranges
- since some letters, similar to latin ones, can
- accidentally appear in CSS tokens
- */
- (cc >= 1024 && cc <= 1279) ||
- c === '&' || /* selector placeholder (LESS, SCSS) */
- c === '_' ||
- c === '<' || /* comparisons (LESS, SCSS) */
- c === '>' ||
- c === '=' ||
- c === '-'
- );
- }
-
- function isDigit(c, cc) {
- cc = cc || c.charCodeAt(0);
- return (cc >= 48 && cc <= 57);
- }
-
- var isOp = (function () {
- var opsa = "{}[]()+*=.,;:>~|\\%$#@^!".split(''),
- opsmatcha = "*^|$~".split(''),
- ops = {},
- opsmatch = {},
- i = 0;
- for (; i < opsa.length; i += 1) {
- ops[opsa[i]] = true;
- }
- for (i = 0; i < opsmatcha.length; i += 1) {
- opsmatch[opsmatcha[i]] = true;
- }
- return function (ch, matchattr) {
- if (matchattr) {
- return ch in opsmatch;
- }
- return ch in ops;
- };
- }());
-
- // creates token objects and pushes them to a list
- function tokener(value, type) {
- session.tokens.push({
- value: value,
- type: type || value,
- start: null,
- end: null
- });
- }
-
- function getPosInfo(w) {
- var errPos = w.chnum;
- var source = w.source.replace(/\r\n?/g, '\n');
- var part = w.source.substring(0, errPos + 1).replace(/\r\n?/g, '\n');
- var lines = part.split('\n');
- var ch = (lines[lines.length - 1] || '').length;
- var fullLine = source.split('\n')[lines.length - 1] || '';
-
- var chunkSize = 100;
- var offset = Math.max(0, ch - chunkSize);
- var formattedLine = fullLine.substr(offset, chunkSize * 2) + '\n';
- for (var i = 0; i < ch - offset - 1; i++) {
- formattedLine += '-';
- }
- formattedLine += '^';
-
- return {
- line: lines.length,
- ch: ch,
- text: fullLine,
- hint: formattedLine
- };
- }
-
- function raiseError(message) {
- var err = error(message);
- var errObj = new Error(err.message, '', err.line);
- errObj.line = err.line;
- errObj.ch = err.ch;
- errObj.name = err.name;
- errObj.hint = err.hint;
-
- throw errObj;
- }
-
- // oops
- function error(m) {
- var w = walker;
- var info = getPosInfo(walker);
- var tokens = session.tokens;
- session.tokens = null;
-
- var message = 'CSS parsing error at line ' + info.line + ', char ' + info.ch + ': ' + m;
- message += '\n' + info.hint;
- return {
- name: "ParseError",
- message: message,
- hint: info.hint,
- line: info.line,
- ch: info.ch
- };
- }
-
-
- // token handlers follow for:
- // white space, comment, string, identifier, number, operator
- function white() {
- var c = walker.ch,
- token = '';
-
- while (c === " " || c === "\t") {
- token += c;
- c = walker.nextChar();
- }
-
- tokener(token, 'white');
-
- }
-
- function comment() {
- var w = walker,
- c = w.ch,
- token = c,
- cnext;
-
- cnext = w.nextChar();
-
- if (cnext === '/') {
- // inline comment in SCSS and LESS
- while (c && !(cnext === "\n" || cnext === "\r")) {
- token += cnext;
- c = cnext;
- cnext = w.nextChar();
- }
- } else if (cnext === '*') {
- // multiline CSS commment
- while (c && !(c === "*" && cnext === "/")) {
- token += cnext;
- c = cnext;
- cnext = w.nextChar();
- }
- } else {
- // oops, not a comment, just a /
- return tokener(token, token);
- }
-
- token += cnext;
- w.nextChar();
- tokener(token, 'comment');
- }
-
- function eatString() {
- var w = walker,
- c = w.ch,
- q = c,
- token = c,
- cnext;
-
- c = w.nextChar();
-
- while (c !== q) {
- if (c === '\n') {
- cnext = w.nextChar();
- if (cnext === "\\") {
- token += c + cnext;
- } else {
- // end of line with no \ escape = bad
- raiseError("Unterminated string");
- }
- } else if (c === '') {
- raiseError("Unterminated string");
- } else {
- if (c === "\\") {
- token += c + w.nextChar();
- } else {
- token += c;
- }
- }
-
- c = w.nextChar();
- }
-
- token += c;
-
- return token;
- }
-
- function str() {
- var token = eatString();
- walker.nextChar();
- tokener(token, 'string');
- }
-
- function brace() {
- var w = walker,
- c = w.ch,
- depth = 1,
- token = c,
- stop = false;
-
- c = w.nextChar();
-
- while (c && !stop) {
- if (c === '(') {
- depth++;
- } else if (c === ')') {
- depth--;
- if (!depth) {
- stop = true;
- }
- } else if (c === '"' || c === "'") {
- c = eatString();
- } else if (c === '') {
- raiseError("Unterminated brace");
- }
-
- token += c;
- c = w.nextChar();
- }
-
- tokener(token, 'brace');
- }
-
- function identifier(pre) {
- var c = walker.ch;
- var token = pre ? pre + c : c;
-
- c = walker.nextChar();
- var cc = c.charCodeAt(0);
- while (isNameChar(c, cc) || isDigit(c, cc)) {
- token += c;
- c = walker.nextChar();
- cc = c.charCodeAt(0);
- }
-
- tokener(token, 'identifier');
- }
-
- function num() {
- var w = walker,
- c = w.ch,
- token = c,
- point = token === '.',
- nondigit;
-
- c = w.nextChar();
- nondigit = !isDigit(c);
-
- // .2px or .classname?
- if (point && nondigit) {
- // meh, NaN, could be a class name, so it's an operator for now
- return tokener(token, '.');
- }
-
- // -2px or -moz-something
- if (token === '-' && nondigit) {
- return identifier('-');
- }
-
- while (c !== '' && (isDigit(c) || (!point && c === '.'))) { // not end of source && digit or first instance of .
- if (c === '.') {
- point = true;
- }
- token += c;
- c = w.nextChar();
- }
-
- tokener(token, 'number');
-
- }
-
- function op() {
- var w = walker,
- c = w.ch,
- token = c,
- next = w.nextChar();
-
- if (next === "=" && isOp(token, true)) {
- token += next;
- tokener(token, 'match');
- w.nextChar();
- return;
- }
-
- tokener(token, token);
- }
-
-
- // call the appropriate handler based on the first character in a token suspect
- function tokenize() {
- var ch = walker.ch;
-
- if (ch === " " || ch === "\t") {
- return white();
- }
-
- if (ch === '/') {
- return comment();
- }
-
- if (ch === '"' || ch === "'") {
- return str();
- }
-
- if (ch === '(') {
- return brace();
- }
-
- if (ch === '-' || ch === '.' || isDigit(ch)) { // tricky - char: minus (-1px) or dash (-moz-stuff)
- return num();
- }
-
- if (isNameChar(ch)) {
- return identifier();
- }
-
- if (isOp(ch)) {
- return op();
- }
-
- if (ch === '\r') {
- if (walker.peek() === '\n') {
- ch += walker.nextChar();
- }
-
- tokener(ch, 'line');
- walker.nextChar();
- return;
- }
-
- if (ch === '\n') {
- tokener(ch, 'line');
- walker.nextChar();
- return;
- }
-
- raiseError("Unrecognized character '" + ch + "'");
- }
-
- return {
- /**
- * Sprits given source into tokens
- * @param {String} source
- * @returns {Array}
- */
- lex: function (source) {
- walker.init(source);
- session.tokens = [];
-
- // for empty source, return single space token
- if (!source) {
- session.tokens.push(this.white());
- } else {
- while (walker.ch !== '') {
- tokenize();
- }
- }
-
- var tokens = session.tokens;
- session.tokens = null;
- return tokens;
- },
-
- /**
- * Tokenizes CSS source. It's like `lex()` method,
- * but also stores proper token indexes in source,
- * so it's a bit slower
- * @param {String} source
- * @returns {Array}
- */
- parse: function(source) {
- // transform tokens
- var tokens = this.lex(source), pos = 0, token;
- for (var i = 0, il = tokens.length; i < il; i++) {
- token = tokens[i];
- token.start = pos;
- token.end = (pos += token.value.length);
- }
- return tokens;
- },
-
- white: function() {
- return {
- value: '',
- type: 'white',
- start: 0,
- end: 0
- };
- },
-
- toSource: function(toks) {
- var i = 0, max = toks.length, src = '';
- for (; i < max; i++) {
- src += toks[i].value;
- }
- return src;
- }
- };
-});
-},{}],"parser\\processor\\attributes.js":[function(require,module,exports){
-/**
- * Resolves node attribute names: moves `default` attribute value
- * from stub to real attribute.
- *
- * This resolver should be applied *after* resource matcher
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../../utils/common');
-
- var findDefault = function(attr) {
- return attr.isDefault;
- };
-
- var findImplied = function(attr) {
- return attr.isImplied;
- };
-
- var findEmpty = function(attr) {
- return !attr.value;
- };
-
- function resolveDefaultAttrs(node, parser) {
- node.children.forEach(function(item) {
- var attrList = item.attributeList();
- var defaultAttrValue = item.attribute(parser.DEFAULT_ATTR_NAME);
- if (typeof defaultAttrValue !== 'undefined') {
- // remove stub attribute
- item.attribute(parser.DEFAULT_ATTR_NAME, null);
-
- if (attrList.length) {
- // target for default value:
- // 1. default attribute
- // 2. implied attribute
- // 3. first empty attribute
-
- // find attribute marked as default
- var defaultAttr = utils.find(attrList, findDefault)
- || utils.find(attrList, findImplied)
- || utils.find(attrList, findEmpty);
-
- if (defaultAttr) {
- var oldVal = item.attribute(defaultAttr.name);
- var newVal = utils.replaceUnescapedSymbol(oldVal, '|', defaultAttrValue);
- // no replacement, e.g. default value does not contains | symbol
- if (oldVal == newVal) {
- newVal = defaultAttrValue
- }
-
- item.attribute(defaultAttr.name, newVal);
- }
- }
- } else {
- // if no default attribute value, remove implied attributes
- attrList.forEach(function(attr) {
- if (attr.isImplied) {
- item.attribute(attr.name, null);
- }
- });
- }
-
- resolveDefaultAttrs(item, parser);
- });
- }
-
- return {
- /**
- * @param {AbbreviationNode} tree
- * @param {Object} options
- * @param {abbreviation} parser
- */
- preprocessor: function(tree, options, parser) {
- resolveDefaultAttrs(tree, parser);
- }
- };
-});
-},{"../../utils/common":"utils\\common.js"}],"parser\\processor\\href.js":[function(require,module,exports){
-/**
- * A preptocessor for <a> tag: tests wrapped content
- * for common URL patterns and, if matched, inserts it as
- * `href` attribute
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var prefs = require('../../assets/preferences');
- var utils = require('../../utils/common');
- var pc = require('./pastedContent');
-
- prefs.define('href.autodetect', true,
- 'Enables or disables automatic URL recognition when wrapping\
- text with
<a> tag. With this option enabled,\
- if wrapped text matches URL or e-mail pattern it will be automatically\
- inserted into
href attribute.');
- prefs.define('href.urlPattern', '^(?:(?:https?|ftp|file)://|www\\.|ftp\\.)(?:\\([-A-Z0-9+&@#/%=~_|$?!:,.]*\\)|[-A-Z0-9+&@#/%=~_|$?!:,.])*(?:\\([-A-Z0-9+&@#/%=~_|$?!:,.]*\\)|[A-Z0-9+&@#/%=~_|$])',
- 'RegExp pattern to match wrapped URLs. Matched content will be inserts\
- as-is into
href attribute, only whitespace will be trimmed.');
-
- prefs.define('href.emailPattern', '^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,5}$',
- 'RegExp pattern to match wrapped e-mails. Unlike
href.urlPattern,\
- wrapped content will be prefixed with
mailto: in
href\
- attribute');
-
- return {
- /**
- * @param {AbbreviationNode} tree
- * @param {Object} options
- */
- postprocessor: function(tree, options) {
- if (!prefs.get('href.autodetect')) {
- return;
- }
-
- var reUrl = new RegExp(prefs.get('href.urlPattern'), 'i');
- var reEmail = new RegExp(prefs.get('href.emailPattern'), 'i');
- var reProto = /^([a-z]+:)?\/\//i;
-
- tree.findAll(function(item) {
- if (item.name().toLowerCase() != 'a' || item.attribute('href')) {
- return;
- }
-
- var pastedContent = utils.trim(pc.pastedContent(item) || options.pastedContent);
- if (pastedContent) {
- if (reUrl.test(pastedContent)) {
- // do we have protocol?
- if (!reProto.test(pastedContent)) {
- pastedContent = 'http://' + pastedContent;
- }
-
- item.attribute('href', pastedContent);
- } else if (reEmail.test(pastedContent)) {
- item.attribute('href', 'mailto:' + pastedContent);
- }
- }
- });
- }
- };
-});
-},{"../../assets/preferences":"assets\\preferences.js","../../utils/common":"utils\\common.js","./pastedContent":"parser\\processor\\pastedContent.js"}],"parser\\processor\\pastedContent.js":[function(require,module,exports){
-/**
- * Pasted content abbreviation processor. A pasted content is a content that
- * should be inserted into implicitly repeated abbreviation nodes.
- * This processor powers “Wrap With Abbreviation” action
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../../utils/common');
- var abbrUtils = require('../../utils/abbreviation');
- var stringStream = require('../../assets/stringStream');
- var range = require('../../assets/range');
-
- var outputPlaceholder = '$#';
-
- /**
- * Locates output placeholders inside text
- * @param {String} text
- * @returns {Array} Array of ranges of output placeholder in text
- */
- function locateOutputPlaceholder(text) {
- var result = [];
-
- var stream = stringStream.create(text);
-
- while (!stream.eol()) {
- if (stream.peek() == '\\') {
- stream.next();
- } else {
- stream.start = stream.pos;
- if (stream.match(outputPlaceholder, true)) {
- result.push(range.create(stream.start, outputPlaceholder));
- continue;
- }
- }
- stream.next();
- }
-
- return result;
- }
-
- /**
- * Replaces output placeholders inside
source with
- *
value
- * @param {String} source
- * @param {String} value
- * @returns {String}
- */
- function replaceOutputPlaceholders(source, value) {
- var ranges = locateOutputPlaceholder(source);
-
- ranges.reverse().forEach(function(r) {
- source = utils.replaceSubstring(source, value, r);
- });
-
- return source;
- }
-
- /**
- * Check if parsed node contains output placeholder – a target where
- * pasted content should be inserted
- * @param {AbbreviationNode} node
- * @returns {Boolean}
- */
- function hasOutputPlaceholder(node) {
- if (locateOutputPlaceholder(node.content).length)
- return true;
-
- // check if attributes contains placeholder
- return !!utils.find(node.attributeList(), function(attr) {
- return !!locateOutputPlaceholder(attr.value).length;
- });
- }
-
- /**
- * Insert pasted content into correct positions of parsed node
- * @param {AbbreviationNode} node
- * @param {String} content
- * @param {Boolean} overwrite Overwrite node content if no value placeholders
- * found instead of appending to existing content
- */
- function insertPastedContent(node, content, overwrite) {
- var nodesWithPlaceholders = node.findAll(function(item) {
- return hasOutputPlaceholder(item);
- });
-
- if (hasOutputPlaceholder(node))
- nodesWithPlaceholders.unshift(node);
-
- if (nodesWithPlaceholders.length) {
- nodesWithPlaceholders.forEach(function(item) {
- item.content = replaceOutputPlaceholders(item.content, content);
- item._attributes.forEach(function(attr) {
- attr.value = replaceOutputPlaceholders(attr.value, content);
- });
- });
- } else {
- // on output placeholders in subtree, insert content in the deepest
- // child node
- var deepest = node.deepestChild() || node;
- if (overwrite) {
- deepest.content = content;
- } else {
- deepest.content = abbrUtils.insertChildContent(deepest.content, content);
- }
- }
- }
-
- return {
- pastedContent: function(item) {
- var content = item.data('paste');
- if (Array.isArray(content)) {
- return content[item.counter - 1];
- } else if (typeof content === 'function') {
- return content(item.counter - 1, item.content);
- } else if (content) {
- return content;
- }
- },
-
- /**
- * @param {AbbreviationNode} tree
- * @param {Object} options
- */
- preprocessor: function(tree, options) {
- if (options.pastedContent) {
- var lines = utils.splitByLines(options.pastedContent, true).map(utils.trim);
-
- // set repeat count for implicitly repeated elements before
- // tree is unrolled
- tree.findAll(function(item) {
- if (item.hasImplicitRepeat) {
- item.data('paste', lines);
- return item.repeatCount = lines.length;
- }
- });
- }
- },
-
- /**
- * @param {AbbreviationNode} tree
- * @param {Object} options
- */
- postprocessor: function(tree, options) {
- var that = this;
- // for each node with pasted content, update text data
- var targets = tree.findAll(function(item) {
- var pastedContent = that.pastedContent(item);
- if (pastedContent) {
- insertPastedContent(item, pastedContent, !!item.data('pasteOverwrites'));
- }
-
- return !!pastedContent;
- });
-
- if (!targets.length && options.pastedContent) {
- // no implicitly repeated elements, put pasted content in
- // the deepest child
- insertPastedContent(tree, options.pastedContent);
- }
- }
- };
-});
-},{"../../assets/range":"assets\\range.js","../../assets/stringStream":"assets\\stringStream.js","../../utils/abbreviation":"utils\\abbreviation.js","../../utils/common":"utils\\common.js"}],"parser\\processor\\resourceMatcher.js":[function(require,module,exports){
-/**
- * Processor function that matches parsed
AbbreviationNode
- * against resources defined in
resource module
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var resources = require('../../assets/resources');
- var elements = require('../../assets/elements');
- var utils = require('../../utils/common');
- var abbreviationUtils = require('../../utils/abbreviation');
-
- /**
- * Finds matched resources for child nodes of passed
node
- * element. A matched resource is a reference to
snippets.json entry
- * that describes output of parsed node
- * @param {AbbreviationNode} node
- * @param {String} syntax
- */
- function matchResources(node, syntax, parser) {
- // do a shallow copy because the children list can be modified during
- // resource matching
- node.children.slice(0).forEach(function(child) {
- var r = resources.getMatchedResource(child, syntax);
- if (typeof r === 'string') {
- r = elements.create('snippet', r);
- }
-
- child.data('resource', r);
- var elemType = elements.type(r);
-
- if (elemType == 'snippet') {
- var content = r.data;
- var curContent = child._text || child.content;
- if (curContent) {
- content = abbreviationUtils.insertChildContent(content, curContent);
- }
-
- child.content = content;
- } else if (elemType == 'element') {
- child._name = r.name;
- if (Array.isArray(r.attributes)) {
- child._attributes = [].concat(r.attributes, child._attributes);
- }
- } else if (elemType == 'reference') {
- // it’s a reference to another abbreviation:
- // parse it and insert instead of current child
- /** @type AbbreviationNode */
- var subtree = parser.parse(r.data, {
- syntax: syntax
- });
-
- // if context element should be repeated, check if we need to
- // transfer repeated element to specific child node
- if (child.repeatCount > 1) {
- var repeatedChildren = subtree.findAll(function(node) {
- return node.hasImplicitRepeat;
- });
-
- if (!repeatedChildren.length) {
- repeatedChildren = subtree.children
- }
-
- repeatedChildren.forEach(function(node) {
- node.repeatCount = child.repeatCount;
- node.hasImplicitRepeat = false;
- });
- }
-
- // move child‘s children into the deepest child of new subtree
- var deepestChild = subtree.deepestChild();
- if (deepestChild) {
- child.children.forEach(function(c) {
- deepestChild.addChild(c);
- });
- deepestChild.content = child.content;
- }
-
- // copy current attributes to children
- subtree.children.forEach(function(node) {
- child.attributeList().forEach(function(attr) {
- node.attribute(attr.name, attr.value);
- });
- });
-
- child.replace(subtree.children);
- }
-
- matchResources(child, syntax, parser);
- });
- }
-
- return {
- preprocessor: function(tree, options, parser) {
- var syntax = options.syntax || utils.defaultSyntax();
- matchResources(tree, syntax, parser);
- }
- };
-});
-},{"../../assets/elements":"assets\\elements.js","../../assets/resources":"assets\\resources.js","../../utils/abbreviation":"utils\\abbreviation.js","../../utils/common":"utils\\common.js"}],"parser\\processor\\tagName.js":[function(require,module,exports){
-/**
- * Resolves tag names in abbreviations with implied name
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var tagName = require('../../resolver/tagName');
-
- /**
- * Resolves implicit node names in parsed tree
- * @param {AbbreviationNode} tree
- */
- function resolveNodeNames(tree) {
- tree.children.forEach(function(node) {
- if (node.hasImplicitName() || node.data('forceNameResolving')) {
- node._name = tagName.resolve(node.parent.name());
- node.data('nameResolved', true);
- }
- resolveNodeNames(node);
- });
-
- return tree;
- }
-
- return {
- postprocessor: resolveNodeNames
- };
-});
-},{"../../resolver/tagName":"resolver\\tagName.js"}],"parser\\xml.js":[function(require,module,exports){
-/**
- * HTML tokenizer by Marijn Haverbeke
- * http://codemirror.net/
- * @constructor
- * @memberOf __xmlParseDefine
- * @param {Function} require
- * @param {Underscore} _
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var stringStream = require('../assets/stringStream');
-
- var Kludges = {
- autoSelfClosers : {},
- implicitlyClosed : {},
- contextGrabbers : {},
- doNotIndent : {},
- allowUnquoted : true,
- allowMissing : true
- };
-
- // Return variables for tokenizers
- var tagName = null, type = null;
-
- function inText(stream, state) {
- function chain(parser) {
- state.tokenize = parser;
- return parser(stream, state);
- }
-
- var ch = stream.next();
- if (ch == "<") {
- if (stream.eat("!")) {
- if (stream.eat("[")) {
- if (stream.match("CDATA["))
- return chain(inBlock("atom", "]]>"));
- else
- return null;
- } else if (stream.match("--"))
- return chain(inBlock("comment", "-->"));
- else if (stream.match("DOCTYPE", true, true)) {
- stream.eatWhile(/[\w\._\-]/);
- return chain(doctype(1));
- } else
- return null;
- } else if (stream.eat("?")) {
- stream.eatWhile(/[\w\._\-]/);
- state.tokenize = inBlock("meta", "?>");
- return "meta";
- } else {
- type = stream.eat("/") ? "closeTag" : "openTag";
- stream.eatSpace();
- tagName = "";
- var c;
- while ((c = stream.eat(/[^\s\u00a0=<>\"\'\/?]/)))
- tagName += c;
- state.tokenize = inTag;
- return "tag";
- }
- } else if (ch == "&") {
- var ok;
- if (stream.eat("#")) {
- if (stream.eat("x")) {
- ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
- } else {
- ok = stream.eatWhile(/[\d]/) && stream.eat(";");
- }
- } else {
- ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
- }
- return ok ? "atom" : "error";
- } else {
- stream.eatWhile(/[^&<]/);
- return "text";
- }
- }
-
- function inTag(stream, state) {
- var ch = stream.next();
- if (ch == ">" || (ch == "/" && stream.eat(">"))) {
- state.tokenize = inText;
- type = ch == ">" ? "endTag" : "selfcloseTag";
- return "tag";
- } else if (ch == "=") {
- type = "equals";
- return null;
- } else if (/[\'\"]/.test(ch)) {
- state.tokenize = inAttribute(ch);
- return state.tokenize(stream, state);
- } else {
- stream.eatWhile(/[^\s\u00a0=<>\"\'\/?]/);
- return "word";
- }
- }
-
- function inAttribute(quote) {
- return function(stream, state) {
- while (!stream.eol()) {
- if (stream.next() == quote) {
- state.tokenize = inTag;
- break;
- }
- }
- return "string";
- };
- }
-
- function inBlock(style, terminator) {
- return function(stream, state) {
- while (!stream.eol()) {
- if (stream.match(terminator)) {
- state.tokenize = inText;
- break;
- }
- stream.next();
- }
- return style;
- };
- }
-
- function doctype(depth) {
- return function(stream, state) {
- var ch;
- while ((ch = stream.next()) !== null) {
- if (ch == "<") {
- state.tokenize = doctype(depth + 1);
- return state.tokenize(stream, state);
- } else if (ch == ">") {
- if (depth == 1) {
- state.tokenize = inText;
- break;
- } else {
- state.tokenize = doctype(depth - 1);
- return state.tokenize(stream, state);
- }
- }
- }
- return "meta";
- };
- }
-
- var curState = null, setStyle;
- function pass() {
- for (var i = arguments.length - 1; i >= 0; i--)
- curState.cc.push(arguments[i]);
- }
-
- function cont() {
- pass.apply(null, arguments);
- return true;
- }
-
- function pushContext(tagName, startOfLine) {
- var noIndent = Kludges.doNotIndent.hasOwnProperty(tagName)
- || (curState.context && curState.context.noIndent);
- curState.context = {
- prev : curState.context,
- tagName : tagName,
- indent : curState.indented,
- startOfLine : startOfLine,
- noIndent : noIndent
- };
- }
-
- function popContext() {
- if (curState.context)
- curState.context = curState.context.prev;
- }
-
- function element(type) {
- if (type == "openTag") {
- curState.tagName = tagName;
- return cont(attributes, endtag(curState.startOfLine));
- } else if (type == "closeTag") {
- var err = false;
- if (curState.context) {
- if (curState.context.tagName != tagName) {
- if (Kludges.implicitlyClosed.hasOwnProperty(curState.context.tagName.toLowerCase())) {
- popContext();
- }
- err = !curState.context || curState.context.tagName != tagName;
- }
- } else {
- err = true;
- }
-
- if (err)
- setStyle = "error";
- return cont(endclosetag(err));
- }
- return cont();
- }
-
- function endtag(startOfLine) {
- return function(type) {
- if (type == "selfcloseTag"
- || (type == "endTag" && Kludges.autoSelfClosers
- .hasOwnProperty(curState.tagName
- .toLowerCase()))) {
- maybePopContext(curState.tagName.toLowerCase());
- return cont();
- }
- if (type == "endTag") {
- maybePopContext(curState.tagName.toLowerCase());
- pushContext(curState.tagName, startOfLine);
- return cont();
- }
- return cont();
- };
- }
-
- function endclosetag(err) {
- return function(type) {
- if (err)
- setStyle = "error";
- if (type == "endTag") {
- popContext();
- return cont();
- }
- setStyle = "error";
- return cont(arguments.callee);
- };
- }
-
- function maybePopContext(nextTagName) {
- var parentTagName;
- while (true) {
- if (!curState.context) {
- return;
- }
- parentTagName = curState.context.tagName.toLowerCase();
- if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName)
- || !Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
- return;
- }
- popContext();
- }
- }
-
- function attributes(type) {
- if (type == "word") {
- setStyle = "attribute";
- return cont(attribute, attributes);
- }
- if (type == "endTag" || type == "selfcloseTag")
- return pass();
- setStyle = "error";
- return cont(attributes);
- }
-
- function attribute(type) {
- if (type == "equals")
- return cont(attvalue, attributes);
- if (!Kludges.allowMissing)
- setStyle = "error";
- return (type == "endTag" || type == "selfcloseTag") ? pass()
- : cont();
- }
-
- function attvalue(type) {
- if (type == "string")
- return cont(attvaluemaybe);
- if (type == "word" && Kludges.allowUnquoted) {
- setStyle = "string";
- return cont();
- }
- setStyle = "error";
- return (type == "endTag" || type == "selfCloseTag") ? pass()
- : cont();
- }
-
- function attvaluemaybe(type) {
- if (type == "string")
- return cont(attvaluemaybe);
- else
- return pass();
- }
-
- function startState() {
- return {
- tokenize : inText,
- cc : [],
- indented : 0,
- startOfLine : true,
- tagName : null,
- context : null
- };
- }
-
- function token(stream, state) {
- if (stream.sol()) {
- state.startOfLine = true;
- state.indented = 0;
- }
-
- if (stream.eatSpace())
- return null;
-
- setStyle = type = tagName = null;
- var style = state.tokenize(stream, state);
- state.type = type;
- if ((style || type) && style != "comment") {
- curState = state;
- while (true) {
- var comb = state.cc.pop() || element;
- if (comb(type || style))
- break;
- }
- }
- state.startOfLine = false;
- return setStyle || style;
- }
-
- return {
- /**
- * @memberOf emmet.xmlParser
- * @returns
- */
- parse: function(data, offset) {
- offset = offset || 0;
- var state = startState();
- var stream = stringStream.create(data);
- var tokens = [];
- while (!stream.eol()) {
- tokens.push({
- type: token(stream, state),
- start: stream.start + offset,
- end: stream.pos + offset
- });
- stream.start = stream.pos;
- }
-
- return tokens;
- }
- };
-});
-
-},{"../assets/stringStream":"assets\\stringStream.js"}],"plugin\\file.js":[function(require,module,exports){
-/**
- * Module for working with file. Shall implement
- * IEmmetFile interface.
- *
- * Since implementation of this module depends
- * greatly on current runtime, this module must be
- * initialized with actual implementation first
- * before use. E.g.
- * require('./plugin/file')({
- * read: function() {...}
- * })
- *
- * By default, this module provides Node.JS implementation
- */
-
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../utils/common');
- var _transport = {};
-
- // hide it from Require.JS parser
- (function(r) {
- if (typeof define === 'undefined' || !define.amd) {
- try {
- fs = r('fs');
- path = r('path');
- _transport.http = r('http');
- _transport.https = r('https');
- } catch(e) { }
- }
- })(require);
-
- // module is a function that can extend itself
- module.exports = function(obj) {
- if (obj) {
- utils.extend(module.exports, obj);
- }
- };
-
- function bts(bytes) {
- var out = [];
- for (var i = 0, il = bytes.length; i < il; i++) {
- out.push(String.fromCharCode(bytes[i]));
- }
- return out.join('');
- }
-
- function isURL(path) {
- var re = /^https?:\/\//;
- return re.test(path);
- }
-
- return utils.extend(module.exports, {
- _parseParams: function(args) {
- var params = {
- path: args[0],
- size: 0
- };
-
- args = utils.toArray(args, 1);
- params.callback = args[args.length - 1];
- args = args.slice(0, args.length - 1);
- if (args.length) {
- params.size = args[0];
- }
-
- return params;
- },
-
- _read: function(params, callback) {
- if (isURL(params.path)) {
- var req = _transport[/^https:/.test(params.path) ? 'https' : 'http'].get(params.path, function(res) {
- var bufs = [];
- var totalLength = 0;
- var finished = false;
- res
- .on('data', function(chunk) {
- totalLength += chunk.length;
- bufs.push(chunk);
- if (params.size && totalLength >= params.size) {
- finished = true;
- callback(null, Buffer.concat(bufs));
- req.abort();
- }
- })
- .on('end', function() {
- if (!finished) {
- finished = true;
- callback(null, Buffer.concat(bufs));
- }
- });
- }).on('error', callback);
- } else {
- if (params.size) {
- var fd = fs.openSync(params.path, 'r');
- var buf = new Buffer(params.size);
- fs.read(fd, buf, 0, params.size, null, function(err, bytesRead) {
- callback(err, buf)
- });
- } else {
- callback(null, fs.readFileSync(params.path));
- }
- }
- },
-
- /**
- * Reads binary file content and return it
- * @param {String} path File's relative or absolute path
- * @return {String}
- */
- read: function(path, size, callback) {
- var params = this._parseParams(arguments);
- this._read(params, function(err, buf) {
- params.callback(err, err ? '' : bts(buf));
- });
- },
-
- /**
- * Read file content and return it
- * @param {String} path File's relative or absolute path
- * @return {String}
- */
- readText: function(path, size, callback) {
- var params = this._parseParams(arguments);
- this._read(params, function(err, buf) {
- params.callback(err, err ? '' : buf.toString());
- });
- },
-
- /**
- * Locate
file_name file that relates to
editor_file.
- * File name may be absolute or relative path
- *
- *
Dealing with absolute path.
- * Many modern editors have a "project" support as information unit, but you
- * should not rely on project path to find file with absolute path. First,
- * it requires user to create a project before using this method (and this
- * is not very convenient). Second, project path doesn't always points to
- * to website's document root folder: it may point, for example, to an
- * upper folder which contains server-side scripts.
- *
- * For better result, you should use the following algorithm in locating
- * absolute resources:
- * 1) Get parent folder for
editorFile as a start point
- * 2) Append required
fileName to start point and test if
- * file exists
- * 3) If it doesn't exists, move start point one level up (to parent folder)
- * and repeat step 2.
- *
- * @param {String} editorFile
- * @param {String} fileName
- * @return {String} Returns null if
fileName cannot be located
- */
- locateFile: function(editorFile, fileName, callback) {
- if (isURL(fileName)) {
- return callback(fileName);
- }
-
- var dirname = editorFile
- var filepath;
- fileName = fileName.replace(/^\/+/, '');
- while (dirname && dirname !== path.dirname(dirname)) {
- dirname = path.dirname(dirname);
- filepath = path.join(dirname, fileName);
- if (fs.existsSync(filepath))
- return callback(filepath);
- }
-
- callback(null);
- },
-
- /**
- * Creates absolute path by concatenating
parent and
fileName.
- * If
parent points to file, its parent directory is used
- * @param {String} parent
- * @param {String} fileName
- * @return {String}
- */
- createPath: function(parent, fileName, callback) {
- fs.stat(parent, function(err, stat) {
- if (err) {
- return callback(err);
- }
-
- if (stat.isFile()) {
- parent = path.dirname(parent);
- }
-
- var filepath = path.resolve(parent, fileName);
- callback(null, filepath);
- });
- },
-
- /**
- * Saves
content as
file
- * @param {String} file File's absolute path
- * @param {String} content File content
- */
- save: function(file, content, callback) {
- fs.writeFile(file, content, 'ascii', function(err) {
- callback(err ? err : null);
- });
- },
-
- /**
- * Returns file extension in lower case
- * @param {String} file
- * @return {String}
- */
- getExt: function(file) {
- var m = (file || '').match(/\.([\w\-]+)$/);
- return m ? m[1].toLowerCase() : '';
- }
-
- });
-});
-
-},{"../utils/common":"utils\\common.js"}],"resolver\\css.js":[function(require,module,exports){
-/**
- * Resolver for fast CSS typing. Handles abbreviations with the following
- * notation:
- *
- *
(-vendor prefix)?property(value)*(!)?
- *
- *
- *
Abbreviation handling
- *
- * By default, Emmet searches for matching snippet definition for provided abbreviation.
- * If snippet wasn't found, Emmet automatically generates element with
- * abbreviation's name. For example,
foo abbreviation will generate
- *
<foo></foo> output.
- *
- * This module will capture all expanded properties and upgrade them with values,
- * vendor prefixes and !important declarations. All unmatched abbreviations will
- * be automatically transformed into
property-name: ${1} snippets.
- *
- *
Vendor prefixes
- *
- * If CSS-property is preceded with dash, resolver should output property with
- * all known vendor prefixes. For example, if brad
- * abbreviation generates border-radius: ${value}; snippet,
- * the -brad abbreviation should generate:
- *
- * -webkit-border-radius: ${value};
- * -moz-border-radius: ${value};
- * border-radius: ${value};
- *
- * Note that o and ms prefixes are omitted since Opera and IE
- * supports unprefixed property.
- *
- * Users can also provide an explicit list of one-character prefixes for any
- * CSS property. For example, -wm-float will produce
- *
- *
- * -webkit-float: ${1};
- * -moz-float: ${1};
- * float: ${1};
- *
- *
- * Although this example looks pointless, users can use this feature to write
- * cutting-edge properties implemented by browser vendors recently.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var prefs = require('../assets/preferences');
- var resources = require('../assets/resources');
- var stringStream = require('../assets/stringStream');
- var ciu = require('../assets/caniuse');
- var utils = require('../utils/common');
- var template = require('../utils/template');
- var cssEditTree = require('../editTree/css');
-
- var prefixObj = {
- /** Real vendor prefix name */
- prefix: 'emmet',
-
- /**
- * Indicates this prefix is obsolete and should't be used when user
- * wants to generate all-prefixed properties
- */
- obsolete: false,
-
- /**
- * Returns prefixed CSS property name
- * @param {String} name Unprefixed CSS property
- */
- transformName: function(name) {
- return '-' + this.prefix + '-' + name;
- },
-
- /**
- * List of unprefixed CSS properties that supported by
- * current prefix. This list is used to generate all-prefixed property
- * @returns {Array}
- */
- properties: function() {
- return getProperties('css.' + this.prefix + 'Properties') || [];
- },
-
- /**
- * Check if given property is supported by current prefix
- * @param name
- */
- supports: function(name) {
- return ~this.properties().indexOf(name);
- }
- };
-
-
- /**
- * List of registered one-character prefixes. Key is a one-character prefix,
- * value is an prefixObj object
- */
- var vendorPrefixes = {};
-
- var defaultValue = '${1};';
-
- // XXX module preferences
- prefs.define('css.valueSeparator', ': ',
- 'Defines a symbol that should be placed between CSS property and '
- + 'value when expanding CSS abbreviations.');
- prefs.define('css.propertyEnd', ';',
- 'Defines a symbol that should be placed at the end of CSS property '
- + 'when expanding CSS abbreviations.');
-
- prefs.define('stylus.valueSeparator', ' ',
- 'Defines a symbol that should be placed between CSS property and '
- + 'value when expanding CSS abbreviations in Stylus dialect.');
- prefs.define('stylus.propertyEnd', '',
- 'Defines a symbol that should be placed at the end of CSS property '
- + 'when expanding CSS abbreviations in Stylus dialect.');
-
- prefs.define('sass.propertyEnd', '',
- 'Defines a symbol that should be placed at the end of CSS property '
- + 'when expanding CSS abbreviations in SASS dialect.');
-
- prefs.define('css.syntaxes', 'css, less, sass, scss, stylus, styl',
- 'List of syntaxes that should be treated as CSS dialects.');
-
- prefs.define('css.autoInsertVendorPrefixes', true,
- 'Automatically generate vendor-prefixed copies of expanded CSS '
- + 'property. By default, Emmet will generate vendor-prefixed '
- + 'properties only when you put dash before abbreviation '
- + '(e.g. -bxsh). With this option enabled, you don’t '
- + 'need dashes before abbreviations: Emmet will produce '
- + 'vendor-prefixed properties for you.');
-
- prefs.define('less.autoInsertVendorPrefixes', false, 'Same as css.autoInsertVendorPrefixes but for LESS syntax');
- prefs.define('scss.autoInsertVendorPrefixes', false, 'Same as css.autoInsertVendorPrefixes but for SCSS syntax');
- prefs.define('sass.autoInsertVendorPrefixes', false, 'Same as css.autoInsertVendorPrefixes but for SASS syntax');
- prefs.define('stylus.autoInsertVendorPrefixes', false, 'Same as css.autoInsertVendorPrefixes but for Stylus syntax');
-
- var descTemplate = template('A comma-separated list of CSS properties that may have '
- + '<%= vendor %> vendor prefix. This list is used to generate '
- + 'a list of prefixed properties when expanding -property '
- + 'abbreviations. Empty list means that all possible CSS values may '
- + 'have <%= vendor %> prefix.');
-
- var descAddonTemplate = template('A comma-separated list of additional CSS properties '
- + 'for css.<%= vendor %>Preperties preference. '
- + 'You should use this list if you want to add or remove a few CSS '
- + 'properties to original set. To add a new property, simply write its name, '
- + 'to remove it, precede property with hyphen. '
- + 'For example, to add foo property and remove border-radius one, '
- + 'the preference value will look like this: foo, -border-radius.');
-
- // properties list is created from cssFeatures.html file
- var props = {
- 'webkit': 'animation, animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, appearance, backface-visibility, background-clip, background-composite, background-origin, background-size, border-fit, border-horizontal-spacing, border-image, border-vertical-spacing, box-align, box-direction, box-flex, box-flex-group, box-lines, box-ordinal-group, box-orient, box-pack, box-reflect, box-shadow, color-correction, column-break-after, column-break-before, column-break-inside, column-count, column-gap, column-rule-color, column-rule-style, column-rule-width, column-span, column-width, dashboard-region, font-smoothing, highlight, hyphenate-character, hyphenate-limit-after, hyphenate-limit-before, hyphens, line-box-contain, line-break, line-clamp, locale, margin-before-collapse, margin-after-collapse, marquee-direction, marquee-increment, marquee-repetition, marquee-style, mask-attachment, mask-box-image, mask-box-image-outset, mask-box-image-repeat, mask-box-image-slice, mask-box-image-source, mask-box-image-width, mask-clip, mask-composite, mask-image, mask-origin, mask-position, mask-repeat, mask-size, nbsp-mode, perspective, perspective-origin, rtl-ordering, text-combine, text-decorations-in-effect, text-emphasis-color, text-emphasis-position, text-emphasis-style, text-fill-color, text-orientation, text-security, text-stroke-color, text-stroke-width, transform, transition, transform-origin, transform-style, transition-delay, transition-duration, transition-property, transition-timing-function, user-drag, user-modify, user-select, writing-mode, svg-shadow, box-sizing, border-radius',
- 'moz': 'animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, appearance, backface-visibility, background-inline-policy, binding, border-bottom-colors, border-image, border-left-colors, border-right-colors, border-top-colors, box-align, box-direction, box-flex, box-ordinal-group, box-orient, box-pack, box-shadow, box-sizing, column-count, column-gap, column-rule-color, column-rule-style, column-rule-width, column-width, float-edge, font-feature-settings, font-language-override, force-broken-image-icon, hyphens, image-region, orient, outline-radius-bottomleft, outline-radius-bottomright, outline-radius-topleft, outline-radius-topright, perspective, perspective-origin, stack-sizing, tab-size, text-blink, text-decoration-color, text-decoration-line, text-decoration-style, text-size-adjust, transform, transform-origin, transform-style, transition, transition-delay, transition-duration, transition-property, transition-timing-function, user-focus, user-input, user-modify, user-select, window-shadow, background-clip, border-radius',
- 'ms': 'accelerator, backface-visibility, background-position-x, background-position-y, behavior, block-progression, box-align, box-direction, box-flex, box-line-progression, box-lines, box-ordinal-group, box-orient, box-pack, content-zoom-boundary, content-zoom-boundary-max, content-zoom-boundary-min, content-zoom-chaining, content-zoom-snap, content-zoom-snap-points, content-zoom-snap-type, content-zooming, filter, flow-from, flow-into, font-feature-settings, grid-column, grid-column-align, grid-column-span, grid-columns, grid-layer, grid-row, grid-row-align, grid-row-span, grid-rows, high-contrast-adjust, hyphenate-limit-chars, hyphenate-limit-lines, hyphenate-limit-zone, hyphens, ime-mode, interpolation-mode, layout-flow, layout-grid, layout-grid-char, layout-grid-line, layout-grid-mode, layout-grid-type, line-break, overflow-style, perspective, perspective-origin, perspective-origin-x, perspective-origin-y, scroll-boundary, scroll-boundary-bottom, scroll-boundary-left, scroll-boundary-right, scroll-boundary-top, scroll-chaining, scroll-rails, scroll-snap-points-x, scroll-snap-points-y, scroll-snap-type, scroll-snap-x, scroll-snap-y, scrollbar-arrow-color, scrollbar-base-color, scrollbar-darkshadow-color, scrollbar-face-color, scrollbar-highlight-color, scrollbar-shadow-color, scrollbar-track-color, text-align-last, text-autospace, text-justify, text-kashida-space, text-overflow, text-size-adjust, text-underline-position, touch-action, transform, transform-origin, transform-origin-x, transform-origin-y, transform-origin-z, transform-style, transition, transition-delay, transition-duration, transition-property, transition-timing-function, user-select, word-break, wrap-flow, wrap-margin, wrap-through, writing-mode',
- 'o': 'dashboard-region, animation, animation-delay, animation-direction, animation-duration, animation-fill-mode, animation-iteration-count, animation-name, animation-play-state, animation-timing-function, border-image, link, link-source, object-fit, object-position, tab-size, table-baseline, transform, transform-origin, transition, transition-delay, transition-duration, transition-property, transition-timing-function, accesskey, input-format, input-required, marquee-dir, marquee-loop, marquee-speed, marquee-style'
- };
-
- Object.keys(props).forEach(function(k) {
- prefs.define('css.' + k + 'Properties', props[k], descTemplate({vendor: k}));
- prefs.define('css.' + k + 'PropertiesAddon', '', descAddonTemplate({vendor: k}));
- });
-
- prefs.define('css.unitlessProperties', 'z-index, line-height, opacity, font-weight, zoom',
- 'The list of properties whose values must not contain units.');
-
- prefs.define('css.intUnit', 'px', 'Default unit for integer values');
- prefs.define('css.floatUnit', 'em', 'Default unit for float values');
-
- prefs.define('css.keywords', 'auto, inherit, all',
- 'A comma-separated list of valid keywords that can be used in CSS abbreviations.');
-
- prefs.define('css.keywordAliases', 'a:auto, i:inherit, s:solid, da:dashed, do:dotted, t:transparent',
- 'A comma-separated list of keyword aliases, used in CSS abbreviation. '
- + 'Each alias should be defined as alias:keyword_name.');
-
- prefs.define('css.unitAliases', 'e:em, p:%, x:ex, r:rem',
- 'A comma-separated list of unit aliases, used in CSS abbreviation. '
- + 'Each alias should be defined as alias:unit_value.');
-
- prefs.define('css.color.short', true,
- 'Should color values like #ffffff be shortened to '
- + '#fff after abbreviation with color was expanded.');
-
- prefs.define('css.color.case', 'keep',
- 'Letter case of color values generated by abbreviations with color '
- + '(like c#0). Possible values are upper, '
- + 'lower and keep.');
-
- prefs.define('css.fuzzySearch', true,
- 'Enable fuzzy search among CSS snippet names. When enabled, every '
- + 'unknown snippet will be scored against available snippet '
- + 'names (not values or CSS properties!). The match with best score '
- + 'will be used to resolve snippet value. For example, with this '
- + 'preference enabled, the following abbreviations are equal: '
- + 'ov:h == ov-h == o-h == '
- + 'oh');
-
- prefs.define('css.fuzzySearchMinScore', 0.3,
- 'The minium score (from 0 to 1) that fuzzy-matched abbreviation should '
- + 'achive. Lower values may produce many false-positive matches, '
- + 'higher values may reduce possible matches.');
-
- prefs.define('css.alignVendor', false,
- 'If set to true, all generated vendor-prefixed properties '
- + 'will be aligned by real property name.');
-
-
- function isNumeric(ch) {
- var code = ch && ch.charCodeAt(0);
- return (ch && ch == '.' || (code > 47 && code < 58));
- }
-
- /**
- * Check if provided snippet contains only one CSS property and value.
- * @param {String} snippet
- * @returns {Boolean}
- */
- function isSingleProperty(snippet) {
- snippet = utils.trim(snippet);
-
- // check if it doesn't contain a comment and a newline
- if (/\/\*|\n|\r/.test(snippet)) {
- return false;
- }
-
- // check if it's a valid snippet definition
- if (!/^[a-z0-9\-]+\s*\:/i.test(snippet)) {
- return false;
- }
-
- return snippet.replace(/\$\{.+?\}/g, '').split(':').length == 2;
- }
-
- /**
- * Normalizes abbreviated value to final CSS one
- * @param {String} value
- * @returns {String}
- */
- function normalizeValue(value) {
- if (value.charAt(0) == '-' && !/^\-[\.\d]/.test(value)) {
- value = value.replace(/^\-+/, '');
- }
-
- var ch = value.charAt(0);
- if (ch == '#') {
- return normalizeHexColor(value);
- }
-
- if (ch == '$') {
- return utils.escapeText(value);
- }
-
- return getKeyword(value);
- }
-
- function normalizeHexColor(value) {
- var hex = value.replace(/^#+/, '') || '0';
- if (hex.toLowerCase() == 't') {
- return 'transparent';
- }
-
- var opacity = '';
- hex = hex.replace(/\.(\d+)$/, function(str) {
- opacity = '0' + str;
- return '';
- });
-
- var repeat = utils.repeatString;
- var color = null;
- switch (hex.length) {
- case 1:
- color = repeat(hex, 6);
- break;
- case 2:
- color = repeat(hex, 3);
- break;
- case 3:
- color = hex.charAt(0) + hex.charAt(0) + hex.charAt(1) + hex.charAt(1) + hex.charAt(2) + hex.charAt(2);
- break;
- case 4:
- color = hex + hex.substr(0, 2);
- break;
- case 5:
- color = hex + hex.charAt(0);
- break;
- default:
- color = hex.substr(0, 6);
- }
-
- if (opacity) {
- return toRgba(color, opacity);
- }
-
- // color must be shortened?
- if (prefs.get('css.color.short')) {
- var p = color.split('');
- if (p[0] == p[1] && p[2] == p[3] && p[4] == p[5]) {
- color = p[0] + p[2] + p[4];
- }
- }
-
- // should transform case?
- switch (prefs.get('css.color.case')) {
- case 'upper':
- color = color.toUpperCase();
- break;
- case 'lower':
- color = color.toLowerCase();
- break;
- }
-
- return '#' + color;
- }
-
- /**
- * Transforms HEX color definition into RGBA one
- * @param {String} color HEX color, 6 characters
- * @param {String} opacity Opacity value
- * @return {String}
- */
- function toRgba(color, opacity) {
- var r = parseInt(color.substr(0, 2), 16);
- var g = parseInt(color.substr(2, 2), 16);
- var b = parseInt(color.substr(4, 2), 16);
-
- return 'rgba(' + [r, g, b, opacity].join(', ') + ')';
- }
-
- function getKeyword(name) {
- var aliases = prefs.getDict('css.keywordAliases');
- return name in aliases ? aliases[name] : name;
- }
-
- function getUnit(name) {
- var aliases = prefs.getDict('css.unitAliases');
- return name in aliases ? aliases[name] : name;
- }
-
- function isValidKeyword(keyword) {
- return ~prefs.getArray('css.keywords').indexOf(getKeyword(keyword));
- }
-
- /**
- * Check if passed CSS property support specified vendor prefix
- * @param {String} property
- * @param {String} prefix
- */
- function hasPrefix(property, prefix) {
- var info = vendorPrefixes[prefix];
-
- if (!info)
- info = utils.find(vendorPrefixes, function(data) {
- return data.prefix == prefix;
- });
-
- return info && info.supports(property);
- }
-
- /**
- * Finds available vendor prefixes for given CSS property.
- * Search is performed within Can I Use database and internal
- * property list
- * @param {String} property CSS property name
- * @return {Array} Array of resolved prefixes or null if
- * prefixes are not available for this property at all.
- * Empty array means prefixes are not available for current
- * user-define era
- */
- function findVendorPrefixes(property) {
- var prefixes = ciu.resolvePrefixes(property);
- if (!prefixes) {
- // Can I Use database is disabled or prefixes are not
- // available for this property
- prefixes = [];
- Object.keys(vendorPrefixes).forEach(function(key) {
- if (hasPrefix(property, key)) {
- prefixes.push(vendorPrefixes[key].prefix);
- }
- });
-
- if (!prefixes.length) {
- prefixes = null;
- }
- }
-
- return prefixes;
- }
-
- /**
- * Search for a list of supported prefixes for CSS property. This list
- * is used to generate all-prefixed snippet
- * @param {String} property CSS property name
- * @returns {Array}
- */
- function findInternalPrefixes(property, noAutofill) {
- var result = [];
- var prefixes = findVendorPrefixes(property);
-
- if (prefixes) {
- var prefixMap = {};
- Object.keys(vendorPrefixes).forEach(function(key) {
- prefixMap[vendorPrefixes[key].prefix] = key;
- });
-
- result = prefixes.map(function(prefix) {
- return prefixMap[prefix];
- });
- }
-
- if (!result.length && !noAutofill) {
- // add all non-obsolete prefixes
- Object.keys(vendorPrefixes).forEach(function(prefix) {
- if (!vendorPrefixes[prefix].obsolete) {
- result.push(prefix);
- }
- });
- }
-
- return result;
- }
-
- function addPrefix(name, obj) {
- if (typeof obj === 'string') {
- obj = {prefix: obj};
- }
-
- vendorPrefixes[name] = utils.extend({}, prefixObj, obj);
- }
-
- function getSyntaxPreference(name, syntax) {
- if (syntax) {
- // hacky alias for Stylus dialect
- if (syntax == 'styl') {
- syntax = 'stylus';
- }
-
- var val = prefs.get(syntax + '.' + name);
- if (typeof val !== 'undefined') {
- return val;
- }
- }
-
- return prefs.get('css.' + name);
- }
-
- /**
- * Format CSS property according to current syntax dialect
- * @param {String} property
- * @param {String} syntax
- * @returns {String}
- */
- function formatProperty(property, syntax) {
- var ix = property.indexOf(':');
- property = property.substring(0, ix).replace(/\s+$/, '')
- + getSyntaxPreference('valueSeparator', syntax)
- + utils.trim(property.substring(ix + 1));
-
- return property.replace(/\s*;\s*$/, getSyntaxPreference('propertyEnd', syntax));
- }
-
- /**
- * Transforms snippet value if required. For example, this transformation
- * may add !important declaration to CSS property
- * @param {String} snippet
- * @param {Boolean} isImportant
- * @returns {String}
- */
- function transformSnippet(snippet, isImportant, syntax) {
- if (typeof snippet !== 'string') {
- snippet = snippet.data;
- }
-
- if (!isSingleProperty(snippet)) {
- return snippet;
- }
-
- if (isImportant) {
- if (~snippet.indexOf(';')) {
- snippet = snippet.split(';').join(' !important;');
- } else {
- snippet += ' !important';
- }
- }
-
- return formatProperty(snippet, syntax);
- }
-
- function getProperties(key) {
- var list = prefs.getArray(key);
- var addon = prefs.getArray(key + 'Addon');
- if (addon) {
- addon.forEach(function(prop) {
- if (prop.charAt(0) == '-') {
- list = utils.without(list, prop.substr(1));
- } else {
- if (prop.charAt(0) == '+')
- prop = prop.substr(1);
-
- list.push(prop);
- }
- });
- }
-
- return list;
- }
-
- /**
- * Tries to produce properties with vendor-prefixed value
- * @param {Object} snippetObj Parsed snippet object
- * @return {Array} Array of properties with prefixed values
- */
- function resolvePrefixedValues(snippetObj, isImportant, syntax) {
- var prefixes = [];
- var lookup = {};
-
- var parts = cssEditTree.findParts(snippetObj.value);
- parts.reverse();
- parts.forEach(function(p) {
- var partValue = p.substring(snippetObj.value);
- (findVendorPrefixes(partValue) || []).forEach(function(prefix) {
- if (!lookup[prefix]) {
- lookup[prefix] = snippetObj.value;
- prefixes.push(prefix);
- }
-
- lookup[prefix] = utils.replaceSubstring(lookup[prefix], '-' + prefix + '-' + partValue, p);
- });
- });
-
- return prefixes.map(function(prefix) {
- return transformSnippet(snippetObj.name + ':' + lookup[prefix], isImportant, syntax);
- });
- }
-
-
- // TODO refactor, this looks awkward now
- addPrefix('w', {
- prefix: 'webkit'
- });
- addPrefix('m', {
- prefix: 'moz'
- });
- addPrefix('s', {
- prefix: 'ms'
- });
- addPrefix('o', {
- prefix: 'o'
- });
-
-
- module = module || {};
- module.exports = {
- /**
- * Adds vendor prefix
- * @param {String} name One-character prefix name
- * @param {Object} obj Object describing vendor prefix
- * @memberOf cssResolver
- */
- addPrefix: addPrefix,
-
- /**
- * Check if passed CSS property supports specified vendor prefix
- * @param {String} property
- * @param {String} prefix
- */
- supportsPrefix: hasPrefix,
-
- resolve: function(node, syntax) {
- var cssSyntaxes = prefs.getArray('css.syntaxes');
- if (cssSyntaxes && ~cssSyntaxes.indexOf(syntax) && node.isElement()) {
- return this.expandToSnippet(node.abbreviation, syntax);
- }
-
- return null;
- },
-
- /**
- * Returns prefixed version of passed CSS property, only if this
- * property supports such prefix
- * @param {String} property
- * @param {String} prefix
- * @returns
- */
- prefixed: function(property, prefix) {
- return hasPrefix(property, prefix)
- ? '-' + prefix + '-' + property
- : property;
- },
-
- /**
- * Returns list of all registered vendor prefixes
- * @returns {Array}
- */
- listPrefixes: function() {
- return vendorPrefixes.map(function(obj) {
- return obj.prefix;
- });
- },
-
- /**
- * Returns object describing vendor prefix
- * @param {String} name
- * @returns {Object}
- */
- getPrefix: function(name) {
- return vendorPrefixes[name];
- },
-
- /**
- * Removes prefix object
- * @param {String} name
- */
- removePrefix: function(name) {
- if (name in vendorPrefixes)
- delete vendorPrefixes[name];
- },
-
- /**
- * Extract vendor prefixes from abbreviation
- * @param {String} abbr
- * @returns {Object} Object containing array of prefixes and clean
- * abbreviation name
- */
- extractPrefixes: function(abbr) {
- if (abbr.charAt(0) != '-') {
- return {
- property: abbr,
- prefixes: null
- };
- }
-
- // abbreviation may either contain sequence of one-character prefixes
- // or just dash, meaning that user wants to produce all possible
- // prefixed properties
- var i = 1, il = abbr.length, ch;
- var prefixes = [];
-
- while (i < il) {
- ch = abbr.charAt(i);
- if (ch == '-') {
- // end-sequence character found, stop searching
- i++;
- break;
- }
-
- if (ch in vendorPrefixes) {
- prefixes.push(ch);
- } else {
- // no prefix found, meaning user want to produce all
- // vendor-prefixed properties
- prefixes.length = 0;
- i = 1;
- break;
- }
-
- i++;
- }
-
- // reached end of abbreviation and no property name left
- if (i == il -1) {
- i = 1;
- prefixes.length = 1;
- }
-
- return {
- property: abbr.substring(i),
- prefixes: prefixes.length ? prefixes : 'all'
- };
- },
-
- /**
- * Search for value substring in abbreviation
- * @param {String} abbr
- * @returns {String} Value substring
- */
- findValuesInAbbreviation: function(abbr, syntax) {
- syntax = syntax || 'css';
-
- var i = 0, il = abbr.length, value = '', ch;
- while (i < il) {
- ch = abbr.charAt(i);
- if (isNumeric(ch) || ch == '#' || ch == '$' || (ch == '-' && isNumeric(abbr.charAt(i + 1)))) {
- value = abbr.substring(i);
- break;
- }
-
- i++;
- }
-
- // try to find keywords in abbreviation
- var property = abbr.substring(0, abbr.length - value.length);
- var keywords = [];
- // try to extract some commonly-used properties
- while (~property.indexOf('-') && !resources.findSnippet(syntax, property)) {
- var parts = property.split('-');
- var lastPart = parts.pop();
- if (!isValidKeyword(lastPart)) {
- break;
- }
-
- keywords.unshift(lastPart);
- property = parts.join('-');
- }
-
- return keywords.join('-') + value;
- },
-
- parseValues: function(str) {
- /** @type StringStream */
- var stream = stringStream.create(str);
- var values = [];
- var ch = null;
-
- while ((ch = stream.next())) {
- if (ch == '$') {
- stream.match(/^[^\$]+/, true);
- values.push(stream.current());
- } else if (ch == '#') {
- stream.match(/^t|[0-9a-f]+(\.\d+)?/i, true);
- values.push(stream.current());
- } else if (ch == '-') {
- if (isValidKeyword(utils.last(values)) ||
- ( stream.start && isNumeric(str.charAt(stream.start - 1)) )
- ) {
- stream.start = stream.pos;
- }
-
- stream.match(/^\-?[0-9]*(\.[0-9]+)?[a-z%\.]*/, true);
- values.push(stream.current());
- } else {
- stream.match(/^[0-9]*(\.[0-9]*)?[a-z%]*/, true);
- values.push(stream.current());
- }
-
- stream.start = stream.pos;
- }
-
- return values
- .filter(function(item) {
- return !!item;
- })
- .map(normalizeValue);
- },
-
- /**
- * Extracts values from abbreviation
- * @param {String} abbr
- * @returns {Object} Object containing array of values and clean
- * abbreviation name
- */
- extractValues: function(abbr) {
- // search for value start
- var abbrValues = this.findValuesInAbbreviation(abbr);
- if (!abbrValues) {
- return {
- property: abbr,
- values: null
- };
- }
-
- return {
- property: abbr.substring(0, abbr.length - abbrValues.length).replace(/-$/, ''),
- values: this.parseValues(abbrValues)
- };
- },
-
- /**
- * Normalizes value, defined in abbreviation.
- * @param {String} value
- * @param {String} property
- * @returns {String}
- */
- normalizeValue: function(value, property) {
- property = (property || '').toLowerCase();
- var unitlessProps = prefs.getArray('css.unitlessProperties');
- return value.replace(/^(\-?[0-9\.]+)([a-z]*)$/, function(str, val, unit) {
- if (!unit && (val == '0' || ~unitlessProps.indexOf(property)))
- return val;
-
- if (!unit)
- return val.replace(/\.$/, '') + prefs.get(~val.indexOf('.') ? 'css.floatUnit' : 'css.intUnit');
-
- return val + getUnit(unit);
- });
- },
-
- /**
- * Expands abbreviation into a snippet
- * @param {String} abbr Abbreviation name to expand
- * @param {String} value Abbreviation value
- * @param {String} syntax Currect syntax or dialect. Default is 'css'
- * @returns {Object} Array of CSS properties and values or predefined
- * snippet (string or element)
- */
- expand: function(abbr, value, syntax) {
- syntax = syntax || 'css';
- var autoInsertPrefixes = prefs.get(syntax + '.autoInsertVendorPrefixes');
-
- // check if snippet should be transformed to !important
- var isImportant = /^(.+)\!$/.test(abbr);
- if (isImportant) {
- abbr = RegExp.$1;
- }
-
- // check if we have abbreviated resource
- var snippet = resources.findSnippet(syntax, abbr);
- if (snippet && !autoInsertPrefixes) {
- return transformSnippet(snippet, isImportant, syntax);
- }
-
- // no abbreviated resource, parse abbreviation
- var prefixData = this.extractPrefixes(abbr);
- var valuesData = this.extractValues(prefixData.property);
- var abbrData = utils.extend(prefixData, valuesData);
-
- if (!snippet) {
- snippet = resources.findSnippet(syntax, abbrData.property);
- } else {
- abbrData.values = null;
- }
-
- if (!snippet && prefs.get('css.fuzzySearch')) {
- // let’s try fuzzy search
- snippet = resources.fuzzyFindSnippet(syntax, abbrData.property, parseFloat(prefs.get('css.fuzzySearchMinScore')));
- }
-
- if (!snippet) {
- if (!abbrData.property || abbrData.property.endsWith(':')) {
- return null;
- }
- snippet = abbrData.property + ':' + defaultValue;
- } else if (typeof snippet !== 'string') {
- snippet = snippet.data;
- }
-
- if (!isSingleProperty(snippet)) {
- return snippet;
- }
-
- var snippetObj = this.splitSnippet(snippet);
- var result = [];
- if (!value && abbrData.values) {
- value = abbrData.values.map(function(val) {
- return this.normalizeValue(val, snippetObj.name);
- }, this).join(' ') + ';';
- }
-
- snippetObj.value = value || snippetObj.value;
-
- var prefixes = abbrData.prefixes == 'all' || (!abbrData.prefixes && autoInsertPrefixes)
- ? findInternalPrefixes(snippetObj.name, autoInsertPrefixes && abbrData.prefixes != 'all')
- : abbrData.prefixes;
-
-
- var names = [], propName;
- (prefixes || []).forEach(function(p) {
- if (p in vendorPrefixes) {
- propName = vendorPrefixes[p].transformName(snippetObj.name);
- names.push(propName);
- result.push(transformSnippet(propName + ':' + snippetObj.value,
- isImportant, syntax));
- }
- });
-
- // put the original property
- result.push(transformSnippet(snippetObj.name + ':' + snippetObj.value, isImportant, syntax));
- names.push(snippetObj.name);
-
- result = resolvePrefixedValues(snippetObj, isImportant, syntax).concat(result);
-
- if (prefs.get('css.alignVendor')) {
- var pads = utils.getStringsPads(names);
- result = result.map(function(prop, i) {
- return pads[i] + prop;
- });
- }
-
- return result;
- },
-
- /**
- * Same as expand method but transforms output into
- * Emmet snippet
- * @param {String} abbr
- * @param {String} syntax
- * @returns {String}
- */
- expandToSnippet: function(abbr, syntax) {
- var snippet = this.expand(abbr, null, syntax);
- if (snippet === null) {
- return null;
- }
-
- if (Array.isArray(snippet)) {
- return snippet.join('\n');
- }
-
- if (typeof snippet !== 'string') {
- return snippet.data;
- }
-
- return snippet + '';
- },
-
- /**
- * Split snippet into a CSS property-value pair
- * @param {String} snippet
- */
- splitSnippet: function(snippet) {
- snippet = utils.trim(snippet);
- if (snippet.indexOf(':') == -1) {
- return {
- name: snippet,
- value: defaultValue
- };
- }
-
- var pair = snippet.split(':');
-
- return {
- name: utils.trim(pair.shift()),
- // replace ${0} tabstop to produce valid vendor-prefixed values
- // where possible
- value: utils.trim(pair.join(':')).replace(/^(\$\{0\}|\$0)(\s*;?)$/, '${1}$2')
- };
- },
-
- getSyntaxPreference: getSyntaxPreference,
- transformSnippet: transformSnippet,
- vendorPrefixes: findVendorPrefixes
- };
-
- return module.exports;
-});
-},{"../assets/caniuse":"assets\\caniuse.js","../assets/preferences":"assets\\preferences.js","../assets/resources":"assets\\resources.js","../assets/stringStream":"assets\\stringStream.js","../editTree/css":"editTree\\css.js","../utils/common":"utils\\common.js","../utils/template":"utils\\template.js"}],"resolver\\cssGradient.js":[function(require,module,exports){
-/**
- * 'Expand Abbreviation' handler that parses gradient definition from under
- * cursor and updates CSS rule with vendor-prefixed values.
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var prefs = require('../assets/preferences');
- var resources = require('../assets/resources');
- var utils = require('../utils/common');
- var stringStream = require('../assets/stringStream');
- var cssResolver = require('./css');
- var range = require('../assets/range');
- var cssEditTree = require('../editTree/css');
- var editorUtils = require('../utils/editor');
- var linearGradient = require('./gradient/linear');
-
- var cssSyntaxes = ['css', 'less', 'sass', 'scss', 'stylus', 'styl'];
-
- // XXX define preferences
- prefs.define('css.gradient.prefixes', 'webkit, moz, o',
- 'A comma-separated list of vendor-prefixes for which values should '
- + 'be generated.');
-
- prefs.define('css.gradient.oldWebkit', false,
- 'Generate gradient definition for old Webkit implementations');
-
- prefs.define('css.gradient.omitDefaultDirection', true,
- 'Do not output default direction definition in generated gradients.');
-
- prefs.define('css.gradient.defaultProperty', 'background-image',
- 'When gradient expanded outside CSS value context, it will produce '
- + 'properties with this name.');
-
- prefs.define('css.gradient.fallback', false,
- 'With this option enabled, CSS gradient generator will produce '
- + 'background-color property with gradient first color '
- + 'as fallback for old browsers.');
-
- /**
- * Resolves property name (abbreviation): searches for snippet definition in
- * 'resources' and returns new name of matched property
- */
- function resolvePropertyName(name, syntax) {
- var snippet = resources.findSnippet(syntax, name);
-
- if (!snippet && prefs.get('css.fuzzySearch')) {
- var minScore = parseFloat(prefs.get('css.fuzzySearchMinScore'));
- snippet = resources.fuzzyFindSnippet(syntax, name, minScore);
- }
-
- if (snippet) {
- if (typeof snippet !== 'string') {
- snippet = snippet.data;
- }
-
- return cssResolver.splitSnippet(snippet).name;
- }
- }
-
- /**
- * Returns vendor prefixes for given gradient type
- * @param {String} type Gradient type (currently, 'linear-gradient'
- * is the only supported value)
- * @return {Array}
- */
- function getGradientPrefixes(type) {
- var prefixes = cssResolver.vendorPrefixes(type);
- if (!prefixes) {
- // disabled Can I Use, fallback to property list
- prefixes = prefs.getArray('css.gradient.prefixes');
- }
-
- return prefixes || [];
- }
-
- function getPrefixedNames(type) {
- var prefixes = getGradientPrefixes(type);
- var names = prefixes
- ? prefixes.map(function(p) {
- return '-' + p + '-' + type;
- })
- : [];
-
- names.push(type);
-
- return names;
- }
-
- /**
- * Returns list of CSS properties with gradient
- * @param {Array} gradient List of gradient objects
- * @param {CSSEditElement} property Original CSS property
- * @returns {Array}
- */
- function getPropertiesForGradient(gradients, property) {
- var props = [];
- var propertyName = property.name();
- var omitDir = prefs.get('css.gradient.omitDefaultDirection');
-
- if (prefs.get('css.gradient.fallback') && ~propertyName.toLowerCase().indexOf('background')) {
- props.push({
- name: 'background-color',
- value: '${1:' + gradients[0].gradient.colorStops[0].color + '}'
- });
- }
-
- var value = property.value();
- getGradientPrefixes('linear-gradient').forEach(function(prefix) {
- var name = cssResolver.prefixed(propertyName, prefix);
- if (prefix == 'webkit' && prefs.get('css.gradient.oldWebkit')) {
- try {
- props.push({
- name: name,
- value: insertGradientsIntoCSSValue(gradients, value, {
- prefix: prefix,
- oldWebkit: true,
- omitDefaultDirection: omitDir
- })
- });
- } catch(e) {}
- }
-
- props.push({
- name: name,
- value: insertGradientsIntoCSSValue(gradients, value, {
- prefix: prefix,
- omitDefaultDirection: omitDir
- })
- });
- });
-
- return props.sort(function(a, b) {
- return b.name.length - a.name.length;
- });
- }
-
- /**
- * Replaces old gradient definitions in given CSS property value
- * with new ones, preserving original formatting
- * @param {Array} gradients List of CSS gradients
- * @param {String} value Original CSS value
- * @param {Object} options Options for gradient’s stringify() method
- * @return {String}
- */
- function insertGradientsIntoCSSValue(gradients, value, options) {
- // gradients *should* passed in order they actually appear in CSS property
- // iterate over it in backward direction to preserve gradient locations
- options = options || {};
- gradients = utils.clone(gradients);
- gradients.reverse().forEach(function(item, i) {
- var suffix = !i && options.placeholder ? options.placeholder : '';
- var str = options.oldWebkit ? item.gradient.stringifyOldWebkit(options) : item.gradient.stringify(options);
- value = utils.replaceSubstring(value, str + suffix, item.matchedPart);
- });
-
- return value;
- }
-
- /**
- * Returns list of properties with the same meaning
- * (e.g. vendor-prefixed + original name)
- * @param {String} property CSS property name
- * @return {Array}
- */
- function similarPropertyNames(property) {
- if (typeof property !== 'string') {
- property = property.name();
- }
-
- var similarProps = (cssResolver.vendorPrefixes(property) || []).map(function(prefix) {
- return '-' + prefix + '-' + property;
- });
- similarProps.push(property);
- return similarProps;
- }
-
- /**
- * Pastes gradient definition into CSS rule with correct vendor-prefixes
- * @param {EditElement} property Matched CSS property
- * @param {Array} gradients List of gradients to insert
- */
- function pasteGradient(property, gradients) {
- var rule = property.parent;
- var alignVendor = prefs.get('css.alignVendor');
- var omitDir = prefs.get('css.gradient.omitDefaultDirection');
-
- // we may have aligned gradient definitions: find the smallest value
- // separator
- var sep = property.styleSeparator;
- var before = property.styleBefore;
-
- // first, remove all properties within CSS rule with the same name and
- // gradient definition
- rule.getAll(similarPropertyNames(property)).forEach(function(item) {
- if (item != property && /gradient/i.test(item.value())) {
- if (item.styleSeparator.length < sep.length) {
- sep = item.styleSeparator;
- }
- if (item.styleBefore.length < before.length) {
- before = item.styleBefore;
- }
- rule.remove(item);
- }
- });
-
- if (alignVendor) {
- // update prefix
- if (before != property.styleBefore) {
- var fullRange = property.fullRange();
- rule._updateSource(before, fullRange.start, fullRange.start + property.styleBefore.length);
- property.styleBefore = before;
- }
-
- // update separator value
- if (sep != property.styleSeparator) {
- rule._updateSource(sep, property.nameRange().end, property.valueRange().start);
- property.styleSeparator = sep;
- }
- }
-
- var value = property.value();
-
- // create list of properties to insert
- var propsToInsert = getPropertiesForGradient(gradients, property);
-
- // align prefixed values
- if (alignVendor) {
- var names = [], values = [];
- propsToInsert.forEach(function(item) {
- names.push(item.name);
- values.push(item.value);
- });
- values.push(property.value());
- names.push(property.name());
-
- var valuePads = utils.getStringsPads(values.map(function(v) {
- return v.substring(0, v.indexOf('('));
- }));
-
- var namePads = utils.getStringsPads(names);
- property.name(namePads[namePads.length - 1] + property.name());
-
- propsToInsert.forEach(function(prop, i) {
- prop.name = namePads[i] + prop.name;
- prop.value = valuePads[i] + prop.value;
- });
-
- property.value(valuePads[valuePads.length - 1] + property.value());
- }
-
- // put vendor-prefixed definitions before current rule
- propsToInsert.forEach(function(prop) {
- rule.add(prop.name, prop.value, rule.indexOf(property));
- });
-
- // put vanilla-clean gradient definition into current rule
- property.value(insertGradientsIntoCSSValue(gradients, value, {
- placeholder: '${2}',
- omitDefaultDirection: omitDir
- }));
- }
-
- /**
- * Validates caret position relatively to located gradients
- * in CSS rule. In other words, it checks if it’s safe to
- * expand gradients for current caret position or not.
- *
- * See issue https://github.com/sergeche/emmet-sublime/issues/411
- *
- * @param {Array} gradients List of parsed gradients
- * @param {Number} caretPos Current caret position
- * @param {String} syntax Current document syntax
- * @return {Boolean}
- */
- function isValidCaretPosition(gradients, caretPos, syntax) {
- syntax = syntax || 'css';
- if (syntax == 'css' || syntax == 'less' || syntax == 'scss') {
- return true;
- }
-
- var offset = gradients.property.valueRange(true).start;
- var parts = gradients.gradients;
-
- // in case of preprocessors where properties are separated with
- // newlines, make sure there’s no gradient definition past
- // current caret position.
- for (var i = parts.length - 1; i >= 0; i--) {
- if (parts[i].matchedPart.start + offset >= caretPos) {
- return false;
- }
- }
-
- return true;
- }
-
- module = module || {};
- return module.exports = {
- /**
- * Search for gradient definitions inside CSS property value
- * @returns {Array} Array of matched gradients
- */
- findGradients: function(cssProp) {
- var value = cssProp.value();
- var gradients = [];
- var that = this;
- cssProp.valueParts().forEach(function(part) {
- var partValue = part.substring(value);
- if (linearGradient.isLinearGradient(partValue)) {
- var gradient = linearGradient.parse(partValue);
- if (gradient) {
- gradients.push({
- gradient: gradient,
- matchedPart: part
- });
- }
- }
- });
-
- return gradients.length ? gradients : null;
- },
-
- /**
- * Returns list of gradients found in CSS property
- * of given CSS code in specified (caret) position
- * @param {String} css CSS code snippet
- * @param {Number} pos Character index where to start searching for CSS property
- * @return {Array}
- */
- gradientsFromCSSProperty: function(css, pos) {
- var cssProp = cssEditTree.propertyFromPosition(css, pos);
- if (cssProp) {
- var grd = this.findGradients(cssProp);
- if (grd) {
- return {
- property: cssProp,
- gradients: grd
- };
- }
- }
-
- return null;
- },
-
- /**
- * Handler for “Expand Abbreviation” action
- * @param {IEmmetEditor} editor
- * @param {String} syntax
- * @param {String} profile
- * return {Boolean}
- */
- expandAbbreviationHandler: function(editor, syntax, profile) {
- var info = editorUtils.outputInfo(editor, syntax, profile);
- if (!~cssSyntaxes.indexOf(info.syntax)) {
- return false;
- }
-
- // let's see if we are expanding gradient definition
- var caret = editor.getCaretPos();
- var content = info.content;
- var gradients = this.gradientsFromCSSProperty(content, caret);
- if (gradients) {
- if (!isValidCaretPosition(gradients, caret, info.syntax)) {
- return false;
- }
-
- var cssProperty = gradients.property;
- var cssRule = cssProperty.parent;
- var ruleStart = cssRule.options.offset || 0;
- var ruleEnd = ruleStart + cssRule.toString().length;
-
- // Handle special case:
- // user wrote gradient definition between existing CSS
- // properties and did not finished it with semicolon.
- // In this case, we have semicolon right after gradient
- // definition and re-parse rule again
- if (/[\n\r]/.test(cssProperty.value())) {
- // insert semicolon at the end of gradient definition
- var insertPos = cssProperty.valueRange(true).start + utils.last(gradients.gradients).matchedPart.end;
- content = utils.replaceSubstring(content, ';', insertPos);
-
- var _gradients = this.gradientsFromCSSProperty(content, caret);
- if (_gradients) {
- gradients = _gradients;
- cssProperty = gradients.property;
- cssRule = cssProperty.parent;
- }
- }
-
- // make sure current property has terminating semicolon
- cssProperty.end(';');
-
- // resolve CSS property name
- var resolvedName = resolvePropertyName(cssProperty.name(), syntax);
- if (resolvedName) {
- cssProperty.name(resolvedName);
- }
-
- pasteGradient(cssProperty, gradients.gradients);
- editor.replaceContent(cssRule.toString(), ruleStart, ruleEnd, true);
- return true;
- }
-
- return this.expandGradientOutsideValue(editor, syntax);
- },
-
- /**
- * Tries to expand gradient outside CSS value
- * @param {IEmmetEditor} editor
- * @param {String} syntax
- */
- expandGradientOutsideValue: function(editor, syntax) {
- var propertyName = prefs.get('css.gradient.defaultProperty');
- var omitDir = prefs.get('css.gradient.omitDefaultDirection');
-
- if (!propertyName) {
- return false;
- }
-
- // assuming that gradient definition is written on new line,
- // do a simplified parsing
- var content = String(editor.getContent());
- /** @type Range */
- var lineRange = range.create(editor.getCurrentLineRange());
-
- // get line content and adjust range with padding
- var line = lineRange.substring(content)
- .replace(/^\s+/, function(pad) {
- lineRange.start += pad.length;
- return '';
- })
- .replace(/\s+$/, function(pad) {
- lineRange.end -= pad.length;
- return '';
- });
-
- // trick parser: make it think that we’re parsing actual CSS property
- var fakeCSS = 'a{' + propertyName + ': ' + line + ';}';
- var gradients = this.gradientsFromCSSProperty(fakeCSS, fakeCSS.length - 2);
- if (gradients) {
- var props = getPropertiesForGradient(gradients.gradients, gradients.property);
- props.push({
- name: gradients.property.name(),
- value: insertGradientsIntoCSSValue(gradients.gradients, gradients.property.value(), {
- placeholder: '${2}',
- omitDefaultDirection: omitDir
- })
- });
-
- var sep = cssResolver.getSyntaxPreference('valueSeparator', syntax);
- var end = cssResolver.getSyntaxPreference('propertyEnd', syntax);
-
- if (prefs.get('css.alignVendor')) {
- var pads = utils.getStringsPads(props.map(function(prop) {
- return prop.value.substring(0, prop.value.indexOf('('));
- }));
- props.forEach(function(prop, i) {
- prop.value = pads[i] + prop.value;
- });
- }
-
- props = props.map(function(item) {
- return item.name + sep + item.value + end;
- });
-
- editor.replaceContent(props.join('\n'), lineRange.start, lineRange.end);
- return true;
- }
-
- return false;
- },
-
- /**
- * Handler for “Reflect CSS Value“ action
- * @param {String} property
- */
- reflectValueHandler: function(property) {
- var omitDir = prefs.get('css.gradient.omitDefaultDirection');
- var gradients = this.findGradients(property);
- if (!gradients) {
- return false;
- }
-
- var that = this;
- var value = property.value();
-
- // reflect value for properties with the same name
- property.parent.getAll(similarPropertyNames(property)).forEach(function(prop) {
- if (prop === property) {
- return;
- }
-
- // make sure current property contains gradient definition,
- // otherwise – skip it
- var localGradients = that.findGradients(prop);
- if (localGradients) {
- // detect vendor prefix for current property
- var localValue = prop.value();
- var dfn = localGradients[0].matchedPart.substring(localValue);
- var prefix = '';
- if (/^\s*\-([a-z]+)\-/.test(dfn)) {
- prefix = RegExp.$1;
- }
-
- prop.value(insertGradientsIntoCSSValue(gradients, value, {
- prefix: prefix,
- omitDefaultDirection: omitDir
- }));
- }
- });
-
- return true;
- }
- };
-});
-},{"../assets/preferences":"assets\\preferences.js","../assets/range":"assets\\range.js","../assets/resources":"assets\\resources.js","../assets/stringStream":"assets\\stringStream.js","../editTree/css":"editTree\\css.js","../utils/common":"utils\\common.js","../utils/editor":"utils\\editor.js","./css":"resolver\\css.js","./gradient/linear":"resolver\\gradient\\linear.js"}],"resolver\\gradient\\linear.js":[function(require,module,exports){
-/**
- * CSS linear gradient definition
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var stringStream = require('../../assets/stringStream');
- var utils = require('../../utils/common');
-
- // all directions are expressed in “new style” degrees
- var directions = {
- 'bottom': 0,
- 'bottom left': 45,
- 'left': 90,
- 'top left': 135,
- 'top': 180,
- 'top right': 225,
- 'right': 270,
- 'bottom right': 315,
-
- 'to top': 0,
- 'to top right': 45,
- 'to right': 90,
- 'to bottom right': 135,
- 'to bottom': 180,
- 'to bottom left': 225,
- 'to left': 270,
- 'to top left': 315
- };
-
- var defaultDirections = ['top', 'to bottom', '0deg'];
-
-
- var reLinearGradient = /^\s*(\-[a-z]+\-)?(lg|linear\-gradient)\s*\(/i;
- var reDeg = /(\d+)deg/i;
- var reKeyword = /top|bottom|left|right/i;
-
- function LinearGradient(dfn) {
- this.colorStops = [];
- this.direction = 180;
-
- // extract tokens
- var stream = stringStream.create(utils.trim(dfn));
- var ch, cur;
- while ((ch = stream.next())) {
- if (stream.peek() == ',') {
- // Is it a first entry? Check if it’s a direction
- cur = stream.current();
-
- if (!this.colorStops.length && (reDeg.test(cur) || reKeyword.test(cur))) {
- this.direction = resolveDirection(cur);
- } else {
- this.addColorStop(cur);
- }
-
- stream.next();
- stream.eatSpace();
- stream.start = stream.pos;
- } else if (ch == '(') { // color definition, like 'rgb(0,0,0)'
- stream.skipTo(')');
- }
- }
-
- // add last token
- this.addColorStop(stream.current());
- }
-
- LinearGradient.prototype = {
- type: 'linear-gradient',
- addColorStop: function(color, ix) {
- color = normalizeSpace(color || '');
- if (!color) {
- return;
- }
-
- color = this.parseColorStop(color);
-
- if (typeof ix === 'undefined') {
- this.colorStops.push(color);
- } else {
- this.colorStops.splice(ix, 0, color);
- }
- },
-
- /**
- * Parses color stop definition
- * @param {String} colorStop
- * @returns {Object}
- */
- parseColorStop: function(colorStop) {
- colorStop = normalizeSpace(colorStop);
-
- // find color declaration
- // first, try complex color declaration, like rgb(0,0,0)
- var color = null;
- colorStop = colorStop.replace(/^(\w+\(.+?\))\s*/, function(str, c) {
- color = c;
- return '';
- });
-
- if (!color) {
- // try simple declaration, like yellow, #fco, #ffffff, etc.
- var parts = colorStop.split(' ');
- color = parts[0];
- colorStop = parts[1] || '';
- }
-
- var result = {
- color: color
- };
-
- if (colorStop) {
- // there's position in color stop definition
- colorStop.replace(/^(\-?[\d\.]+)([a-z%]+)?$/, function(str, pos, unit) {
- result.position = pos;
- if (~pos.indexOf('.')) {
- unit = '';
- } else if (!unit) {
- unit = '%';
- }
-
- if (unit) {
- result.unit = unit;
- }
- });
- }
-
- return result;
- },
-
- stringify: function(options) {
- options = options || {};
- var fn = 'linear-gradient';
- if (options.prefix) {
- fn = '-' + options.prefix + '-' + fn;
- }
-
- // transform color-stops
- var parts = this.colorStops.map(function(cs) {
- var pos = cs.position ? ' ' + cs.position + (cs.unit || '') : '';
- return cs.color + pos;
- });
-
- var dir = stringifyDirection(this.direction, !!options.prefix);
- if (!options.omitDefaultDirection || !~defaultDirections.indexOf(dir)) {
- parts.unshift(dir);
- }
-
- return fn + '(' + parts.join(', ') + ')';
- },
-
- stringifyOldWebkit: function() {
- var colorStops = this.colorStops.map(function(item) {
- return utils.clone(item);
- });
-
- // normalize color-stops position
- colorStops.forEach(function(cs) {
- if (!('position' in cs)) // implied position
- return;
-
- if (~cs.position.indexOf('.') || cs.unit == '%') {
- cs.position = parseFloat(cs.position) / (cs.unit == '%' ? 100 : 1);
- } else {
- throw "Can't convert color stop '" + (cs.position + (cs.unit || '')) + "'";
- }
- });
-
- this._fillImpliedPositions(colorStops);
-
- // transform color-stops into string representation
- colorStops = colorStops.map(function(cs, i) {
- if (!cs.position && !i) {
- return 'from(' + cs.color + ')';
- }
-
- if (cs.position == 1 && i == colorStops.length - 1) {
- return 'to(' + cs.color + ')';
- }
-
- return 'color-stop(' + (cs.position.toFixed(2).replace(/\.?0+$/, '')) + ', ' + cs.color + ')';
- });
-
- return '-webkit-gradient(linear, '
- + oldWebkitDirection((this.direction + 180) % 360)
- + ', '
- + colorStops.join(', ')
- + ')';
- },
-
- /**
- * Fills-out implied positions in color-stops. This function is useful for
- * old Webkit gradient definitions
- */
- _fillImpliedPositions: function(colorStops) {
- var from = 0;
-
- colorStops.forEach(function(cs, i) {
- // make sure that first and last positions are defined
- if (!i) {
- return cs.position = cs.position || 0;
- }
-
- if (i == colorStops.length - 1 && !('position' in cs)) {
- cs.position = 1;
- }
-
- if ('position' in cs) {
- var start = colorStops[from].position || 0;
- var step = (cs.position - start) / (i - from);
- colorStops.slice(from, i).forEach(function(cs2, j) {
- cs2.position = start + step * j;
- });
-
- from = i;
- }
- });
- },
-
- valueOf: function() {
- return this.stringify();
- }
- };
-
- function normalizeSpace(str) {
- return utils.trim(str).replace(/\s+/g, ' ');
- }
-
- /**
- * Resolves textual direction to degrees
- * @param {String} dir Direction to resolve
- * @return {Number}
- */
- function resolveDirection(dir) {
- if (typeof dir == 'number') {
- return dir;
- }
-
- dir = normalizeSpace(dir).toLowerCase();
- if (reDeg.test(dir)) {
- return +RegExp.$1;
- }
-
- var prefix = /^to\s/.test(dir) ? 'to ' : '';
- var left = ~dir.indexOf('left') && 'left';
- var right = ~dir.indexOf('right') && 'right';
- var top = ~dir.indexOf('top') && 'top';
- var bottom = ~dir.indexOf('bottom') && 'bottom';
-
- var key = normalizeSpace(prefix + (top || bottom || '') + ' ' + (left || right || ''));
- return directions[key] || 0;
- }
-
- /**
- * Tries to find keyword for given direction, expressed in degrees
- * @param {Number} dir Direction (degrees)
- * @param {Boolean} oldStyle Use old style keywords (e.g. "top" instead of "to bottom")
- * @return {String} Keyword or Ndeg expression
- */
- function stringifyDirection(dir, oldStyle) {
- var reNewStyle = /^to\s/;
- var keys = Object.keys(directions).filter(function(k) {
- var hasPrefix = reNewStyle.test(k);
- return oldStyle ? !hasPrefix : hasPrefix;
- });
-
- for (var i = 0; i < keys.length; i++) {
- if (directions[keys[i]] == dir) {
- return keys[i];
- }
- }
-
- if (oldStyle) {
- dir = (dir + 270) % 360;
- }
-
- return dir + 'deg';
- }
-
- /**
- * Creates direction definition for old Webkit gradients
- * @param {String} direction
- * @returns {String}
- */
- function oldWebkitDirection(dir) {
- dir = stringifyDirection(dir, true);
-
- if(reDeg.test(dir)) {
- throw "The direction is an angle that can’t be converted.";
- }
-
- var v = function(pos) {
- return ~dir.indexOf(pos) ? '100%' : '0';
- };
-
- return v('left') + ' ' + v('top') + ', ' + v('right') + ' ' + v('bottom');
- }
-
- return {
- /**
- * Parses gradient definition into an object.
- * This object can be used to transform gradient into various
- * forms
- * @param {String} gradient Gradient definition
- * @return {LinearGradient}
- */
- parse: function(gradient) {
- // cut out all redundant data
- if (this.isLinearGradient(gradient)) {
- gradient = gradient.replace(/^\s*[\-a-z]+\s*\(|\)\s*$/ig, '');
- } else {
- throw 'Invalid linear gradient definition:\n' + gradient;
- }
-
- return new LinearGradient(gradient);
- },
-
- /**
- * Check if given string can be parsed as linear gradient
- * @param {String} str
- * @return {Boolean}
- */
- isLinearGradient: function(str) {
- return reLinearGradient.test(str);
- },
-
- resolveDirection: resolveDirection,
- stringifyDirection: stringifyDirection
- };
-});
-},{"../../assets/stringStream":"assets\\stringStream.js","../../utils/common":"utils\\common.js"}],"resolver\\tagName.js":[function(require,module,exports){
-/**
- * Module for resolving tag names: returns best matched tag name for child
- * element based on passed parent's tag name. Also provides utility function
- * for element type detection (inline, block-level, empty)
- */
-if (typeof module === 'object' && typeof define !== 'function') {
- var define = function (factory) {
- module.exports = factory(require, exports, module);
- };
-}
-
-define(function(require, exports, module) {
- var utils = require('../utils/common');
-
- var elementTypes = {
-// empty: 'area,base,basefont,br,col,frame,hr,img,input,isindex,link,meta,param,embed,keygen,command'.split(','),
- empty: [],
- blockLevel: 'address,applet,blockquote,button,center,dd,del,dir,div,dl,dt,fieldset,form,frameset,hr,iframe,ins,isindex,li,link,map,menu,noframes,noscript,object,ol,p,pre,script,table,tbody,td,tfoot,th,thead,tr,ul,h1,h2,h3,h4,h5,h6'.split(','),
- inlineLevel: 'a,abbr,acronym,applet,b,basefont,bdo,big,br,button,cite,code,del,dfn,em,font,i,iframe,img,input,ins,kbd,label,map,object,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var'.split(',')
- };
-
- var elementMap = {
- 'p': 'span',
- 'ul': 'li',
- 'ol': 'li',
- 'table': 'tr',
- 'tr': 'td',
- 'tbody': 'tr',
- 'thead': 'tr',
- 'tfoot': 'tr',
- 'colgroup': 'col',
- 'select': 'option',
- 'optgroup': 'option',
- 'audio': 'source',
- 'video': 'source',
- 'object': 'param',
- 'map': 'area'
- };
-
- return {
- /**
- * Returns best matched child element name for passed parent's
- * tag name
- * @param {String} name
- * @returns {String}
- * @memberOf tagName
- */
- resolve: function(name) {
- name = (name || '').toLowerCase();
-
- if (name in elementMap)
- return this.getMapping(name);
-
- if (this.isInlineLevel(name))
- return 'span';
-
- return 'div';
- },
-
- /**
- * Returns mapped child element name for passed parent's name
- * @param {String} name
- * @returns {String}
- */
- getMapping: function(name) {
- return elementMap[name.toLowerCase()];
- },
-
- /**
- * Check if passed element name belongs to inline-level element
- * @param {String} name
- * @returns {Boolean}
- */
- isInlineLevel: function(name) {
- return this.isTypeOf(name, 'inlineLevel');
- },
-
- /**
- * Check if passed element belongs to block-level element.
- * For better matching of unknown elements (for XML, for example),
- * you should use !this.isInlineLevel(name)
- * @returns {Boolean}
- */
- isBlockLevel: function(name) {
- return this.isTypeOf(name, 'blockLevel');
- },
-
- /**
- * Check if passed element is void (i.e. should not have closing tag).
- * @returns {Boolean}
- */
- isEmptyElement: function(name) {
- return this.isTypeOf(name, 'empty');
- },
-
- /**
- * Generic function for testing if element name belongs to specified
- * elements collection
- * @param {String} name Element name
- * @param {String} type Collection name
- * @returns {Boolean}
- */
- isTypeOf: function(name, type) {
- return ~elementTypes[type].indexOf(name);
- },
-
- /**
- * Adds new parent–child mapping
- * @param {String} parent
- * @param {String} child
- */
- addMapping: function(parent, child) {
- elementMap[parent] = child;
- },
-
- /**
- * Removes parent-child mapping
- */
- removeMapping: function(parent) {
- if (parent in elementMap)
- delete elementMap[parent];
- },
-
- /**
- * Adds new element into collection
- * @param {String} name Element name
- * @param {String} collection Collection name
- */
- addElementToCollection: function(name, collection) {
- if (!elementTypes[collection])
- elementTypes[collection] = [];
-
- var col = this.getCollection(collection);
- if (!~col.indexOf(name)) {
- col.push(name);
- }
- },
-
- /**
- * Removes element name from specified collection
- * @param {String} name Element name
- * @param {String} collection Collection name
- * @returns
- */
- removeElementFromCollection: function(name, collection) {
- if (collection in elementTypes) {
- elementTypes[collection] = utils.without(this.getCollection(collection), name);
- }
- },
-
- /**
- * Returns elements name collection
- * @param {String} name Collection name
- * @returns {Array}
- */
- getCollection: function(name) {
- return elementTypes[name];
- }
- };
-});
-},{"../utils/common":"utils\\common.js"}],"snippets.json":[function(require,module,exports){
-module.exports={
- "variables": {
- "lang": "en",
- "locale": "en-US",
- "charset": "UTF-8",
- "indentation": "\t",
- "newline": "\n"
- },
-
- "css": {
- "filters": "css",
- "profile": "css",
- "snippets": {
- "@i": "@import url(|);",
- "@import": "@import url(|);",
- "@m": "@media ${1:screen} {\n\t|\n}",
- "@media": "@media ${1:screen} {\n\t|\n}",
- "@f": "@font-face {\n\tfont-family:|;\n\tsrc:url(|);\n}",
- "@f+": "@font-face {\n\tfont-family: '${1:FontName}';\n\tsrc: url('${2:FileName}.eot');\n\tsrc: url('${2:FileName}.eot?#iefix') format('embedded-opentype'),\n\t\t url('${2:FileName}.woff') format('woff'),\n\t\t url('${2:FileName}.ttf') format('truetype'),\n\t\t url('${2:FileName}.svg#${1:FontName}') format('svg');\n\tfont-style: ${3:normal};\n\tfont-weight: ${4:normal};\n}",
-
- "@kf": "@-webkit-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-o-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@-moz-keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}\n@keyframes ${1:identifier} {\n\t${2:from} { ${3} }${6}\n\t${4:to} { ${5} }\n}",
-
- "anim": "animation:|;",
- "anim-": "animation:${1:name} ${2:duration} ${3:timing-function} ${4:delay} ${5:iteration-count} ${6:direction} ${7:fill-mode};",
- "animdel": "animation-delay:${1:time};",
-
- "animdir": "animation-direction:${1:normal};",
- "animdir:n": "animation-direction:normal;",
- "animdir:r": "animation-direction:reverse;",
- "animdir:a": "animation-direction:alternate;",
- "animdir:ar": "animation-direction:alternate-reverse;",
-
- "animdur": "animation-duration:${1:0}s;",
-
- "animfm": "animation-fill-mode:${1:both};",
- "animfm:f": "animation-fill-mode:forwards;",
- "animfm:b": "animation-fill-mode:backwards;",
- "animfm:bt": "animation-fill-mode:both;",
- "animfm:bh": "animation-fill-mode:both;",
-
- "animic": "animation-iteration-count:${1:1};",
- "animic:i": "animation-iteration-count:infinite;",
-
- "animn": "animation-name:${1:none};",
-
- "animps": "animation-play-state:${1:running};",
- "animps:p": "animation-play-state:paused;",
- "animps:r": "animation-play-state:running;",
-
- "animtf": "animation-timing-function:${1:linear};",
- "animtf:e": "animation-timing-function:ease;",
- "animtf:ei": "animation-timing-function:ease-in;",
- "animtf:eo": "animation-timing-function:ease-out;",
- "animtf:eio": "animation-timing-function:ease-in-out;",
- "animtf:l": "animation-timing-function:linear;",
- "animtf:cb": "animation-timing-function:cubic-bezier(${1:0.1}, ${2:0.7}, ${3:1.0}, ${3:0.1});",
-
- "ap": "appearance:${none};",
-
- "!": "!important",
- "pos": "position:${1:relative};",
- "pos:s": "position:static;",
- "pos:a": "position:absolute;",
- "pos:r": "position:relative;",
- "pos:f": "position:fixed;",
- "t": "top:|;",
- "t:a": "top:auto;",
- "r": "right:|;",
- "r:a": "right:auto;",
- "b": "bottom:|;",
- "b:a": "bottom:auto;",
- "l": "left:|;",
- "l:a": "left:auto;",
- "z": "z-index:|;",
- "z:a": "z-index:auto;",
- "fl": "float:${1:left};",
- "fl:n": "float:none;",
- "fl:l": "float:left;",
- "fl:r": "float:right;",
- "cl": "clear:${1:both};",
- "cl:n": "clear:none;",
- "cl:l": "clear:left;",
- "cl:r": "clear:right;",
- "cl:b": "clear:both;",
-
- "colm": "columns:|;",
- "colmc": "column-count:|;",
- "colmf": "column-fill:|;",
- "colmg": "column-gap:|;",
- "colmr": "column-rule:|;",
- "colmrc": "column-rule-color:|;",
- "colmrs": "column-rule-style:|;",
- "colmrw": "column-rule-width:|;",
- "colms": "column-span:|;",
- "colmw": "column-width:|;",
-
- "d": "display:${1:block};",
- "d:n": "display:none;",
- "d:b": "display:block;",
- "d:f": "display:flex;",
- "d:if": "display:inline-flex;",
- "d:i": "display:inline;",
- "d:ib": "display:inline-block;",
- "d:ib+": "display: inline-block;\n*display: inline;\n*zoom: 1;",
- "d:li": "display:list-item;",
- "d:ri": "display:run-in;",
- "d:cp": "display:compact;",
- "d:tb": "display:table;",
- "d:itb": "display:inline-table;",
- "d:tbcp": "display:table-caption;",
- "d:tbcl": "display:table-column;",
- "d:tbclg": "display:table-column-group;",
- "d:tbhg": "display:table-header-group;",
- "d:tbfg": "display:table-footer-group;",
- "d:tbr": "display:table-row;",
- "d:tbrg": "display:table-row-group;",
- "d:tbc": "display:table-cell;",
- "d:rb": "display:ruby;",
- "d:rbb": "display:ruby-base;",
- "d:rbbg": "display:ruby-base-group;",
- "d:rbt": "display:ruby-text;",
- "d:rbtg": "display:ruby-text-group;",
- "v": "visibility:${1:hidden};",
- "v:v": "visibility:visible;",
- "v:h": "visibility:hidden;",
- "v:c": "visibility:collapse;",
- "ov": "overflow:${1:hidden};",
- "ov:v": "overflow:visible;",
- "ov:h": "overflow:hidden;",
- "ov:s": "overflow:scroll;",
- "ov:a": "overflow:auto;",
- "ovx": "overflow-x:${1:hidden};",
- "ovx:v": "overflow-x:visible;",
- "ovx:h": "overflow-x:hidden;",
- "ovx:s": "overflow-x:scroll;",
- "ovx:a": "overflow-x:auto;",
- "ovy": "overflow-y:${1:hidden};",
- "ovy:v": "overflow-y:visible;",
- "ovy:h": "overflow-y:hidden;",
- "ovy:s": "overflow-y:scroll;",
- "ovy:a": "overflow-y:auto;",
- "ovs": "overflow-style:${1:scrollbar};",
- "ovs:a": "overflow-style:auto;",
- "ovs:s": "overflow-style:scrollbar;",
- "ovs:p": "overflow-style:panner;",
- "ovs:m": "overflow-style:move;",
- "ovs:mq": "overflow-style:marquee;",
- "zoo": "zoom:1;",
- "zm": "zoom:1;",
- "cp": "clip:|;",
- "cp:a": "clip:auto;",
- "cp:r": "clip:rect(${1:top} ${2:right} ${3:bottom} ${4:left});",
- "bxz": "box-sizing:${1:border-box};",
- "bxz:cb": "box-sizing:content-box;",
- "bxz:bb": "box-sizing:border-box;",
- "bxsh": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:color};",
- "bxsh:r": "box-shadow:${1:inset }${2:hoff} ${3:voff} ${4:blur} ${5:spread }rgb(${6:0}, ${7:0}, ${8:0});",
- "bxsh:ra": "box-shadow:${1:inset }${2:h} ${3:v} ${4:blur} ${5:spread }rgba(${6:0}, ${7:0}, ${8:0}, .${9:5});",
- "bxsh:n": "box-shadow:none;",
- "m": "margin:|;",
- "m:a": "margin:auto;",
- "mt": "margin-top:|;",
- "mt:a": "margin-top:auto;",
- "mr": "margin-right:|;",
- "mr:a": "margin-right:auto;",
- "mb": "margin-bottom:|;",
- "mb:a": "margin-bottom:auto;",
- "ml": "margin-left:|;",
- "ml:a": "margin-left:auto;",
- "p": "padding:|;",
- "pt": "padding-top:|;",
- "pr": "padding-right:|;",
- "pb": "padding-bottom:|;",
- "pl": "padding-left:|;",
- "w": "width:|;",
- "w:a": "width:auto;",
- "h": "height:|;",
- "h:a": "height:auto;",
- "maw": "max-width:|;",
- "maw:n": "max-width:none;",
- "mah": "max-height:|;",
- "mah:n": "max-height:none;",
- "miw": "min-width:|;",
- "mih": "min-height:|;",
- "mar": "max-resolution:${1:res};",
- "mir": "min-resolution:${1:res};",
- "ori": "orientation:|;",
- "ori:l": "orientation:landscape;",
- "ori:p": "orientation:portrait;",
- "ol": "outline:|;",
- "ol:n": "outline:none;",
- "olo": "outline-offset:|;",
- "olw": "outline-width:|;",
- "olw:tn": "outline-width:thin;",
- "olw:m": "outline-width:medium;",
- "olw:tc": "outline-width:thick;",
- "ols": "outline-style:|;",
- "ols:n": "outline-style:none;",
- "ols:dt": "outline-style:dotted;",
- "ols:ds": "outline-style:dashed;",
- "ols:s": "outline-style:solid;",
- "ols:db": "outline-style:double;",
- "ols:g": "outline-style:groove;",
- "ols:r": "outline-style:ridge;",
- "ols:i": "outline-style:inset;",
- "ols:o": "outline-style:outset;",
- "olc": "outline-color:#${1:000};",
- "olc:i": "outline-color:invert;",
- "bfv": "backface-visibility:|;",
- "bfv:h": "backface-visibility:hidden;",
- "bfv:v": "backface-visibility:visible;",
- "bd": "border:|;",
- "bd+": "border:${1:1px} ${2:solid} ${3:#000};",
- "bd:n": "border:none;",
- "bdbk": "border-break:${1:close};",
- "bdbk:c": "border-break:close;",
- "bdcl": "border-collapse:|;",
- "bdcl:c": "border-collapse:collapse;",
- "bdcl:s": "border-collapse:separate;",
- "bdc": "border-color:#${1:000};",
- "bdc:t": "border-color:transparent;",
- "bdi": "border-image:url(|);",
- "bdi:n": "border-image:none;",
- "bdti": "border-top-image:url(|);",
- "bdti:n": "border-top-image:none;",
- "bdri": "border-right-image:url(|);",
- "bdri:n": "border-right-image:none;",
- "bdbi": "border-bottom-image:url(|);",
- "bdbi:n": "border-bottom-image:none;",
- "bdli": "border-left-image:url(|);",
- "bdli:n": "border-left-image:none;",
- "bdci": "border-corner-image:url(|);",
- "bdci:n": "border-corner-image:none;",
- "bdci:c": "border-corner-image:continue;",
- "bdtli": "border-top-left-image:url(|);",
- "bdtli:n": "border-top-left-image:none;",
- "bdtli:c": "border-top-left-image:continue;",
- "bdtri": "border-top-right-image:url(|);",
- "bdtri:n": "border-top-right-image:none;",
- "bdtri:c": "border-top-right-image:continue;",
- "bdbri": "border-bottom-right-image:url(|);",
- "bdbri:n": "border-bottom-right-image:none;",
- "bdbri:c": "border-bottom-right-image:continue;",
- "bdbli": "border-bottom-left-image:url(|);",
- "bdbli:n": "border-bottom-left-image:none;",
- "bdbli:c": "border-bottom-left-image:continue;",
- "bdf": "border-fit:${1:repeat};",
- "bdf:c": "border-fit:clip;",
- "bdf:r": "border-fit:repeat;",
- "bdf:sc": "border-fit:scale;",
- "bdf:st": "border-fit:stretch;",
- "bdf:ow": "border-fit:overwrite;",
- "bdf:of": "border-fit:overflow;",
- "bdf:sp": "border-fit:space;",
- "bdlen": "border-length:|;",
- "bdlen:a": "border-length:auto;",
- "bdsp": "border-spacing:|;",
- "bds": "border-style:|;",
- "bds:n": "border-style:none;",
- "bds:h": "border-style:hidden;",
- "bds:dt": "border-style:dotted;",
- "bds:ds": "border-style:dashed;",
- "bds:s": "border-style:solid;",
- "bds:db": "border-style:double;",
- "bds:dtds": "border-style:dot-dash;",
- "bds:dtdtds": "border-style:dot-dot-dash;",
- "bds:w": "border-style:wave;",
- "bds:g": "border-style:groove;",
- "bds:r": "border-style:ridge;",
- "bds:i": "border-style:inset;",
- "bds:o": "border-style:outset;",
- "bdw": "border-width:|;",
- "bdtw": "border-top-width:|;",
- "bdrw": "border-right-width:|;",
- "bdbw": "border-bottom-width:|;",
- "bdlw": "border-left-width:|;",
- "bdt": "border-top:|;",
- "bt": "border-top:|;",
- "bdt+": "border-top:${1:1px} ${2:solid} ${3:#000};",
- "bdt:n": "border-top:none;",
- "bdts": "border-top-style:|;",
- "bdts:n": "border-top-style:none;",
- "bdtc": "border-top-color:#${1:000};",
- "bdtc:t": "border-top-color:transparent;",
- "bdr": "border-right:|;",
- "br": "border-right:|;",
- "bdr+": "border-right:${1:1px} ${2:solid} ${3:#000};",
- "bdr:n": "border-right:none;",
- "bdrst": "border-right-style:|;",
- "bdrst:n": "border-right-style:none;",
- "bdrc": "border-right-color:#${1:000};",
- "bdrc:t": "border-right-color:transparent;",
- "bdb": "border-bottom:|;",
- "bb": "border-bottom:|;",
- "bdb+": "border-bottom:${1:1px} ${2:solid} ${3:#000};",
- "bdb:n": "border-bottom:none;",
- "bdbs": "border-bottom-style:|;",
- "bdbs:n": "border-bottom-style:none;",
- "bdbc": "border-bottom-color:#${1:000};",
- "bdbc:t": "border-bottom-color:transparent;",
- "bdl": "border-left:|;",
- "bl": "border-left:|;",
- "bdl+": "border-left:${1:1px} ${2:solid} ${3:#000};",
- "bdl:n": "border-left:none;",
- "bdls": "border-left-style:|;",
- "bdls:n": "border-left-style:none;",
- "bdlc": "border-left-color:#${1:000};",
- "bdlc:t": "border-left-color:transparent;",
- "bdrs": "border-radius:|;",
- "bdtrrs": "border-top-right-radius:|;",
- "bdtlrs": "border-top-left-radius:|;",
- "bdbrrs": "border-bottom-right-radius:|;",
- "bdblrs": "border-bottom-left-radius:|;",
- "bg": "background:#${1:000};",
- "bg+": "background:${1:#fff} url(${2}) ${3:0} ${4:0} ${5:no-repeat};",
- "bg:n": "background:none;",
- "bg:ie": "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src='${1:x}.png',sizingMethod='${2:crop}');",
- "bgc": "background-color:#${1:fff};",
- "bgc:t": "background-color:transparent;",
- "bgi": "background-image:url(|);",
- "bgi:n": "background-image:none;",
- "bgr": "background-repeat:|;",
- "bgr:n": "background-repeat:no-repeat;",
- "bgr:x": "background-repeat:repeat-x;",
- "bgr:y": "background-repeat:repeat-y;",
- "bgr:sp": "background-repeat:space;",
- "bgr:rd": "background-repeat:round;",
- "bga": "background-attachment:|;",
- "bga:f": "background-attachment:fixed;",
- "bga:s": "background-attachment:scroll;",
- "bgp": "background-position:${1:0} ${2:0};",
- "bgpx": "background-position-x:|;",
- "bgpy": "background-position-y:|;",
- "bgbk": "background-break:|;",
- "bgbk:bb": "background-break:bounding-box;",
- "bgbk:eb": "background-break:each-box;",
- "bgbk:c": "background-break:continuous;",
- "bgcp": "background-clip:${1:padding-box};",
- "bgcp:bb": "background-clip:border-box;",
- "bgcp:pb": "background-clip:padding-box;",
- "bgcp:cb": "background-clip:content-box;",
- "bgcp:nc": "background-clip:no-clip;",
- "bgo": "background-origin:|;",
- "bgo:pb": "background-origin:padding-box;",
- "bgo:bb": "background-origin:border-box;",
- "bgo:cb": "background-origin:content-box;",
- "bgsz": "background-size:|;",
- "bgsz:a": "background-size:auto;",
- "bgsz:ct": "background-size:contain;",
- "bgsz:cv": "background-size:cover;",
- "c": "color:#${1:000};",
- "c:r": "color:rgb(${1:0}, ${2:0}, ${3:0});",
- "c:ra": "color:rgba(${1:0}, ${2:0}, ${3:0}, .${4:5});",
- "cm": "/* |${child} */",
- "cnt": "content:'|';",
- "cnt:n": "content:normal;",
- "cnt:oq": "content:open-quote;",
- "cnt:noq": "content:no-open-quote;",
- "cnt:cq": "content:close-quote;",
- "cnt:ncq": "content:no-close-quote;",
- "cnt:a": "content:attr(|);",
- "cnt:c": "content:counter(|);",
- "cnt:cs": "content:counters(|);",
-
- "tbl": "table-layout:|;",
- "tbl:a": "table-layout:auto;",
- "tbl:f": "table-layout:fixed;",
- "cps": "caption-side:|;",
- "cps:t": "caption-side:top;",
- "cps:b": "caption-side:bottom;",
- "ec": "empty-cells:|;",
- "ec:s": "empty-cells:show;",
- "ec:h": "empty-cells:hide;",
- "lis": "list-style:|;",
- "lis:n": "list-style:none;",
- "lisp": "list-style-position:|;",
- "lisp:i": "list-style-position:inside;",
- "lisp:o": "list-style-position:outside;",
- "list": "list-style-type:|;",
- "list:n": "list-style-type:none;",
- "list:d": "list-style-type:disc;",
- "list:c": "list-style-type:circle;",
- "list:s": "list-style-type:square;",
- "list:dc": "list-style-type:decimal;",
- "list:dclz": "list-style-type:decimal-leading-zero;",
- "list:lr": "list-style-type:lower-roman;",
- "list:ur": "list-style-type:upper-roman;",
- "lisi": "list-style-image:|;",
- "lisi:n": "list-style-image:none;",
- "q": "quotes:|;",
- "q:n": "quotes:none;",
- "q:ru": "quotes:'\\00AB' '\\00BB' '\\201E' '\\201C';",
- "q:en": "quotes:'\\201C' '\\201D' '\\2018' '\\2019';",
- "ct": "content:|;",
- "ct:n": "content:normal;",
- "ct:oq": "content:open-quote;",
- "ct:noq": "content:no-open-quote;",
- "ct:cq": "content:close-quote;",
- "ct:ncq": "content:no-close-quote;",
- "ct:a": "content:attr(|);",
- "ct:c": "content:counter(|);",
- "ct:cs": "content:counters(|);",
- "coi": "counter-increment:|;",
- "cor": "counter-reset:|;",
- "va": "vertical-align:${1:top};",
- "va:sup": "vertical-align:super;",
- "va:t": "vertical-align:top;",
- "va:tt": "vertical-align:text-top;",
- "va:m": "vertical-align:middle;",
- "va:bl": "vertical-align:baseline;",
- "va:b": "vertical-align:bottom;",
- "va:tb": "vertical-align:text-bottom;",
- "va:sub": "vertical-align:sub;",
- "ta": "text-align:${1:left};",
- "ta:l": "text-align:left;",
- "ta:c": "text-align:center;",
- "ta:r": "text-align:right;",
- "ta:j": "text-align:justify;",
- "ta-lst": "text-align-last:|;",
- "tal:a": "text-align-last:auto;",
- "tal:l": "text-align-last:left;",
- "tal:c": "text-align-last:center;",
- "tal:r": "text-align-last:right;",
- "td": "text-decoration:${1:none};",
- "td:n": "text-decoration:none;",
- "td:u": "text-decoration:underline;",
- "td:o": "text-decoration:overline;",
- "td:l": "text-decoration:line-through;",
- "te": "text-emphasis:|;",
- "te:n": "text-emphasis:none;",
- "te:ac": "text-emphasis:accent;",
- "te:dt": "text-emphasis:dot;",
- "te:c": "text-emphasis:circle;",
- "te:ds": "text-emphasis:disc;",
- "te:b": "text-emphasis:before;",
- "te:a": "text-emphasis:after;",
- "th": "text-height:|;",
- "th:a": "text-height:auto;",
- "th:f": "text-height:font-size;",
- "th:t": "text-height:text-size;",
- "th:m": "text-height:max-size;",
- "ti": "text-indent:|;",
- "ti:-": "text-indent:-9999px;",
- "tj": "text-justify:|;",
- "tj:a": "text-justify:auto;",
- "tj:iw": "text-justify:inter-word;",
- "tj:ii": "text-justify:inter-ideograph;",
- "tj:ic": "text-justify:inter-cluster;",
- "tj:d": "text-justify:distribute;",
- "tj:k": "text-justify:kashida;",
- "tj:t": "text-justify:tibetan;",
- "tov": "text-overflow:${ellipsis};",
- "tov:e": "text-overflow:ellipsis;",
- "tov:c": "text-overflow:clip;",
- "to": "text-outline:|;",
- "to+": "text-outline:${1:0} ${2:0} ${3:#000};",
- "to:n": "text-outline:none;",
- "tr": "text-replace:|;",
- "tr:n": "text-replace:none;",
- "tt": "text-transform:${1:uppercase};",
- "tt:n": "text-transform:none;",
- "tt:c": "text-transform:capitalize;",
- "tt:u": "text-transform:uppercase;",
- "tt:l": "text-transform:lowercase;",
- "tw": "text-wrap:|;",
- "tw:n": "text-wrap:normal;",
- "tw:no": "text-wrap:none;",
- "tw:u": "text-wrap:unrestricted;",
- "tw:s": "text-wrap:suppress;",
- "tsh": "text-shadow:${1:hoff} ${2:voff} ${3:blur} ${4:#000};",
- "tsh:r": "text-shadow:${1:h} ${2:v} ${3:blur} rgb(${4:0}, ${5:0}, ${6:0});",
- "tsh:ra": "text-shadow:${1:h} ${2:v} ${3:blur} rgba(${4:0}, ${5:0}, ${6:0}, .${7:5});",
- "tsh+": "text-shadow:${1:0} ${2:0} ${3:0} ${4:#000};",
- "tsh:n": "text-shadow:none;",
- "trf": "transform:|;",
- "trf:skx": "transform: skewX(${1:angle});",
- "trf:sky": "transform: skewY(${1:angle});",
- "trf:sc": "transform: scale(${1:x}, ${2:y});",
- "trf:scx": "transform: scaleX(${1:x});",
- "trf:scy": "transform: scaleY(${1:y});",
- "trf:scz": "transform: scaleZ(${1:z});",
- "trf:sc3": "transform: scale3d(${1:x}, ${2:y}, ${3:z});",
- "trf:r": "transform: rotate(${1:angle});",
- "trf:rx": "transform: rotateX(${1:angle});",
- "trf:ry": "transform: rotateY(${1:angle});",
- "trf:rz": "transform: rotateZ(${1:angle});",
- "trf:t": "transform: translate(${1:x}, ${2:y});",
- "trf:tx": "transform: translateX(${1:x});",
- "trf:ty": "transform: translateY(${1:y});",
- "trf:tz": "transform: translateZ(${1:z});",
- "trf:t3": "transform: translate3d(${1:tx}, ${2:ty}, ${3:tz});",
- "trfo": "transform-origin:|;",
- "trfs": "transform-style:${1:preserve-3d};",
- "trs": "transition:${1:prop} ${2:time};",
- "trsde": "transition-delay:${1:time};",
- "trsdu": "transition-duration:${1:time};",
- "trsp": "transition-property:${1:prop};",
- "trstf": "transition-timing-function:${1:tfunc};",
- "lh": "line-height:|;",
- "whs": "white-space:|;",
- "whs:n": "white-space:normal;",
- "whs:p": "white-space:pre;",
- "whs:nw": "white-space:nowrap;",
- "whs:pw": "white-space:pre-wrap;",
- "whs:pl": "white-space:pre-line;",
- "whsc": "white-space-collapse:|;",
- "whsc:n": "white-space-collapse:normal;",
- "whsc:k": "white-space-collapse:keep-all;",
- "whsc:l": "white-space-collapse:loose;",
- "whsc:bs": "white-space-collapse:break-strict;",
- "whsc:ba": "white-space-collapse:break-all;",
- "wob": "word-break:|;",
- "wob:n": "word-break:normal;",
- "wob:k": "word-break:keep-all;",
- "wob:ba": "word-break:break-all;",
- "wos": "word-spacing:|;",
- "wow": "word-wrap:|;",
- "wow:nm": "word-wrap:normal;",
- "wow:n": "word-wrap:none;",
- "wow:u": "word-wrap:unrestricted;",
- "wow:s": "word-wrap:suppress;",
- "wow:b": "word-wrap:break-word;",
- "wm": "writing-mode:${1:lr-tb};",
- "wm:lrt": "writing-mode:lr-tb;",
- "wm:lrb": "writing-mode:lr-bt;",
- "wm:rlt": "writing-mode:rl-tb;",
- "wm:rlb": "writing-mode:rl-bt;",
- "wm:tbr": "writing-mode:tb-rl;",
- "wm:tbl": "writing-mode:tb-lr;",
- "wm:btl": "writing-mode:bt-lr;",
- "wm:btr": "writing-mode:bt-rl;",
- "lts": "letter-spacing:|;",
- "lts-n": "letter-spacing:normal;",
- "f": "font:|;",
- "f+": "font:${1:1em} ${2:Arial,sans-serif};",
- "fw": "font-weight:|;",
- "fw:n": "font-weight:normal;",
- "fw:b": "font-weight:bold;",
- "fw:br": "font-weight:bolder;",
- "fw:lr": "font-weight:lighter;",
- "fs": "font-style:${italic};",
- "fs:n": "font-style:normal;",
- "fs:i": "font-style:italic;",
- "fs:o": "font-style:oblique;",
- "fv": "font-variant:|;",
- "fv:n": "font-variant:normal;",
- "fv:sc": "font-variant:small-caps;",
- "fz": "font-size:|;",
- "fza": "font-size-adjust:|;",
- "fza:n": "font-size-adjust:none;",
- "ff": "font-family:|;",
- "ff:s": "font-family:serif;",
- "ff:ss": "font-family:sans-serif;",
- "ff:c": "font-family:cursive;",
- "ff:f": "font-family:fantasy;",
- "ff:m": "font-family:monospace;",
- "ff:a": "font-family: Arial, \"Helvetica Neue\", Helvetica, sans-serif;",
- "ff:t": "font-family: \"Times New Roman\", Times, Baskerville, Georgia, serif;",
- "ff:v": "font-family: Verdana, Geneva, sans-serif;",
- "fef": "font-effect:|;",
- "fef:n": "font-effect:none;",
- "fef:eg": "font-effect:engrave;",
- "fef:eb": "font-effect:emboss;",
- "fef:o": "font-effect:outline;",
- "fem": "font-emphasize:|;",
- "femp": "font-emphasize-position:|;",
- "femp:b": "font-emphasize-position:before;",
- "femp:a": "font-emphasize-position:after;",
- "fems": "font-emphasize-style:|;",
- "fems:n": "font-emphasize-style:none;",
- "fems:ac": "font-emphasize-style:accent;",
- "fems:dt": "font-emphasize-style:dot;",
- "fems:c": "font-emphasize-style:circle;",
- "fems:ds": "font-emphasize-style:disc;",
- "fsm": "font-smooth:|;",
- "fsm:a": "font-smooth:auto;",
- "fsm:n": "font-smooth:never;",
- "fsm:aw": "font-smooth:always;",
- "fst": "font-stretch:|;",
- "fst:n": "font-stretch:normal;",
- "fst:uc": "font-stretch:ultra-condensed;",
- "fst:ec": "font-stretch:extra-condensed;",
- "fst:c": "font-stretch:condensed;",
- "fst:sc": "font-stretch:semi-condensed;",
- "fst:se": "font-stretch:semi-expanded;",
- "fst:e": "font-stretch:expanded;",
- "fst:ee": "font-stretch:extra-expanded;",
- "fst:ue": "font-stretch:ultra-expanded;",
- "op": "opacity:|;",
- "op+": "opacity: $1;\nfilter: alpha(opacity=$2);",
- "op:ie": "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity=100);",
- "op:ms": "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=100)';",
- "rsz": "resize:|;",
- "rsz:n": "resize:none;",
- "rsz:b": "resize:both;",
- "rsz:h": "resize:horizontal;",
- "rsz:v": "resize:vertical;",
- "cur": "cursor:${pointer};",
- "cur:a": "cursor:auto;",
- "cur:d": "cursor:default;",
- "cur:c": "cursor:crosshair;",
- "cur:ha": "cursor:hand;",
- "cur:he": "cursor:help;",
- "cur:m": "cursor:move;",
- "cur:p": "cursor:pointer;",
- "cur:t": "cursor:text;",
- "fxd": "flex-direction:|;",
- "fxd:r": "flex-direction:row;",
- "fxd:rr": "flex-direction:row-reverse;",
- "fxd:c": "flex-direction:column;",
- "fxd:cr": "flex-direction:column-reverse;",
- "fxw": "flex-wrap: |;",
- "fxw:n": "flex-wrap:nowrap;",
- "fxw:w": "flex-wrap:wrap;",
- "fxw:wr": "flex-wrap:wrap-reverse;",
- "fxf": "flex-flow:|;",
- "jc": "justify-content:|;",
- "jc:fs": "justify-content:flex-start;",
- "jc:fe": "justify-content:flex-end;",
- "jc:c": "justify-content:center;",
- "jc:sb": "justify-content:space-between;",
- "jc:sa": "justify-content:space-around;",
- "ai": "align-items:|;",
- "ai:fs": "align-items:flex-start;",
- "ai:fe": "align-items:flex-end;",
- "ai:c": "align-items:center;",
- "ai:b": "align-items:baseline;",
- "ai:s": "align-items:stretch;",
- "ac": "align-content:|;",
- "ac:fs": "align-content:flex-start;",
- "ac:fe": "align-content:flex-end;",
- "ac:c": "align-content:center;",
- "ac:sb": "align-content:space-between;",
- "ac:sa": "align-content:space-around;",
- "ac:s": "align-content:stretch;",
- "ord": "order:|;",
- "fxg": "flex-grow:|;",
- "fxsh": "flex-shrink:|;",
- "fxb": "flex-basis:|;",
- "fx": "flex:|;",
- "as": "align-self:|;",
- "as:a": "align-self:auto;",
- "as:fs": "align-self:flex-start;",
- "as:fe": "align-self:flex-end;",
- "as:c": "align-self:center;",
- "as:b": "align-self:baseline;",
- "as:s": "align-self:stretch;",
- "pgbb": "page-break-before:|;",
- "pgbb:au": "page-break-before:auto;",
- "pgbb:al": "page-break-before:always;",
- "pgbb:l": "page-break-before:left;",
- "pgbb:r": "page-break-before:right;",
- "pgbi": "page-break-inside:|;",
- "pgbi:au": "page-break-inside:auto;",
- "pgbi:av": "page-break-inside:avoid;",
- "pgba": "page-break-after:|;",
- "pgba:au": "page-break-after:auto;",
- "pgba:al": "page-break-after:always;",
- "pgba:l": "page-break-after:left;",
- "pgba:r": "page-break-after:right;",
- "orp": "orphans:|;",
- "us": "user-select:${none};",
- "wid": "widows:|;",
- "wfsm": "-webkit-font-smoothing:${antialiased};",
- "wfsm:a": "-webkit-font-smoothing:antialiased;",
- "wfsm:s": "-webkit-font-smoothing:subpixel-antialiased;",
- "wfsm:sa": "-webkit-font-smoothing:subpixel-antialiased;",
- "wfsm:n": "-webkit-font-smoothing:none;"
- }
- },
-
- "html": {
- "filters": "html",
- "profile": "html",
- "snippets": {
- "!!!": "",
- "!!!4t": "",
- "!!!4s": "",
- "!!!xt": "",
- "!!!xs": "",
- "!!!xxs": "",
-
- "c": "",
- "cc:ie6": "",
- "cc:ie": "",
- "cc:noie": "\n\t${child}|\n"
- },
-
- "abbreviations": {
- "!": "html:5",
- "a": "",
- "a:link": " ",
- "a:mail": " ",
- "abbr": "",
- "acr|acronym": "",
- "base": " ",
- "basefont": " ",
- "br": " ",
- "frame": " ",
- "hr": " ",
- "bdo": "",
- "bdo:r": "",
- "bdo:l": "",
- "col": " ",
- "link": " ",
- "link:css": " ",
- "link:print": " ",
- "link:favicon": " ",
- "link:touch": " ",
- "link:rss": " ",
- "link:atom": " ",
- "link:im|link:import": " ",
- "meta": " ",
- "meta:utf": " ",
- "meta:win": " ",
- "meta:edge": " ",
- "meta:vp": " ",
- "meta:compat": " ",
- "meta:redirect": " ",
- "style": "" +
- "\n\t\n\t" +
- "\n\t" +
- htmlEditor.getValue() +
- "\n\t
-
-
-
-