2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #include "CalendarPickerElement.h"
34 #if ENABLE(CALENDAR_PICKER)
36 #include "CalendarPicker.h"
38 #include "ChromeClient.h"
39 #include "DateComponents.h"
40 #include "DocumentWriter.h"
42 #include "FrameView.h"
43 #include "HTMLInputElement.h"
44 #include "HTMLNames.h"
46 #include "LocalizedDate.h"
47 #include "LocalizedStrings.h"
49 #include "RenderDetailsMarker.h"
50 #include <wtf/text/StringBuilder.h>
52 using namespace WTF::Unicode;
56 using namespace HTMLNames;
58 inline CalendarPickerElement::CalendarPickerElement(Document* document)
59 : HTMLDivElement(divTag, document)
62 setShadowPseudoId("-webkit-calendar-picker-indicator");
65 PassRefPtr<CalendarPickerElement> CalendarPickerElement::create(Document* document)
67 return adoptRef(new CalendarPickerElement(document));
70 RenderObject* CalendarPickerElement::createRenderer(RenderArena* arena, RenderStyle*)
72 return new (arena) RenderDetailsMarker(this);
75 inline HTMLInputElement* CalendarPickerElement::hostInput()
77 ASSERT(shadowAncestorNode());
78 ASSERT(shadowAncestorNode()->hasTagName(inputTag));
79 return static_cast<HTMLInputElement*>(shadowAncestorNode());
82 void CalendarPickerElement::defaultEventHandler(Event* event)
84 HTMLInputElement* input = hostInput();
85 if (input->readOnly() || input->disabled())
88 if (event->type() == eventNames().clickEvent) {
90 event->setDefaultHandled();
93 if (!event->defaultHandled())
94 HTMLDivElement::defaultEventHandler(event);
97 void CalendarPickerElement::openPopup()
101 if (!document()->page())
103 Chrome* chrome = document()->page()->chrome();
106 if (!document()->view())
108 IntRect elementRectInRootView = document()->view()->contentsToRootView(hostInput()->getPixelSnappedRect());
109 m_popup = chrome->client()->openPagePopup(this, elementRectInRootView);
112 void CalendarPickerElement::closePopup()
116 if (!document()->page())
118 Chrome* chrome = document()->page()->chrome();
121 chrome->client()->closePagePopup(m_popup);
124 void CalendarPickerElement::detach()
127 HTMLDivElement::detach();
130 IntSize CalendarPickerElement::contentSize()
132 return IntSize(100, 100);
135 #define addLiteral(literal, writer) writer.addData(literal, sizeof(literal) - 1)
137 static inline void addString(const String& str, DocumentWriter& writer)
139 CString str8 = str.utf8();
140 writer.addData(str8.data(), str8.length());
143 static void addJavaScriptString(const String& str, DocumentWriter& writer)
145 addLiteral("\"", writer);
146 StringBuilder builder;
147 builder.reserveCapacity(str.length());
148 for (unsigned i = 0; i < str.length(); ++i) {
149 if (str[i] == '\\' || str[i] == '"')
150 builder.append('\\');
151 builder.append(str[i]);
153 addString(builder.toString(), writer);
154 addLiteral("\"", writer);
157 static void addProperty(const char* name, const String& value, DocumentWriter& writer)
159 writer.addData(name, strlen(name));
160 addLiteral(": ", writer);
161 addJavaScriptString(value, writer);
162 addLiteral(",\n", writer);
165 static void addProperty(const char* name, unsigned value, DocumentWriter& writer)
167 writer.addData(name, strlen(name));
168 addLiteral(": ", writer);
169 addString(String::number(value), writer);
170 addLiteral(",\n", writer);
173 static void addProperty(const char* name, bool value, DocumentWriter& writer)
175 writer.addData(name, strlen(name));
176 addLiteral(": ", writer);
178 addLiteral("true", writer);
180 addLiteral("false", writer);
181 addLiteral(",\n", writer);
184 static void addProperty(const char* name, const Vector<String>& values, DocumentWriter& writer)
186 writer.addData(name, strlen(name));
187 addLiteral(": [", writer);
188 for (unsigned i = 0; i < values.size(); ++i) {
190 addLiteral(",", writer);
191 addJavaScriptString(values[i], writer);
193 addLiteral("],\n", writer);
196 void CalendarPickerElement::writeDocument(DocumentWriter& writer)
198 HTMLInputElement* input = hostInput();
200 date.setMillisecondsSinceEpochForDate(input->minimum());
201 String minString = date.toString();
202 date.setMillisecondsSinceEpochForDate(input->maximum());
203 String maxString = date.toString();
205 String stepString = input->fastGetAttribute(stepAttr);
206 if (stepString.isEmpty() || !input->getAllowedValueStep(&step))
209 addLiteral("<!DOCTYPE html><head><meta charset='UTF-8'><style>\n", writer);
210 writer.addData(calendarPickerCss, sizeof(calendarPickerCss));
211 addLiteral("</style></head><body><div id=main>Loading...</div><script>\n"
212 "window.dialogArguments = {\n", writer);
213 addProperty("min", minString, writer);
214 addProperty("max", maxString, writer);
215 addProperty("step", stepString, writer);
216 addProperty("required", input->required(), writer);
217 addProperty("currentValue", input->value(), writer);
218 addProperty("locale", defaultLanguage(), writer);
219 addProperty("todayLabel", calendarTodayText(), writer);
220 addProperty("clearLabel", calendarClearText(), writer);
221 addProperty("weekStartDay", firstDayOfWeek(), writer);
222 addProperty("monthLabels", monthLabels(), writer);
223 addProperty("dayLabels", weekDayShortLabels(), writer);
224 Direction dir = direction(monthLabels()[0][0]);
225 addProperty("isRTL", dir == RightToLeft || dir == RightToLeftArabic, writer);
226 addLiteral("}\n", writer);
228 writer.addData(calendarPickerJs, sizeof(calendarPickerJs));
229 addLiteral("</script></body>\n", writer);
232 void CalendarPickerElement::setValueAndClosePopup(int numValue, const String& stringValue)
237 hostInput()->setValue(stringValue, DispatchChangeEvent);
240 void CalendarPickerElement::didClosePopup()