concrete 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +32 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +87 -0
- data/concrete/basic_inline_editor.js +73 -0
- data/concrete/clipboard.js +72 -0
- data/concrete/concrete.js +58 -0
- data/concrete/constraint_checker.js +297 -0
- data/concrete/editor.js +964 -0
- data/concrete/element_extension.js +68 -0
- data/concrete/external_identifier_provider.js +112 -0
- data/concrete/helper.js +63 -0
- data/concrete/identifier_provider.js +168 -0
- data/concrete/inline_editor.js +55 -0
- data/concrete/metamodel_provider.js +171 -0
- data/concrete/model_interface.js +429 -0
- data/concrete/scroller.js +106 -0
- data/concrete/selector.js +302 -0
- data/concrete/template_provider.js +141 -0
- data/concrete/ui/abstract_dialog.js +80 -0
- data/concrete/ui/concrete_ui.js +28 -0
- data/concrete/ui/create_module_dialog.js +55 -0
- data/concrete/ui/images/close.png +0 -0
- data/concrete/ui/images/document-new.png +0 -0
- data/concrete/ui/images/document-save.png +0 -0
- data/concrete/ui/images/edit-find-replace.png +0 -0
- data/concrete/ui/images/emblem-symbolic-link.png +0 -0
- data/concrete/ui/images/help-browser.png +0 -0
- data/concrete/ui/images/minus_11px.png +0 -0
- data/concrete/ui/images/plus_11px.png +0 -0
- data/concrete/ui/images/preferences-system.png +0 -0
- data/concrete/ui/images/process-stop.png +0 -0
- data/concrete/ui/images/system-search.png +0 -0
- data/concrete/ui/layout_manager.js +54 -0
- data/concrete/ui/module_browser.js +88 -0
- data/concrete/ui/module_editor.js +217 -0
- data/concrete/ui/open_element_dialog.js +90 -0
- data/concrete/ui/preferences_dialog.js +75 -0
- data/concrete/ui/proceed_dialog.js +52 -0
- data/concrete/ui/search_replace_dialog.js +323 -0
- data/concrete/ui/style.css +296 -0
- data/concrete/ui/toolbar.js +74 -0
- data/concrete/ui/workbench.js +165 -0
- data/doc/concrete_developers_guide.html +1054 -0
- data/doc/concrete_developers_guide.txt +502 -0
- data/doc/concrete_users_guide.html +694 -0
- data/doc/concrete_users_guide.txt +223 -0
- data/example/formula_editor/example_data/example1.json +11 -0
- data/example/formula_editor/formula_editor.html +83 -0
- data/example/formula_editor/sqrt_horz.png +0 -0
- data/example/formula_editor/sqrt_vert.png +0 -0
- data/example/formula_editor/style.css +31 -0
- data/example/metamodel_editor/edit.rb +54 -0
- data/example/metamodel_editor/example_data/formula_metamodel.json +18 -0
- data/example/metamodel_editor/example_data/meta_metamodel.json +22 -0
- data/example/metamodel_editor/example_data/statemachine_metamodel.json +32 -0
- data/example/metamodel_editor/metamodel_editor.html +120 -0
- data/example/metamodel_editor/metamodel_editor2.html +135 -0
- data/example/metamodel_editor/metamodel_editor3.html +151 -0
- data/example/metamodel_editor/style.css +8 -0
- data/example/metamodel_editor/style2.css +19 -0
- data/example/metamodel_editor/style3.css +35 -0
- data/example/minimal_editor/minimal_editor.html +43 -0
- data/example/statemachine_editor/example_data/example1.json +11 -0
- data/example/statemachine_editor/state_background.png +0 -0
- data/example/statemachine_editor/statemachine_editor0.html +55 -0
- data/example/statemachine_editor/statemachine_editor1.html +62 -0
- data/example/statemachine_editor/statemachine_editor2.html +103 -0
- data/example/statemachine_editor/style0.css +8 -0
- data/example/statemachine_editor/style1.css +32 -0
- data/example/statemachine_editor/style2.css +43 -0
- data/example/themes/cobalt.css +176 -0
- data/example/themes/dialog-error.png +0 -0
- data/example/themes/dialog-information.png +0 -0
- data/example/themes/dialog-warning.png +0 -0
- data/example/themes/dots_12px.png +0 -0
- data/example/themes/fold_button_dots_when_hidden.css +18 -0
- data/example/themes/fold_button_plus_minus.css +21 -0
- data/example/themes/fold_button_plus_when_hidden.css +18 -0
- data/example/themes/light_blue.css +177 -0
- data/example/themes/minus_11px.png +0 -0
- data/example/themes/minus_13px.png +0 -0
- data/example/themes/minus_9px.png +0 -0
- data/example/themes/plus_11px.png +0 -0
- data/example/themes/plus_13px.png +0 -0
- data/example/themes/plus_9px.png +0 -0
- data/example/themes/white.css +177 -0
- data/lib/concrete/concrete_syntax_provider.rb +63 -0
- data/lib/concrete/config.rb +36 -0
- data/lib/concrete/file_cache_map.rb +88 -0
- data/lib/concrete/index_builder.rb +108 -0
- data/lib/concrete/metamodel/concrete_mmm.rb +45 -0
- data/lib/concrete/metamodel/ecore_to_concrete.rb +80 -0
- data/lib/concrete/server.rb +92 -0
- data/lib/concrete/util/logger.rb +24 -0
- data/lib/concrete/util/string_writer.rb +17 -0
- data/lib/concrete/working_set.rb +41 -0
- data/rakefile +33 -0
- data/redist/prototype.js +4320 -0
- data/redist/scriptaculous/builder.js +136 -0
- data/redist/scriptaculous/controls.js +991 -0
- data/redist/scriptaculous/dragdrop.js +975 -0
- data/redist/scriptaculous/effects.js +1130 -0
- data/redist/scriptaculous/scriptaculous.js +60 -0
- data/redist/scriptaculous/slider.js +275 -0
- data/redist/scriptaculous/sound.js +55 -0
- data/redist/scriptaculous/unittest.js +568 -0
- data/test/concrete_test.rb +5 -0
- data/test/file_cache_map_test.rb +90 -0
- data/test/file_cache_map_test/testdir/fileA +1 -0
- data/test/index_builder_test.rb +68 -0
- data/test/index_builder_test/ecore_index.js +85 -0
- data/test/index_builder_test/ecore_index_expected.js +85 -0
- data/test/integration/external_elements_test.html +114 -0
- data/test/metamodel_test.rb +40 -0
- data/test/metamodel_test/concrete_mmm_expected.js +19 -0
- data/test/metamodel_test/concrete_mmm_generated.js +19 -0
- data/test/metamodel_test/concrete_mmm_regenerated.js +19 -0
- data/test/unit/external_identifier_provider_test.html +138 -0
- data/test/unit/identifier_provider_test.html +269 -0
- data/test/unit/metamodel_provider_test.html +318 -0
- data/test/unit/model_interface_test.html +257 -0
- data/test/unit/template_provider_test.html +171 -0
- data/test/unit/test.css +90 -0
- data/test/working_set_test.rb +54 -0
- data/test/working_set_test/file1.txt +0 -0
- data/test/working_set_test/file2 +0 -0
- data/test/working_set_test/subdir/file3.xml +0 -0
- metadata +201 -0
@@ -0,0 +1,90 @@
|
|
1
|
+
Concrete.UI.OpenElementDialog = Class.create(Concrete.UI.AbstractDialog, {
|
2
|
+
|
3
|
+
initialize: function($super, extIdentProvider, options) {
|
4
|
+
var dialogElement = this._createDomElement();
|
5
|
+
$super(dialogElement, options);
|
6
|
+
this.input = dialogElement.down(".search_box_input");
|
7
|
+
this.extIdentProvider = extIdentProvider;
|
8
|
+
this.completer = this._createAutoCompleter();
|
9
|
+
},
|
10
|
+
|
11
|
+
_createDomElement: function() {
|
12
|
+
if ($('ct_open_element_dialog')) return $('ct_open_element_dialog');
|
13
|
+
Element.insert($$('body').first(), { bottom:
|
14
|
+
"<div id='ct_open_element_dialog' class='popup_dialog' style='display: none; position: fixed; z-index: 1000'>" +
|
15
|
+
"<div class='shadow'></div>" +
|
16
|
+
"<div class='dialog_box'>" +
|
17
|
+
"<div class='title_bar'>" +
|
18
|
+
"Open Element" +
|
19
|
+
"<a class='close_button'></a>" +
|
20
|
+
"</div>" +
|
21
|
+
"<div class='container'>" +
|
22
|
+
"<p class='label'>Element name</p>" +
|
23
|
+
"<input class='text_input search_box_input' type='text' spellcheck='false'/>" +
|
24
|
+
"<div class='search_box_list_container'>" +
|
25
|
+
"<div class='search_box_list auto_complete_dropdown' style='position: relative'>" +
|
26
|
+
"</div> " +
|
27
|
+
"</div> " +
|
28
|
+
"<div style='text-align: center; margin: 10px'>" +
|
29
|
+
"<input class='button_input proceed_button' type='button' value='Open' />" +
|
30
|
+
"</div>" +
|
31
|
+
"</div> " +
|
32
|
+
"</div> " +
|
33
|
+
"</div>"
|
34
|
+
});
|
35
|
+
return $('ct_open_element_dialog');
|
36
|
+
},
|
37
|
+
|
38
|
+
_createAutoCompleter: function() {
|
39
|
+
var eip = this.extIdentProvider;
|
40
|
+
var completer = new Autocompleter.Local(
|
41
|
+
this.input,
|
42
|
+
this.dialogElement.down(".search_box_list"),
|
43
|
+
[],
|
44
|
+
{ partialSearch: true, fullSearch: true, minChars: 0, partialChars: 0, choices: 100,
|
45
|
+
selector: function(completer) {
|
46
|
+
var result = [];
|
47
|
+
var entry = completer.getToken();
|
48
|
+
|
49
|
+
for (var i = 0; i < completer.options.array.length &&
|
50
|
+
result.length < completer.options.choices ; i++) {
|
51
|
+
|
52
|
+
var ei = completer.options.array[i];
|
53
|
+
var identifier = ei.identifier;
|
54
|
+
var foundPos = completer.options.ignoreCase ?
|
55
|
+
identifier.toLowerCase().indexOf(entry.toLowerCase()) :
|
56
|
+
identifier.indexOf(entry);
|
57
|
+
|
58
|
+
if (foundPos != -1) {
|
59
|
+
result.push("<li><span class='search_box_identifier'>"+
|
60
|
+
identifier.substr(0, foundPos) +
|
61
|
+
"<strong>" + identifier.substr(foundPos, entry.length) + "</strong>" +
|
62
|
+
identifier.substr(foundPos + entry.length) +
|
63
|
+
"</span><span class='informal search_box_class_name'> ["+ei.type+"]</span><br />"+
|
64
|
+
"<span class='search_box_module_name'> "+ei.module+"</span>"+
|
65
|
+
"</li>");
|
66
|
+
}
|
67
|
+
}
|
68
|
+
return "<ul>" + result.join('') + "</ul>";
|
69
|
+
}});
|
70
|
+
return completer;
|
71
|
+
},
|
72
|
+
|
73
|
+
_proceed: function() {
|
74
|
+
if (this.options.onOpenReference) {
|
75
|
+
var value = this.input.value;
|
76
|
+
var splitIndex = value.indexOf(" ");
|
77
|
+
var ident = value.substr(0, splitIndex);
|
78
|
+
var module = value.substr(splitIndex+1, value.length-splitIndex-1);
|
79
|
+
this.options.onOpenReference(module, ident);
|
80
|
+
}
|
81
|
+
},
|
82
|
+
|
83
|
+
open: function($super, eis) {
|
84
|
+
$super();
|
85
|
+
this.input.value = "";
|
86
|
+
this.completer.options.array = eis;
|
87
|
+
},
|
88
|
+
|
89
|
+
});
|
90
|
+
|
@@ -0,0 +1,75 @@
|
|
1
|
+
Concrete.UI.PreferencesDialog = Class.create(Concrete.UI.AbstractDialog, {
|
2
|
+
|
3
|
+
initialize: function($super, options) {
|
4
|
+
options = options || {};
|
5
|
+
var dialogElement = this._createDomElement();
|
6
|
+
$super(dialogElement, options);
|
7
|
+
this.syntaxInput = dialogElement.down(".syntax_input");
|
8
|
+
},
|
9
|
+
|
10
|
+
_createDomElement: function() {
|
11
|
+
if ($('ct_preferences_dialog')) return $('ct_preferences_dialog');
|
12
|
+
Element.insert($$('body').first(), { bottom:
|
13
|
+
"<div id='ct_preferences_dialog' class='popup_dialog' style='display: none; position: fixed; z-index: 1000'>" +
|
14
|
+
"<div class='shadow'></div>" +
|
15
|
+
"<div class='dialog_box'>" +
|
16
|
+
"<div class='title_bar'>Preferences" +
|
17
|
+
"<a class='close_button'></a>" +
|
18
|
+
"</div>" +
|
19
|
+
"<div class='container'>" +
|
20
|
+
"<p class='label'>Concrete Syntax</p>" +
|
21
|
+
"<select class='dropdown_input syntax_input'>" +
|
22
|
+
"</select>" +
|
23
|
+
"<p>Save your work and press 'reload' to make changes visible.</p>" +
|
24
|
+
"<div style='text-align: center; margin: 10px'>" +
|
25
|
+
"<input class='button_input proceed_button' type='button' value='OK' />" +
|
26
|
+
"<input class='button_input cancel_button' type='button' value='Cancel' />" +
|
27
|
+
"</div>" +
|
28
|
+
"</div>" +
|
29
|
+
"</div>" +
|
30
|
+
"</div>" });
|
31
|
+
return $('ct_preferences_dialog');
|
32
|
+
},
|
33
|
+
|
34
|
+
_proceed: function() {
|
35
|
+
new Ajax.Request("/setConcreteSyntax", {
|
36
|
+
method: 'get',
|
37
|
+
parameters: {"ident": this.syntaxInput.value},
|
38
|
+
onSuccess: function(transport) {
|
39
|
+
},
|
40
|
+
onFailure: function() {
|
41
|
+
}
|
42
|
+
});
|
43
|
+
},
|
44
|
+
|
45
|
+
_buttonPressed: function(element) {
|
46
|
+
if (element == this.dialogElement.down(".cancel_button")) {
|
47
|
+
this.close();
|
48
|
+
}
|
49
|
+
},
|
50
|
+
|
51
|
+
open: function($super, options) {
|
52
|
+
$super();
|
53
|
+
new Ajax.Request("/concreteSyntaxes", {
|
54
|
+
method: 'get',
|
55
|
+
onSuccess: function(transport) {
|
56
|
+
if (transport.responseText.isJSON()) {
|
57
|
+
var synDesc = transport.responseText.evalJSON();
|
58
|
+
Element.replace(this.syntaxInput,
|
59
|
+
"<select class='dropdown_input syntax_input'>" +
|
60
|
+
synDesc.syntaxes.collect(function(s) {
|
61
|
+
var selected = (s.ident == synDesc.selected) ? "selected" : "";
|
62
|
+
return "<option "+selected+" value=\""+s.ident+"\">"+s.name+"</option>";
|
63
|
+
}).join("") +
|
64
|
+
"</select>"
|
65
|
+
);
|
66
|
+
this.syntaxInput = this.dialogElement.down(".syntax_input");
|
67
|
+
}
|
68
|
+
}.bind(this),
|
69
|
+
});
|
70
|
+
}
|
71
|
+
|
72
|
+
});
|
73
|
+
|
74
|
+
|
75
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
Concrete.UI.ProceedDialog = Class.create(Concrete.UI.AbstractDialog, {
|
2
|
+
|
3
|
+
initialize: function($super, options) {
|
4
|
+
options = options || {};
|
5
|
+
this.title = options.title || "Proceed?";
|
6
|
+
this.message = options.message || "Proceed?";
|
7
|
+
this.proceedButtonText = options.proceedButtonText || "Proceed";
|
8
|
+
var dialogElement = this._createDomElement();
|
9
|
+
$super(dialogElement, options);
|
10
|
+
},
|
11
|
+
|
12
|
+
_createDomElement: function() {
|
13
|
+
if ($('ct_proceed_dialog')) return $('ct_proceed_dialog');
|
14
|
+
Element.insert($$('body').first(), { bottom:
|
15
|
+
"<div id='ct_proceed_dialog' class='popup_dialog' style='display: none; position: fixed; z-index: 1000'>" +
|
16
|
+
"<div class='shadow'></div>" +
|
17
|
+
"<div class='dialog_box'>" +
|
18
|
+
"<div class='title_bar'>" + this.title +
|
19
|
+
"<a class='close_button'></a>" +
|
20
|
+
"</div>" +
|
21
|
+
"<div class='container'>" +
|
22
|
+
"<p class='label'>"+this.message+"</p>" +
|
23
|
+
"<div style='text-align: center; margin: 10px'>" +
|
24
|
+
"<input class='button_input proceed_button' type='button' value='"+this.proceedButtonText+"' />" +
|
25
|
+
"<input class='button_input cancel_button' type='button' value='Cancel' />" +
|
26
|
+
"</div>" +
|
27
|
+
"</div>" +
|
28
|
+
"</div>" +
|
29
|
+
"</div>" });
|
30
|
+
return $('ct_proceed_dialog');
|
31
|
+
},
|
32
|
+
|
33
|
+
_proceed: function() {
|
34
|
+
if (this._onProceed) {
|
35
|
+
this._onProceed();
|
36
|
+
}
|
37
|
+
},
|
38
|
+
|
39
|
+
_buttonPressed: function(element) {
|
40
|
+
if (element == this.dialogElement.down(".cancel_button")) {
|
41
|
+
this.close();
|
42
|
+
}
|
43
|
+
},
|
44
|
+
|
45
|
+
open: function($super, options) {
|
46
|
+
$super();
|
47
|
+
this._onProceed = options.onProceed;
|
48
|
+
},
|
49
|
+
|
50
|
+
});
|
51
|
+
|
52
|
+
|
@@ -0,0 +1,323 @@
|
|
1
|
+
Concrete.UI.SearchReplaceDialog = Class.create(Concrete.UI.AbstractDialog, {
|
2
|
+
|
3
|
+
initialize: function($super, options) {
|
4
|
+
var dialogElement = this._createDomElement();
|
5
|
+
$super(dialogElement, options);
|
6
|
+
|
7
|
+
this.propertyInput = dialogElement.down(".property_input");
|
8
|
+
Element.insert(this.propertyInput, { after:
|
9
|
+
"<div style='position: relative; margin: 1px'><div class='auto_complete_dropdown' style='display: none; width: 100%; max-height: 100px; overflow-y: auto'></div></div>"
|
10
|
+
});
|
11
|
+
this.propertyOptions = [];
|
12
|
+
new Autocompleter.Local(this.propertyInput, this.propertyInput.next().down(), this.propertyOptions, {
|
13
|
+
partialSearch: true, fullSearch: true, minChars: 0, partialChars: 0, choices: 100 })
|
14
|
+
|
15
|
+
this.searchInput = dialogElement.down(".search_input");
|
16
|
+
this.replaceInput = dialogElement.down(".replace_input");
|
17
|
+
this.findButton = dialogElement.down(".find_button");
|
18
|
+
this.replaceButton = dialogElement.down(".replace_button");
|
19
|
+
this.replaceFindButton = dialogElement.down(".replace_find_button");
|
20
|
+
this.replaceAllButton = dialogElement.down(".replace_all_button");
|
21
|
+
this.regexpBox = dialogElement.down(".regular_expression_box");
|
22
|
+
this.statusOutput = dialogElement.down(".status_output");
|
23
|
+
this.lastNodeFound = undefined;
|
24
|
+
},
|
25
|
+
|
26
|
+
_createDomElement: function() {
|
27
|
+
if ($('ct_search_replace_dialog')) return $('ct_search_replace_dialog');
|
28
|
+
Element.insert($$('body').first(), { bottom:
|
29
|
+
"<div id='ct_search_replace_dialog' class='popup_dialog' style='display: none; position: fixed; z-index: 1000'>" +
|
30
|
+
"<div class='shadow'></div>" +
|
31
|
+
"<div class='dialog_box'>" +
|
32
|
+
"<div class='title_bar'>" +
|
33
|
+
"Find and replace" +
|
34
|
+
"<a class='close_button'></a>" +
|
35
|
+
"</div>" +
|
36
|
+
"<div class='container'>" +
|
37
|
+
"<p class='label'>For property</p>" +
|
38
|
+
"<input class='text_input property_input' type='text' spellcheck='false'/>" +
|
39
|
+
"<div style='float: right; margin-top: 10px'>Regular Expression: <input class='checkbox_input regular_expression_box' type='checkbox' /></div>" +
|
40
|
+
"<p class='label'>Find value</p>" +
|
41
|
+
"<input class='text_input search_input' type='text' spellcheck='false'/>" +
|
42
|
+
"<p class='label'>Replace with</p>" +
|
43
|
+
"<input class='text_input replace_input' type='text' spellcheck='false'/>" +
|
44
|
+
"<div style='width: 100%; margin: 5px 0 5px 0' class='status_output' > </div>" +
|
45
|
+
"<div style='text-align: center; margin: 10px'>" +
|
46
|
+
"<input class='button_input find_button' type='button' value='Find' />" +
|
47
|
+
"<input class='button_input replace_button' type='button' value='Replace' />" +
|
48
|
+
"<input class='button_input replace_find_button' type='button' value='Replace/Find' />" +
|
49
|
+
"<input class='button_input replace_all_button' type='button' value='Replace All' />" +
|
50
|
+
"</div>" +
|
51
|
+
"</div>" +
|
52
|
+
"</div>" +
|
53
|
+
"</div>" });
|
54
|
+
return $('ct_search_replace_dialog');
|
55
|
+
},
|
56
|
+
|
57
|
+
_buttonPressed: function(element) {
|
58
|
+
var featureDesc = this.propertyInput.value.strip();
|
59
|
+
if (/^(\w*|\*|\w+#\*|\w+#\w+)$/.match(featureDesc)) {
|
60
|
+
if (featureDesc.include("#")) {
|
61
|
+
var className = featureDesc.split("#")[0];
|
62
|
+
var featureName = featureDesc.split("#")[1];
|
63
|
+
}
|
64
|
+
else {
|
65
|
+
var featureName = featureDesc;
|
66
|
+
}
|
67
|
+
}
|
68
|
+
else {
|
69
|
+
this._setStatus("Invalid feature description: specify <feature name>, <class name>#<feature name>, <class name>#*, * or leave empty");
|
70
|
+
return;
|
71
|
+
}
|
72
|
+
var searchPattern = this.searchInput.value;
|
73
|
+
if (this.regexpBox.checked) {
|
74
|
+
try {
|
75
|
+
searchPattern = new RegExp(searchPattern);
|
76
|
+
}
|
77
|
+
catch(e) {
|
78
|
+
this._setStatus("Invalid regular expression");
|
79
|
+
return;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
var replaceText = this.replaceInput.value;
|
83
|
+
|
84
|
+
if (element == this.findButton) {
|
85
|
+
this._findCommand(className, featureName, searchPattern);
|
86
|
+
}
|
87
|
+
else if (element == this.replaceButton) {
|
88
|
+
this._replaceCommand(searchPattern, replaceText);
|
89
|
+
}
|
90
|
+
else if (element == this.replaceFindButton) {
|
91
|
+
this._replaceCommand(searchPattern, replaceText);
|
92
|
+
this._findCommand(className, featureName, searchPattern);
|
93
|
+
}
|
94
|
+
else if (element == this.replaceAllButton) {
|
95
|
+
this._replaceAllCommand(className, featureName, searchPattern, replaceText);
|
96
|
+
}
|
97
|
+
},
|
98
|
+
|
99
|
+
_findCommand: function(className, featureName, searchPattern) {
|
100
|
+
this._setStatus("Searching...");
|
101
|
+
this._defer(function() {
|
102
|
+
if (this._selectNextMatch(className, featureName, searchPattern)) {
|
103
|
+
this._setStatus("Found next occurance");
|
104
|
+
}
|
105
|
+
else {
|
106
|
+
this._setStatus("Pattern not found");
|
107
|
+
}
|
108
|
+
});
|
109
|
+
},
|
110
|
+
|
111
|
+
_replaceCommand: function(searchPattern, replaceText) {
|
112
|
+
if (this.lastNodeFound && this.lastSearchPattern.toString() == searchPattern.toString() && this.editor.selector.selected == this.lastNodeFound) {
|
113
|
+
this._setStatus("Replacing...");
|
114
|
+
this._defer(function() {
|
115
|
+
if (this._replaceMatch(this.lastNodeFound, searchPattern, replaceText)) {
|
116
|
+
this._setStatus("Replaced 1 occurance");
|
117
|
+
}
|
118
|
+
else {
|
119
|
+
this._setStatus("Nothing replaced");
|
120
|
+
}
|
121
|
+
});
|
122
|
+
}
|
123
|
+
else {
|
124
|
+
this._setStatus("Use find before replace");
|
125
|
+
}
|
126
|
+
},
|
127
|
+
|
128
|
+
_replaceAllCommand: function(className, featureName, searchPattern, replaceText) {
|
129
|
+
this._setStatus("Replacing...");
|
130
|
+
this._defer(function() {
|
131
|
+
var numReplaced = this._replaceAll(className, featureName, searchPattern, replaceText);
|
132
|
+
this._setStatus("Replaced "+numReplaced+" occurances");
|
133
|
+
});
|
134
|
+
},
|
135
|
+
|
136
|
+
// this is a special defer which is necessary, since Prototype's defer doesn't seem to yield
|
137
|
+
// the current process in a way that UI redrawing can take place
|
138
|
+
_defer: function(func) {
|
139
|
+
func = func.bind(this);
|
140
|
+
window.setTimeout(function() {
|
141
|
+
window.setTimeout(func, 0);
|
142
|
+
}, 0);
|
143
|
+
},
|
144
|
+
|
145
|
+
_selectNextMatch: function(className, featureName, searchPattern) {
|
146
|
+
var startLoc = this._findLocation(this.editor.selector.selected);
|
147
|
+
if (!startLoc) return false;
|
148
|
+
var nextLoc = this.findNext(startLoc[0], startLoc[1], startLoc[2], className, featureName, searchPattern);
|
149
|
+
if (nextLoc) {
|
150
|
+
var node = nextLoc[0].features[nextLoc[1]].slot.childElements()[nextLoc[2]];
|
151
|
+
this.editor.expandParentElements(node);
|
152
|
+
if (node.ancestors().any(function(a) {return !a.visible();})) {
|
153
|
+
this.editor.showHiddenFeatures(node.up(".ct_element"));
|
154
|
+
}
|
155
|
+
this.editor.selector.selectDirect(node);
|
156
|
+
this.lastNodeFound = node;
|
157
|
+
this.lastSearchPattern = searchPattern;
|
158
|
+
}
|
159
|
+
return (nextLoc != false);
|
160
|
+
},
|
161
|
+
|
162
|
+
_replaceAll: function(className, featureName, searchPattern, replaceText) {
|
163
|
+
var startLoc = this._findLocation(this.editor.selector.selected);
|
164
|
+
if (!startLoc) return 0;
|
165
|
+
var firstMatch = this.findNext(startLoc[0], startLoc[1], startLoc[2], className, featureName, searchPattern);
|
166
|
+
var nextMatch = firstMatch;
|
167
|
+
var matches = [];
|
168
|
+
while (nextMatch) {
|
169
|
+
matches.push(nextMatch);
|
170
|
+
nextMatch = this.findNext(nextMatch[0], nextMatch[1], nextMatch[2], className, featureName, searchPattern);
|
171
|
+
if (nextMatch[0] == firstMatch[0] && nextMatch[1] == firstMatch[1] && nextMatch[2] == firstMatch[2]) {
|
172
|
+
break;
|
173
|
+
}
|
174
|
+
}
|
175
|
+
var numReplaced = 0;
|
176
|
+
matches.each(function(match) {
|
177
|
+
var node = match[0].features[match[1]].slot.childElements()[match[2]];
|
178
|
+
if (this._replaceMatch(node, searchPattern, replaceText)) {
|
179
|
+
numReplaced++;
|
180
|
+
}
|
181
|
+
}, this);
|
182
|
+
return numReplaced;
|
183
|
+
},
|
184
|
+
|
185
|
+
_replaceMatch: function(node, searchPattern, replaceText) {
|
186
|
+
if (Object.isString(searchPattern) && (searchPattern.empty() || searchPattern.strip() == "*")) {
|
187
|
+
if (replaceText.empty()) {
|
188
|
+
//this.editor.modelInterface.removeValue(node);
|
189
|
+
}
|
190
|
+
else {
|
191
|
+
var newValue = replaceText;
|
192
|
+
}
|
193
|
+
}
|
194
|
+
else {
|
195
|
+
var newValue = node.value.replace(searchPattern, replaceText);
|
196
|
+
}
|
197
|
+
if (newValue) {
|
198
|
+
this.editor.modelInterface.changeValue(node, newValue);
|
199
|
+
return true;
|
200
|
+
}
|
201
|
+
else {
|
202
|
+
return false;
|
203
|
+
}
|
204
|
+
},
|
205
|
+
|
206
|
+
// finds the next value starting from +element+, feature index +fIndex+, value index +vIndex+
|
207
|
+
// when the last model element has been checked, the search will continue with the first element
|
208
|
+
// the search will stop after the starting point has been reached and checked
|
209
|
+
//
|
210
|
+
findNext: function(element, fIndex, vIndex, className, featureName, searchPattern) {
|
211
|
+
var startElement = element;
|
212
|
+
var startFIndex = fIndex;
|
213
|
+
var startVIndex = vIndex;
|
214
|
+
var containmentStack = [];
|
215
|
+
var wrapAround = 0;
|
216
|
+
while (true) {
|
217
|
+
var feature = element.features[fIndex];
|
218
|
+
var values = feature && element.featureValues(feature.mmFeature.name);
|
219
|
+
if (feature && (vIndex < values.size()-1)) {
|
220
|
+
// next value
|
221
|
+
vIndex++;
|
222
|
+
if (feature.mmFeature.isContainment()) {
|
223
|
+
// go down to child element
|
224
|
+
containmentStack.push(element);
|
225
|
+
containmentStack.push(feature);
|
226
|
+
element = values[vIndex];
|
227
|
+
fIndex = 0;
|
228
|
+
vIndex = -1;
|
229
|
+
}
|
230
|
+
else {
|
231
|
+
// found a value
|
232
|
+
if ((!className || className == "*" || element.mmClass.name == className) &&
|
233
|
+
(!featureName || featureName == "*" || feature.mmFeature.name == featureName) &&
|
234
|
+
(!searchPattern ||
|
235
|
+
(Object.isString(searchPattern) && (searchPattern == "*" || (""+values[vIndex]).include(searchPattern))) ||
|
236
|
+
(!Object.isString(searchPattern) && searchPattern.match(""+values[vIndex])))) {
|
237
|
+
return [element, fIndex, vIndex];
|
238
|
+
}
|
239
|
+
}
|
240
|
+
}
|
241
|
+
else if (fIndex < element.features.size()-1) {
|
242
|
+
// next feature
|
243
|
+
fIndex++;
|
244
|
+
vIndex = -1;
|
245
|
+
}
|
246
|
+
else {
|
247
|
+
var parentFeature = containmentStack.pop() || element.up(".ct_containment");
|
248
|
+
if (parentFeature) {
|
249
|
+
// go up to parent
|
250
|
+
var parentElement = containmentStack.pop() || parentFeature.up(".ct_element");
|
251
|
+
fIndex = parentElement.features.indexOf(parentFeature);
|
252
|
+
vIndex = parentFeature.slot.childElements().indexOf(element);
|
253
|
+
element = parentElement;
|
254
|
+
}
|
255
|
+
else if (element.next()) {
|
256
|
+
// next on root level
|
257
|
+
element = element.next();
|
258
|
+
fIndex = 0;
|
259
|
+
vIndex = -1;
|
260
|
+
}
|
261
|
+
else {
|
262
|
+
// first on root level, wrap around
|
263
|
+
element = element.up(".ct_root").childElements().first();
|
264
|
+
fIndex = 0;
|
265
|
+
vIndex = -1;
|
266
|
+
wrapAround++;
|
267
|
+
}
|
268
|
+
}
|
269
|
+
if ((element == startElement && fIndex == startFIndex && vIndex == startVIndex) || wrapAround > 1) {
|
270
|
+
// reached starting point, or wrapped around more than once (safety check to avoid endless loop)
|
271
|
+
return false;
|
272
|
+
}
|
273
|
+
}
|
274
|
+
},
|
275
|
+
|
276
|
+
_setStatus: function(text) {
|
277
|
+
this.statusOutput.textContent = text;
|
278
|
+
},
|
279
|
+
|
280
|
+
_findLocation: function(node) {
|
281
|
+
if (node.mmClass) {
|
282
|
+
return [node, 0, -1];
|
283
|
+
}
|
284
|
+
else if (node.hasClassName("ct_empty")) {
|
285
|
+
var feature = node.findAncestor(["ct_containment", "ct_reference", "ct_attribute"]);
|
286
|
+
if (feature) {
|
287
|
+
var element = feature.up(".ct_element");
|
288
|
+
return [element, element.features.indexOf(feature), -1];
|
289
|
+
}
|
290
|
+
else {
|
291
|
+
// empty element on root level
|
292
|
+
return false;
|
293
|
+
}
|
294
|
+
}
|
295
|
+
else {
|
296
|
+
var feature = node.findAncestor(["ct_containment", "ct_reference", "ct_attribute"]);
|
297
|
+
var element = feature.up(".ct_element");
|
298
|
+
return [element, element.features.indexOf(feature), feature.slot.childElements().indexOf(node)];
|
299
|
+
}
|
300
|
+
},
|
301
|
+
|
302
|
+
open: function($super, editor) {
|
303
|
+
$super();
|
304
|
+
this.editor = editor;
|
305
|
+
this.propertyOptions.clear();
|
306
|
+
this.lastNodeFound = undefined;
|
307
|
+
this.statusOutput.innerHTML = " ";
|
308
|
+
var featureNames = [];
|
309
|
+
this.options.metamodelProvider.metaclasses.each(function(c) {
|
310
|
+
this.propertyOptions.push(c.name+"#*");
|
311
|
+
c.allFeatures().each(function(f) {
|
312
|
+
featureNames.push(f.name);
|
313
|
+
this.propertyOptions.push(c.name+"#"+f.name);
|
314
|
+
}, this);
|
315
|
+
}, this);
|
316
|
+
featureNames.uniq().reverse().each(function(fn) {
|
317
|
+
this.propertyOptions.unshift(fn);
|
318
|
+
}, this);
|
319
|
+
}
|
320
|
+
|
321
|
+
});
|
322
|
+
|
323
|
+
|