forked from tiff/wysihtml5
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dialog.js
198 lines (180 loc) · 6.27 KB
/
dialog.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/**
* Toolbar Dialog
*
* @param {Element} link The toolbar link which causes the dialog to show up
* @param {Element} container The dialog container
*
* @example
* <!-- Toolbar link -->
* <a data-wysihtml5-command="insertImage">insert an image</a>
*
* <!-- Dialog -->
* <div data-wysihtml5-dialog="insertImage" style="display: none;">
* <label>
* URL: <input data-wysihtml5-dialog-field="src" value="http://">
* </label>
* <label>
* Alternative text: <input data-wysihtml5-dialog-field="alt" value="">
* </label>
* </div>
*
* <script>
* var dialog = new wysihtml5.toolbar.Dialog(
* document.querySelector("[data-wysihtml5-command='insertImage']"),
* document.querySelector("[data-wysihtml5-dialog='insertImage']")
* );
* dialog.observe("save", function(attributes) {
* // do something
* });
* </script>
*/
(function(wysihtml5) {
var dom = wysihtml5.dom,
CLASS_NAME_OPENED = "wysihtml5-command-dialog-opened",
SELECTOR_FORM_ELEMENTS = "input, select, textarea",
SELECTOR_FIELDS = "[data-wysihtml5-dialog-field]",
ATTRIBUTE_FIELDS = "data-wysihtml5-dialog-field";
wysihtml5.toolbar.Dialog = wysihtml5.lang.Dispatcher.extend(
/** @scope wysihtml5.toolbar.Dialog.prototype */ {
constructor: function(link, container) {
this.link = link;
this.container = container;
},
_observe: function() {
if (this._observed) {
return;
}
var that = this,
callbackWrapper = function(event) {
var attributes = that._serialize();
if (attributes == that.elementToChange) {
that.fire("edit", attributes);
} else {
that.fire("save", attributes);
}
that.hide();
event.preventDefault();
event.stopPropagation();
};
dom.observe(that.link, "click", function(event) {
if (dom.hasClass(that.link, CLASS_NAME_OPENED)) {
setTimeout(function() { that.hide(); }, 0);
}
});
dom.observe(this.container, "keydown", function(event) {
var keyCode = event.keyCode;
if (keyCode === wysihtml5.ENTER_KEY) {
callbackWrapper(event);
}
if (keyCode === wysihtml5.ESCAPE_KEY) {
that.hide();
}
});
dom.delegate(this.container, "[data-wysihtml5-dialog-action=save]", "click", callbackWrapper);
dom.delegate(this.container, "[data-wysihtml5-dialog-action=cancel]", "click", function(event) {
that.fire("cancel");
that.hide();
event.preventDefault();
event.stopPropagation();
});
var formElements = this.container.querySelectorAll(SELECTOR_FORM_ELEMENTS),
i = 0,
length = formElements.length,
_clearInterval = function() { clearInterval(that.interval); };
for (; i<length; i++) {
dom.observe(formElements[i], "change", _clearInterval);
}
this._observed = true;
},
/**
* Grabs all fields in the dialog and puts them in key=>value style in an object which
* then gets returned
*/
_serialize: function() {
var data = this.elementToChange || {},
fields = this.container.querySelectorAll(SELECTOR_FIELDS),
length = fields.length,
i = 0;
for (; i<length; i++) {
data[fields[i].getAttribute(ATTRIBUTE_FIELDS)] = fields[i].value;
}
return data;
},
/**
* Takes the attributes of the "elementToChange"
* and inserts them in their corresponding dialog input fields
*
* Assume the "elementToChange" looks like this:
* <a href="http://www.google.com" target="_blank">foo</a>
*
* and we have the following dialog:
* <input type="text" data-wysihtml5-dialog-field="href" value="">
* <input type="text" data-wysihtml5-dialog-field="target" value="">
*
* after calling _interpolate() the dialog will look like this
* <input type="text" data-wysihtml5-dialog-field="href" value="http://www.google.com">
* <input type="text" data-wysihtml5-dialog-field="target" value="_blank">
*
* Basically it adopted the attribute values into the corresponding input fields
*
*/
_interpolate: function(avoidHiddenFields) {
var field,
fieldName,
newValue,
focusedElement = document.querySelector(":focus"),
fields = this.container.querySelectorAll(SELECTOR_FIELDS),
length = fields.length,
i = 0;
for (; i<length; i++) {
field = fields[i];
// Never change elements where the user is currently typing in
if (field === focusedElement) {
continue;
}
// Don't update hidden fields
// See https://github.com/xing/wysihtml5/pull/14
if (avoidHiddenFields && field.type === "hidden") {
continue;
}
fieldName = field.getAttribute(ATTRIBUTE_FIELDS);
newValue = this.elementToChange ? (this.elementToChange[fieldName] || "") : field.defaultValue;
field.value = newValue;
}
},
/**
* Show the dialog element
*/
show: function(elementToChange) {
if (dom.hasClass(this.link, CLASS_NAME_OPENED)) {
return;
}
var that = this,
firstField = this.container.querySelector(SELECTOR_FORM_ELEMENTS);
this.elementToChange = elementToChange;
this._observe();
this._interpolate();
if (elementToChange) {
this.interval = setInterval(function() { that._interpolate(true); }, 500);
}
dom.addClass(this.link, CLASS_NAME_OPENED);
this.container.style.display = "";
this.fire("show");
if (firstField && !elementToChange) {
try {
firstField.focus();
} catch(e) {}
}
},
/**
* Hide the dialog element
*/
hide: function() {
clearInterval(this.interval);
this.elementToChange = null;
dom.removeClass(this.link, CLASS_NAME_OPENED);
this.container.style.display = "none";
this.fire("hide");
}
});
})(wysihtml5);