[TemporaryStorage] add files required for SDK build
[samples/web/TemporaryStorage.git] / tizen-web-ui-fw / latest / js / src / widgets / jquery.mobile.tizen.widgetex.js
1
2 /*
3  *
4  * This software is licensed under the MIT licence (as defined by the OSI at
5  * http://www.opensource.org/licenses/mit-license.php)
6  * 
7  * ***************************************************************************
8  * Copyright (C) 2011 by Intel Corporation Ltd.
9  * 
10  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software" ),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  * 
17  * The above copyright notice and this permission notice shall be included in
18  * all copies or substantial portions of the Software.
19  * 
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  * ***************************************************************************
28  */
29
30 // Base class for widgets that need the following features:
31 //
32 // I. HTML prototype loading
33 //
34 // This class provides HTML prototype loading for widgets. That is, the widget implementation specifies its HTML portions
35 // in one continuous HTML snippet, and it optionally provides an object containing selectors into the various parts of the
36 // HTML snippet. This widget loads the HTML snippet into a jQuery object, and optionally assigns jQuery objects to each of
37 // the selectors in the optionally provided object.
38 //
39 // To use this functionality you can either derive from this class, or you can call its prototype's gtype method.
40 //
41 // 1. Widgets deriving from this class should define _htmlProto as part of their prototype declaration. _htmlProto looks like
42 // this:
43 //
44 // _htmlProto: {
45 //     source: string|jQuery object (optional) default: string - The name of the widget
46 //     ui: {
47 //         uiElement1: "#ui-element-1-selector",
48 //         uiElement2: "#ui-element-2-selector",
49 //         ...
50 //         subElement: {
51 //             subElement1: "#sub-element-1-selector",
52 //             subElement2: "#sub-element-2-selector",
53 //             ...
54 //         }
55 //         ...
56 //     }
57 // }
58 //
59 // If neither 'source' nor 'ui' are defined, you must still include an empty _htmlProto key (_htmlProto: {}) to indicate
60 // that you wish to make use of this feature. This will cause a prototype HTML file named after your widget to be loaded.
61 // The loaded prototype will be placed into your widget's prototype's _protoHtml.source key.
62 //
63 // If 'source' is defined as a string, it is the name of the widget (including namespace). This is the default. If your
64 // widget's HTML prototype is loaded via AJAX and the name of the AJAX file is different from the name of your widget
65 // (that is, it is not "<widgetName>.prototype.html", then you should explicitly define 'source' as:
66 //
67 // If you wish to load HTML prototypes via AJAX, modify the getProtoPath() function defined below to reflect the directory
68 // structure holding your widget HTML prototypes.
69 //
70 // source: "alternateWidgetName"
71 //
72 // If AJAX loading fails, source is set to a jQuery object containing a div with an error message. You can check whether
73 // loading failed via the jQuery object's jqmData( "tizen.widgetex.ajax.fail" ) data item. If false, then the jQuery object
74 // is the actual prototype loaded via AJAX or present inline. Otherwise, the jQuery object is the error message div.
75 //
76 // If 'source' is defined as a jQuery object, it is considered already loaded.
77 //
78 // if 'ui' is defined inside _htmlProto, It is assumed to be an object such that every one of its keys is either a string,
79 // or another object with the same properties as itself.
80 //
81 // When a widget is instantiated, the HTML prototype is loaded if not already present in the prototype. If 'ui' is present
82 // inside _htmlProto, the prototype is cloned. Then, a new structure is created based on 'ui' with each selector replaced
83 // by a jQuery object containing the results of performing .find() on the prototype's clone with the filter set to the
84 // value of the string. In the special case where the selector starts with a '#', the ID is removed from the element after
85 // it is assigned into the structure being created. This structure is then made accessible from the widget instance via
86 // the '_ui' key (i.e., this._ui).
87 //
88 // 2. Use the loadPrototype method when your widget does not derive from $.tizen.widgetex:
89 // Add _htmlProto to your widget's prototype as described above. Then, in your widget's _create() method, call
90 // loadPrototype in the following manner:
91 //
92 // $.tizen.widgetex.loadPrototype.call(this, "namespace.widgetName" );
93 //
94 // Thereafter, you may use the HTML prototype from your widget's prototype or, if you have specified a 'ui' key in your
95 // _htmlProto key, you may use this._ui from your widget instance.
96 //
97 // II. realize method
98 //
99 // When a widget is created, some of its properties cannot be set immediately, because they depend on the widths/heights
100 // of its constituent elements. They can only be calculated when the page containing the widget is made visible via the
101 // "pageshow" event, because widths/heights always evaluate to 0 when retrieved from a widget that is not visible. When
102 // you inherit from widgetex, you can add a "_realize" function to your prototype. This function will be called once right
103 // after _create() if the element that anchors your widget is on a visible page. Otherwise, it will be called when the
104 // page to which the widget belongs emits the "pageshow" event.
105 //
106 // NB: If your widget is inside a container which is itself not visible, such as an expandable or a collapsible, your
107 // widget will remain hidden even though "pageshow" is fired and therefore _realize is called. In this case, widths and
108 // heights will be unreliable even during _realize.
109 //
110 // III. systematic option handling
111 //
112 // If a widget has lots of options, the _setOption function can become a long switch for setting each recognized option.
113 // It is also tempting to allow options to determine the way a widget is created, by basing decisions on various options
114 // during _create(). Often, the actions based on option values in _create() are the same as those in _setOption. To avoid
115 // such code duplication, this class calls _setOption once for each option after _create() has completed.
116 //
117 // Furthermore, to avoid writing long switches in a widget's _setOption method, this class implements _setOption in such
118 // a way that, for any given option (e.g. "myOption" ), _setOption looks for a method _setMyOption in the widget's
119 // implementation, and if found, calls the method with the value of the option.
120 //
121 // If your widget does not inherit from widgetex, you can still use widgetex' systematic option handling:
122 // 1. define the _setOption method for your widget as follows:
123 //      _setOption: $.tizen.widgetex.prototype._setOption
124 // 2. Call this._setOptions(this.options) from your widget's _create() function.
125 // 3. As with widgetex-derived widgets, implement a corresponding _setMyOptionName function for each option myOptionName
126 // you wish to handle.
127 //
128 // IV. systematic value handling for input elements
129 //
130 // If your widget happens to be constructed from an <input> element, you have to handle the "value" attribute specially,
131 // and you have to emit the "change" signal whenever it changes, in addition to your widget's normal signals and option
132 // changes. With widgetex, you can assign one of your widget's "data-*" properties to be synchronized to the "value"
133 // property whenever your widget is constructed onto an <input> element. To do this, define, in your prototype:
134 //
135 // _value: {
136 //      attr: "data-my-attribute",
137 //      signal: "signal-to-emit"
138 // }
139 //
140 // Then, call this._setValue(newValue) whenever you wish to set the value for your widget. This will set the data-*
141 // attribute, emit the custom signal (if set) with the new value as its parameter, and, if the widget is based on an
142 // <input> element, it will also set the "value" attribute and emit the "change" signal.
143 //
144 // "attr" is required if you choose to define "_value", and identifies the data-attribute to set in addition to "value",
145 // if your widget's element is an input.
146 // "signal" is optional, and will be emitted when setting the data-attribute via this._setValue(newValue).
147 //
148 // If your widget does not derive from widgetex, you can still define "_value" as described above and call
149 // $.tizen.widgetex.setValue(widget, newValue).
150 //
151 // V. Systematic enabled/disabled handling for input elements
152 //
153 // widgetex implements _setDisabled which will disable the input associated with this widget, if any. Thus, if you derive
154 // from widgetex and you plan on implementing the disabled state, you should chain up to
155 // $.tizen.widgetex.prototype._setDisabled(value), rather than $.Widget.prototype._setOption( "disabled", value).
156
157 (function ($, undefined) {
158
159 // Framework-specific HTML prototype path for AJAX loads
160         function getProtoPath() {
161                 var theScriptTag = $( "script[data-framework-version][data-framework-root][data-framework-theme]" );
162
163                 return (theScriptTag.attr( "data-framework-root" ) + "/" +
164                                 theScriptTag.attr( "data-framework-version" ) + "/themes/" +
165                                 theScriptTag.attr( "data-framework-theme" ) + "/proto-html" );
166         }
167
168         $.widget( "tizen.widgetex", $.mobile.widget, {
169                 _createWidget: function () {
170                         $.tizen.widgetex.loadPrototype.call( this, this.namespace + "." + this.widgetName );
171                         $.mobile.widget.prototype._createWidget.apply( this, arguments );
172                 },
173
174                 _init: function () {
175                         // TODO THIS IS TEMPORARY PATCH TO AVOID CTXPOPUP PAGE CRASH
176                         if ( this.element === undefined ) {
177                                 return;
178                         }
179
180                         var page = this.element.closest( ".ui-page" ),
181                                 self = this,
182                                 myOptions = {};
183
184                         if ( page.is( ":visible" ) ) {
185                                 this._realize();
186                         } else {
187                                 page.bind( "pageshow", function () { self._realize(); } );
188                         }
189
190                         $.extend( myOptions, this.options );
191
192                         this.options = {};
193
194                         this._setOptions( myOptions );
195                 },
196
197                 _getCreateOptions: function () {
198                         // if we're dealing with an <input> element, value takes precedence over corresponding data-* attribute, if a
199                         // mapping has been established via this._value. So, assign the value to the data-* attribute, so that it may
200                         // then be assigned to this.options in the superclass' _getCreateOptions
201
202                         if (this.element.is( "input" ) && this._value !== undefined) {
203                                 var theValue =
204                                         ( ( this.element.attr( "type" ) === "checkbox" || this.element.attr( "type" ) === "radio" )
205                                                         ? this.element.is( ":checked" )
206                                                                         : this.element.is( "[value]" )
207                                                                         ? this.element.attr( "value" )
208                                                                                         : undefined);
209
210                                 if ( theValue != undefined ) {
211                                         this.element.attr( this._value.attr, theValue );
212                                 }
213                         }
214
215                         return $.mobile.widget.prototype._getCreateOptions.apply( this, arguments );
216                 },
217
218                 _setOption: function ( key, value ) {
219                         var setter = "_set" + key.replace(/^[a-z]/, function (c) { return c.toUpperCase(); } );
220
221                         if ( this[setter] !== undefined ) {
222                                 this[setter]( value );
223                         } else {
224                                 $.mobile.widget.prototype._setOption.apply( this, arguments );
225                         }
226                 },
227
228                 _setDisabled: function ( value ) {
229                         $.Widget.prototype._setOption.call( this, "disabled", value );
230                         if ( this.element.is( "input" ) ) {
231                                 this.element.attr( "disabled", value );
232                         }
233                 },
234
235                 _setValue: function ( newValue ) {
236                         $.tizen.widgetex.setValue( this, newValue );
237                 },
238
239                 _realize: function () {}
240         } );
241
242         $.tizen.widgetex.setValue = function ( widget, newValue ) {
243                 if ( widget._value !== undefined ) {
244                         var valueString = ( widget._value.makeString ? widget._value.makeString(newValue) : newValue ),
245                                 inputType;
246
247                         widget.element.attr( widget._value.attr, valueString );
248                         if ( widget._value.signal !== undefined ) {
249                                 widget.element.triggerHandler( widget._value.signal, newValue );
250                         }
251
252                         if ( widget.element.is( "input" ) ) {
253                                 inputType = widget.element.attr( "type" );
254
255                                 // Special handling for checkboxes and radio buttons, where the presence of the "checked" attribute is really
256                                 // the value
257                                 if ( inputType === "checkbox" || inputType === "radio" ) {
258                                         if ( newValue ) {
259                                                 widget.element.attr( "checked", true );
260                                         } else {
261                                                 widget.element.removeAttr( "checked" );
262                                         }
263                                 } else {
264                                         widget.element.attr( "value", valueString );
265                                 }
266
267                                 widget.element.trigger( "change" );
268                         }
269                 }
270         };
271
272         $.tizen.widgetex.assignElements = function (proto, obj) {
273                 var ret = {},
274                         key;
275
276                 for ( key in obj ) {
277                         if ( ( typeof obj[key] ) === "string" ) {
278                                 ret[key] = proto.find( obj[key] );
279                                 if ( obj[key].match(/^#/) ) {
280                                         ret[key].removeAttr( "id" );
281                                 }
282                         } else {
283                                 if ( (typeof obj[key]) === "object" ) {
284                                         ret[key] = $.tizen.widgetex.assignElements( proto, obj[key] );
285                                 }
286                         }
287                 }
288
289                 return ret;
290         };
291
292         $.tizen.widgetex.loadPrototype = function ( widget, ui ) {
293                 var ar = widget.split( "." ),
294                         namespace,
295                         widgetName,
296                         source,
297                         noSource = false,
298                         htmlProto,
299                         protoPath;
300
301                 if ( ar.length == 2 ) {
302                         namespace = ar[0];
303                         widgetName = ar[1];
304
305                         // If htmlProto is defined
306                         if ( $[namespace][widgetName].prototype._htmlProto !== undefined ) {
307                                 // If no source is defined, use the widget name
308                                 source = $[namespace][widgetName].prototype._htmlProto.source;
309                                 if ( source === undefined ) {
310                                         source = widgetName;
311                                         noSource = true;
312                                 }
313
314                                 // Load the HTML prototype via AJAX if not defined inline
315                                 if ( typeof source === "string" ) {
316                                         if ( noSource ) {       // use external htmlproto file
317                                                 // Establish the path for the proto file
318                                                 widget = source;
319                                                 protoPath = getProtoPath();
320
321                                                 // Make the AJAX call
322                                                 $.ajax( {
323                                                         url: protoPath + "/" + widget + ".prototype.html",
324                                                         async: false,
325                                                         dataType: "html"
326                                                 }).success( function (data, textStatus, jqXHR ) {
327                                                         source = $( "<div></div>" ).html(data).jqmData( "tizen.widgetex.ajax.fail", false );
328                                                 } );
329
330                                                 // Assign the HTML proto to the widget prototype
331                                                 source  = $( "<div></div>" )
332                                                         .text( "Failed to load proto for widget " + namespace + "." + widgetName + "!" )
333                                                         .css( {background: "red", color: "blue", border: "1px solid black"} )
334                                                         .jqmData( "tizen.widgetex.ajax.fail", true );
335
336                                         } else {
337                                                 // inline definition (string)
338                                                 source = $( source ).jqmData( "tizen.widgetex.ajax.fail", false );
339                                         }
340
341                                 } else {
342                                         // inline definition (object)
343                                         // AJAX loading has trivially succeeded, since there was no AJAX loading at all
344                                         source.jqmData( "tizen.widgetex.ajax.fail", false );
345                                 }
346                                 htmlProto = source;
347                                 $[namespace][widgetName].prototype._htmlProto.source = source;
348
349                                 // If there's a "ui" portion in the HTML proto, copy it over to this instance, and
350                                 // replace the selectors with the selected elements from a copy of the HTML prototype
351                                 if ( $[namespace][widgetName].prototype._htmlProto.ui !== undefined ) {
352                                         // Assign the relevant parts of the proto
353                                         $.extend( this, {
354                                                 _ui: $.tizen.widgetex.assignElements( htmlProto.clone(), $[namespace][widgetName].prototype._htmlProto.ui )
355                                         });
356                                 }
357                         }
358                 }
359         };
360
361 }( jQuery ) );
362