Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(56)

Side by Side Diff: Source/devtools/front_end/bindings/SASSSourceMapping.js

Issue 1307063005: DevTools: edit SASS through SourceMaps. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: improvements Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2012 Google Inc. All rights reserved. 2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are 5 * modification, are permitted provided that the following conditions are
6 * met: 6 * met:
7 * 7 *
8 * * Redistributions of source code must retain the above copyright 8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above 10 * * Redistributions in binary form must reproduce the above
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
45 this._networkProject = networkProject; 45 this._networkProject = networkProject;
46 this._addingRevisionCounter = 0; 46 this._addingRevisionCounter = 0;
47 this._reset(); 47 this._reset();
48 WebInspector.fileManager.addEventListener(WebInspector.FileManager.EventType s.SavedURL, this._fileSaveFinished, this); 48 WebInspector.fileManager.addEventListener(WebInspector.FileManager.EventType s.SavedURL, this._fileSaveFinished, this);
49 WebInspector.moduleSetting("cssSourceMapsEnabled").addChangeListener(this._t oggleSourceMapSupport, this); 49 WebInspector.moduleSetting("cssSourceMapsEnabled").addChangeListener(this._t oggleSourceMapSupport, this);
50 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheet Changed, this._styleSheetChanged, this); 50 this._cssModel.addEventListener(WebInspector.CSSStyleModel.Events.StyleSheet Changed, this._styleSheetChanged, this);
51 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeA dded, this._uiSourceCodeAdded, this); 51 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeA dded, this._uiSourceCodeAdded, this);
52 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeC ontentCommitted, this._uiSourceCodeContentCommitted, this); 52 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeC ontentCommitted, this._uiSourceCodeContentCommitted, this);
53 this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemove d, this._reset, this); 53 this._workspace.addEventListener(WebInspector.Workspace.Events.ProjectRemove d, this._reset, this);
54 this._networkMapping = networkMapping; 54 this._networkMapping = networkMapping;
55
56 this._editor = new WebInspector.SASSSourceMapping.Editor(workspace, networkM apping, cssModel, this);
55 } 57 }
56 58
57 WebInspector.SASSSourceMapping.prototype = { 59 WebInspector.SASSSourceMapping.prototype = {
58 /** 60 /**
59 * @param {!WebInspector.Event} event 61 * @param {!WebInspector.Event} event
60 */ 62 */
61 _styleSheetChanged: function(event) 63 _styleSheetChanged: function(event)
62 { 64 {
63 var id = /** @type {!CSSAgent.StyleSheetId} */ (event.data.styleSheetId) ; 65 var id = /** @type {!CSSAgent.StyleSheetId} */ (event.data.styleSheetId) ;
64 if (this._addingRevisionCounter) { 66 if (this._addingRevisionCounter) {
65 --this._addingRevisionCounter; 67 --this._addingRevisionCounter;
66 return; 68 return;
67 } 69 }
70 return;
68 var header = this._cssModel.styleSheetHeaderForId(id); 71 var header = this._cssModel.styleSheetHeaderForId(id);
69 if (!header) 72 if (!header)
70 return; 73 return;
71 74
72 this.removeHeader(header); 75 this.removeHeader(header);
73 }, 76 },
74 77
75 /** 78 /**
76 * @param {!WebInspector.Event} event 79 * @param {!WebInspector.Event} event
77 */ 80 */
(...skipping 566 matching lines...) Expand 10 before | Expand all | Expand 10 after
644 this._addingRevisionCounter = 0; 647 this._addingRevisionCounter = 0;
645 this._completeSourceMapURLForCSSURL = {}; 648 this._completeSourceMapURLForCSSURL = {};
646 this._cssURLsForSASSURL = {}; 649 this._cssURLsForSASSURL = {};
647 /** @type {!Object.<string, !Array.<function(?WebInspector.SourceMap)>>} */ 650 /** @type {!Object.<string, !Array.<function(?WebInspector.SourceMap)>>} */
648 this._pendingSourceMapLoadingCallbacks = {}; 651 this._pendingSourceMapLoadingCallbacks = {};
649 /** @type {!Object.<string, !{deadlineMs: number, dataByURL: !Object.<st ring, !{timer: number, previousPoll: number}>}>} */ 652 /** @type {!Object.<string, !{deadlineMs: number, dataByURL: !Object.<st ring, !{timer: number, previousPoll: number}>}>} */
650 this._pollDataForSASSURL = {}; 653 this._pollDataForSASSURL = {};
651 /** @type {!Object.<string, !WebInspector.SourceMap>} */ 654 /** @type {!Object.<string, !WebInspector.SourceMap>} */
652 this._sourceMapByURL = {}; 655 this._sourceMapByURL = {};
653 this._sourceMapByStyleSheetURL = {}; 656 this._sourceMapByStyleSheetURL = {};
657 },
658
659 _sourceMapForCSSURL: function(cssURL)
660 {
661 var sassURL = this._completeSourceMapURLForCSSURL[cssURL];
662 if (!sassURL)
663 return null;
664 return this._sourceMapByURL[sassURL] || null;
654 } 665 }
655 } 666 }
667
668 WebInspector.SASSSourceMapping.Editor = function(workspace, networkMapping, cssM odel, sassSourceMapping)
669 {
670 this._workspace = workspace;
671 this._networkMapping = networkMapping;
672 this._cssModel = cssModel;
673 this._sassSourceMapping = sassSourceMapping;
674
675 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeA dded, this._uiSourceCodeAddedToWorkspace, this);
676 this._workspace.addEventListener(WebInspector.Workspace.Events.UISourceCodeR emoved, this._uiSourceCodeRemoved, this);
677
678 this._contents = new Map();
679 this._changedURLs = new Set();
680 this._throttler = new WebInspector.Throttler(0);
681 }
682
683 WebInspector.SASSSourceMapping.Editor.prototype = {
684 _uiSourceCodeRemoved: function(event)
685 {
686 event.data.removeEventListener(WebInspector.UISourceCode.Events.WorkingC opyCommitted, this._sourceCodeCommitted, this);
687 },
688
689 _uiSourceCodeAddedToWorkspace: function(event)
690 {
691 var uiSourceCode = event.data;
692 var url = uiSourceCode.originURL();
693 if (!this._cssModel.styleSheetIdsForURL(url).length)
694 return;
695 uiSourceCode.addEventListener(WebInspector.UISourceCode.Events.WorkingCo pyCommitted, this._sourceCodeCommitted, this);
696 uiSourceCode.requestContentPromise().then(setContent.bind(this));
697
698 function setContent(text)
699 {
700 this._contents.set(url, text);
701 }
702 },
703
704 _killMappingForURL: function(cssURL)
705 {
706 var ids = this._cssModel.styleSheetIdsForURL(cssURL);
707 for (var id of ids) {
708 var header = this._cssModel.styleSheetHeaderForId(id);
709 this._sassSourceMapping.removeHeader(header);
710 }
711 },
712
713 _sourceCodeCommitted: function(event)
714 {
715 if (this._muteSourceCodeCommitted)
716 return;
717
718 var sourceURL = this._networkMapping.networkURL(event.target);
719 this._changedURLs.add(sourceURL);
720 this._throttler.schedule(this._processChangedSourceCodes.bind(this));
721 },
722
723 _processChangedSourceCodes: function()
724 {
725 console.log("React!");
726 //FIXME: handle all changes.
727 var cssSourceURL = this._changedURLs.valuesArray()[0];
728 this._changedURLs.clear();
729
730 var uiSourceCode = this._networkMapping.uiSourceCodeForURL(cssSourceURL, this._cssModel.target());
731 var historyLength = uiSourceCode.history.length;
732 var oldCSSContent = this._contents.get(cssSourceURL);
733 var newCSSContent = uiSourceCode.history[historyLength - 1].content;
734
735 var sourceMap = this._sassSourceMapping._sourceMapForCSSURL(cssSourceURL );
736 if (!sourceMap)
737 return Promise.resolve();
738 var edits = WebInspector.SourceMapEditor.computeEdits(cssSourceURL, oldC SSContent, newCSSContent);
739 edits.sort(sequentialOrder);
740 // New sourcemap which maps to content.
741 var newSourceMap = sourceMap.clone();
742 for (var i = edits.length - 1; i >= 0; --i)
743 newSourceMap.compiledRangeEdited(edits[i].oldRange, edits[i].newRang e());
744
745 var parser = new WebInspector.CSSParser();
746
747 var oldCSSStruct, newCSSStruct;
748
749 var parsePromise = parser.parsePromise(oldCSSContent)
750 .then(function(struct) { oldCSSStruct = struct; return parser.parseP romise(newCSSContent);})
751 .then(function(struct) { newCSSStruct = struct; parser.dispose(); })
752 .then(onCSSStructs);
753
754 var urlsToRequest = new Set();
755 for (var i = 0; i < edits.length; ++i) {
756 var edit = edits[i];
757 urlsToRequest.add(edit.sourceURL);
758 var mapping = sourceMap.findEntry(edit.oldRange.startLine, edit.oldR ange.startColumn);
759 urlsToRequest.add(mapping.sourceURL);
760 }
761
762 var sources = new Map();
763 var sourcePromises = [];
764 for (var url of urlsToRequest) {
765 var uiSourceCode = this._networkMapping.uiSourceCodeForURL(url, this ._cssModel.target());
766 var promise = uiSourceCode.requestContentPromise().then(setSource.bi nd(null, sources, url));
767 sourcePromises.push(promise);
768 }
769
770 return Promise.all([parsePromise, Promise.all(sourcePromises)]).spread(d oEdits.bind(this))
771 .catch(killMapping.bind(this, cssSourceURL));
772
773 function setSource(sources, sourceURL, content)
774 {
775 if (typeof content !== "string")
776 throw new Error("Failed to fetch content of " + sourceURL);
777 sources.set(sourceURL, content);
778 }
779
780 function onCSSStructs()
781 {
782 return WebInspector.SASSSourceMapping.diffCSSStructs(oldCSSStruct, n ewCSSStruct);
783 }
784
785 function doEdits(structuralDiff)
786 {
787 function mapCSStoSASS(cssLine, cssColumn, sassEdit, useEnd)
788 {
789 var sassLineNumber = useEnd ? sassEdit.newRange().endLine : sass Edit.newRange().startLine;
790 var sassColumnNumber = useEnd ? sassEdit.newRange().endColumn : sassEdit.newRange().startColumn;
791 var mapping = new WebInspector.SourceMap.Entry(cssLine, cssColum n, sassEdit.sourceURL, sassLineNumber, sassColumnNumber);
792 ensureMappings.set(sassEdit, mapping);
793 }
794
795 if (this._changedURLs.size > 0)
796 return;
797 var structureMapping = new WebInspector.SASSStructureMapping(newCSSS truct, sources);
798
799 var edits = [];
800 var ensureMappings = new Map();
801 for (var i = 0; i < structuralDiff.length; ++i) {
802 //FIXME: handle other types of edits.
803 var diff = structuralDiff[i];
804 if (diff.type === "ValueChanged") {
805 var cssProperty = diff.property;
806 var sassValue = structureMapping.cssPropertyValueToSASS(WebI nspector.TextRange.fromObject(cssProperty.valueRange), newSourceMap);
807 var sassContent = sources.get(sassValue.url);
808 var sassEdit = new WebInspector.SourceMapEdit(sassValue.url, sassValue.range, sassValue.range.extract(sassContent), " " + cssProperty.value. trim());
809 edits.push(sassEdit);
810 mapCSStoSASS(cssProperty.valueRange.startLine, cssProperty.v alueRange.startColumn, sassEdit, false);
811
812 var backEdits = structureMapping.sassPropertyValueToCSS(sass Value.url, sassValue.range, newSourceMap);
813 if (backEdits.length === 1)
814 continue;
815 for (var j = 0; j < backEdits.length; ++j) {
816 var backEditProperty = backEdits[j];
817 if (backEditProperty === cssProperty)
818 continue;
819 var oldRange = WebInspector.TextRange.fromObject(backEdi tProperty.valueRange);
820 var oldText = oldRange.extract(newCSSContent);
821 var cssEdit = new WebInspector.SourceMapEdit(cssSourceUR L, oldRange, oldText, sassEdit.newText);
822 edits.push(cssEdit);
823 var mapping = new WebInspector.SourceMap.Entry(oldRange. startLine, oldRange.startColumn, sassValue.url, sassValue.range.startLine, sassV alue.range.startColumn);
824 ensureMappings.set(cssEdit, mapping);
825 }
826 } else if (diff.type === "PropertyAdded") {
827 var cssProperty = diff.property;
828 if (diff.after) {
829 var afterCSSProperty = diff.after;
830 var afterSASSProperty = structureMapping.cssPropertyToSA SS(afterCSSProperty.range, newSourceMap);
831 var url = afterSASSProperty.url;
832 var sassContent = sources.get(url);
833 var oldRange = WebInspector.TextRange.createFromLocation (afterSASSProperty.range.endLine, afterSASSProperty.range.endColumn);
834 var indent = (new WebInspector.TextRange(afterSASSProper ty.range.startLine, 0, afterSASSProperty.range.startLine, afterSASSProperty.rang e.startColumn)).extract(sassContent);
835 if (!/^\s+$/.test(indent)) indent = "";
836
837 // Split property addition into chunks to preserve mappi ngs.
838 var newText = String.sprintf("\n%s", indent);
839 var edit1 = new WebInspector.SourceMapEdit(url, oldRange , "", newText);
840 mapCSStoSASS(cssProperty.range.startLine, cssProperty.ra nge.startColumn, edit1, true);
841
842 var newText = String.sprintf("%s:", cssProperty.name.tri m());
843 var edit2 = new WebInspector.SourceMapEdit(url, oldRange , "", newText);
844 mapCSStoSASS(cssProperty.valueRange.startLine, cssProper ty.valueRange.startColumn, edit2, true);
845
846 var newText = String.sprintf(" %s;", cssProperty.value.t rim());
847 var edit3 = new WebInspector.SourceMapEdit(url, oldRange , "", newText);
848 mapCSStoSASS(cssProperty.range.endLine, cssProperty.rang e.endColumn, edit3, true);
849
850 edits.push(edit3, edit2, edit1);
851 } else if (diff.before) {
852 var beforeCSSProperty = diff.before;
853 var beforeSASSProperty = structureMapping.cssPropertyToS ASS(beforeCSSProperty.range, newSourceMap);
854 var url = beforeSASSProperty.url;
855 var sassContent = sources.get(url);
856 var oldRange = WebInspector.TextRange.createFromLocation (beforeSASSProperty.range.startLine, beforeSASSProperty.range.startColumn);
857 var indent = (new WebInspector.TextRange(beforeSASSPrope rty.range.startLine, 0, beforeSASSProperty.range.startLine, beforeSASSProperty.r ange.startColumn)).extract(sassContent);
858 if (!/^\s+$/.test(indent)) indent = "";
859
860 // Split property addition into chunks to preserve mappi ngs.
861 var newText = String.sprintf("%s:", cssProperty.name.tri m());
862 var edit1 = new WebInspector.SourceMapEdit(url, oldRange , "", newText);
863 mapCSStoSASS(cssProperty.range.startLine, cssProperty.ra nge.startColumn, edit1);
864
865 var newText = String.sprintf(" %s;", cssProperty.value.t rim());
866 var edit2 = new WebInspector.SourceMapEdit(url, oldRange , "", newText);
867 mapCSStoSASS(cssProperty.valueRange.startLine, cssProper ty.valueRange.startColumn, edit2);
868
869 var newText = String.sprintf("\n%s", indent);
870 var edit3 = new WebInspector.SourceMapEdit(url, oldRange , "", newText);
871 mapCSStoSASS(cssProperty.range.endLine, cssProperty.rang e.endColumn, edit3);
872
873 edits.push(edit3, edit2, edit1);
874 }
875 //FIXME: do back edits.
876 } else if (diff.type === "PropertyRemoved") {
877 var cssProperty = diff.property;
878 var sassProperty = structureMapping.cssPropertyToSASS(cssPro perty.range, sourceMap);
879 var sassContent = sources.get(sassProperty.url);
880 var lineRemoveRange = new WebInspector.TextRange(sassPropert y.range.startLine, 0, sassProperty.range.endLine + 1, 0);
881 var oldRange = (lineRemoveRange.extract(sassContent).trim() === sassProperty.range.extract(sassContent).trim()) ? lineRemoveRange : sassProp erty.range;
882 var sassEdit = new WebInspector.SourceMapEdit(sassProperty.u rl, oldRange, oldRange.extract(sassContent), "");
883 edits.push(sassEdit);
884 //FIXME: do back edits.
885 }
886 }
887
888 // Categorize edits per url.
889 var editsPerURL = new Map();
890 for (var edit of edits) {
891 if (!editsPerURL.has(edit.sourceURL))
892 editsPerURL.set(edit.sourceURL, []);
893 var list = editsPerURL.get(edit.sourceURL);
894 list.push(edit);
895 }
896
897 // Apply to CSS.
898 var cssEdits = editsPerURL.get(cssSourceURL);
899 if (cssEdits) {
900 cssEdits.stableSort(sequentialOrder);
901 // Apply edits in a reversed order so that they do not conflict with each other.
902 for (var i = cssEdits.length - 1; i >= 0; --i) {
903 var cssEdit = cssEdits[i];
904 newCSSContent = cssEdit.applyToText(newCSSContent);
905 newSourceMap.compiledRangeEdited(cssEdit.oldRange, cssEdit.n ewRange());
906 var ensureMapping = ensureMappings.get(cssEdit);
907 // Add missing mappings to source map.
908 if (ensureMapping)
909 newSourceMap.ensureHasMapping(ensureMapping);
910 }
911 var uiSourceCode = this._networkMapping.uiSourceCodeForURL(cssSo urceURL, this._cssModel.target());
912 this._muteSourceCodeCommitted = true;
913 uiSourceCode.addRevision(newCSSContent);
914 this._muteSourceCodeCommitted = false;
915 }
916 this._contents.set(cssSourceURL, newCSSContent);
917
918 // Apply to SASS.
919 for (var sassURL of editsPerURL.keys()) {
920 if (sassURL === cssSourceURL)
921 continue;
922 var sassContent = sources.get(sassURL);
923 var sassEdits = editsPerURL.get(sassURL);
924 sassEdits.stableSort(sequentialOrder);
925 // Apply edits in a reversed order so that they do not conflict with each other.
926 for (var i = sassEdits.length - 1; i >= 0; --i) {
927 var sassEdit = sassEdits[i];
928 sassContent = sassEdit.applyToText(sassContent);
929 newSourceMap.sourceRangeEdited(sassEdit.sourceURL, sassEdit. oldRange, sassEdit.newRange());
930 var ensureMapping = ensureMappings.get(sassEdit);
931 // Add missing mappings to source map.
932 if (ensureMapping)
933 newSourceMap.ensureHasMapping(ensureMapping);
934 }
935 var uiSourceCode = this._networkMapping.uiSourceCodeForURL(sassU RL, this._cssModel.target());
936 uiSourceCode.addRevision(sassContent);
937 }
938
939 // Hot-Swap source maps.
940 sourceMap._mappings = newSourceMap._mappings;
941 sourceMap._reverseMappingsBySourceURL = newSourceMap._reverseMapping sBySourceURL;
942 }
943
944 function sequentialOrder(range1, range2)
945 {
946 return range1.oldRange.follows(range2.oldRange) ? 1 : -1;
947 }
948
949 function killMapping(sourceURL, e)
950 {
951 console.error(e);
952 this._killMappingForURL(sourceURL);
953 }
954 }
955 }
956
957 WebInspector.SASSSourceMapping.diffCSSStructs = function(oldCSSStruct, newCSSStr uct)
958 {
959 oldCSSStruct = oldCSSStruct.filter(styleRulesFilter);
960 newCSSStruct = newCSSStruct.filter(styleRulesFilter);
961 if (oldCSSStruct.length !== newCSSStruct.length)
962 throw new Error("not implemented for rule diff.");
963 var structuralDiff = [];
964 for (var i = 0; i < oldCSSStruct.length; ++i) {
965 var oldRule = oldCSSStruct[i];
966 var newRule = newCSSStruct[i];
967 var removedSet = new Set();
968 var addedSet = new Set();
969 if (oldRule.properties.length !== newRule.properties.length)
970 WebInspector.SASSSourceMapping.cssPropertiesDiff(oldRule.properties, newRule.properties, removedSet, addedSet);
971 for (var property of removedSet.values()) {
972 structuralDiff.push({
973 type: "PropertyRemoved",
974 property: property
975 });
976 }
977 var firstValidProperty = null;
978 for (var j = 0; j < newRule.properties.length; ++j) {
979 var property = newRule.properties[j];
980 if (!addedSet.has(property)) {
981 firstValidProperty = property;
982 break;
983 }
984 }
985 var lastValidProperty = null;
986 for (var j = 0; j < newRule.properties.length; ++j) {
987 var property = newRule.properties[j];
988 if (!addedSet.has(property)) {
989 lastValidProperty = property;
990 continue;
991 }
992 var diff = {
993 type: "PropertyAdded",
994 property: property,
995 };
996 if (lastValidProperty)
997 diff.after = lastValidProperty;
998 else if (firstValidProperty)
999 diff.before = firstValidProperty;
1000 structuralDiff.push(diff);
1001 }
1002
1003 var p1 = 0;
1004 var p2 = 0;
1005 while (p1 < oldRule.properties.length && p2 < newRule.properties.length) {
1006 if (removedSet.has(oldRule.properties[p1])) {
1007 ++p1;
1008 continue;
1009 }
1010 if (addedSet.has(newRule.properties[p2])) {
1011 ++p2;
1012 continue;
1013 }
1014 var oldProperty = oldRule.properties[p1++];
1015 var newProperty = newRule.properties[p2++];
1016 if (oldProperty.name !== newProperty.name) {
1017 structuralDiff.push({
1018 type: "NameChanged",
1019 property: newProperty
1020 });
1021 } else if (oldProperty.value !== newProperty.value) {
1022 structuralDiff.push({
1023 type: "ValueChanged",
1024 property: newProperty
1025 });
1026 }
1027 }
1028 }
1029 return structuralDiff;
1030
1031 function styleRulesFilter(rule)
1032 {
1033 return !!rule.properties;
1034 }
1035 }
1036
1037 WebInspector.SASSSourceMapping.cssPropertiesDiff = function(properties1, propert ies2, removedSet, addedSet)
1038 {
1039 var charCode = 33;
1040 var encodedProperties = new Map();
1041 var text1 = doEncode(properties1);
1042 var text2 = doEncode(properties2);
1043 var differ = new diff_match_patch();
1044 var diff = differ.diff_main(text1, text2);
1045
1046 var p1 = 0, p2 = 0;
1047 for (var i = 0; i < diff.length; ++i) {
1048 var token = diff[i];
1049 if (token[0] === 0) {
1050 p1 += token[1].length;
1051 p2 += token[1].length;
1052 } else if (token[0] === -1) {
1053 for (var j = 0; j < token[1].length; ++j) {
1054 var property = properties1[p1++];
1055 removedSet.add(property);
1056 }
1057 } else {
1058 for (var j = 0; j < token[1].length; ++j) {
1059 var property = properties2[p2++];
1060 addedSet.add(property);
1061 }
1062 }
1063 }
1064
1065 function doEncode(properties)
1066 {
1067 var text = "";
1068 for (var i = 0; i < properties.length; ++i) {
1069 var encoded = encodedProperties.get(properties[i].name);
1070 if (!encoded) {
1071 encoded = String.fromCharCode(charCode++);
1072 encodedProperties.set(properties[i].name, encoded);
1073 }
1074 text += encoded;
1075 }
1076 return text;
1077 }
1078 }
OLDNEW
« no previous file with comments | « Source/devtools/devtools.gypi ('k') | Source/devtools/front_end/bindings/SASSStructureMapping.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698