/lib/source/js/kendo.window.js

http://luckyloot.codeplex.com · JavaScript · 1648 lines · 734 code · 182 blank · 732 comment · 95 complexity · 3994656169fcfadbde11c5aa77086c80 MD5 · raw file

Large files are truncated click here to view the full file

  1. /*
  2. * Kendo UI Web v2012.2.710 (http://kendoui.com)
  3. * Copyright 2012 Telerik AD. All rights reserved.
  4. *
  5. * Kendo UI Web commercial licenses may be obtained at http://kendoui.com/web-license
  6. * If you do not own a commercial license, this file shall be governed by the
  7. * GNU General Public License (GPL) version 3.
  8. * For GPL requirements, please review: http://www.gnu.org/copyleft/gpl.html
  9. */
  10. /**
  11. * @fileOverview Provides a Window implementation which can be used to display content in a modal or non-modal HTML
  12. * window.
  13. */
  14. (function($, undefined) {
  15. /**
  16. * @name kendo.ui.Window.Description
  17. *
  18. * @section
  19. * <p>
  20. * A <strong>Window</strong> displays content in a modal or non-modal HTML window. By default, a
  21. * <strong>Window</strong> can be moved, resized, and closed. Its content can also be defined with either as
  22. * static HTML or loaded dynamically via AJAX.
  23. * </p>
  24. * <p>
  25. * A <strong>Window</strong> can be initialized from virtually any DOM element. During initialization, the
  26. * targeted content will automatically be wrapped in the div element of the <strong>Window</strong>.
  27. * </p>
  28. * <h3>Getting Started</h3>
  29. *
  30. * @exampleTitle Create a simple HTML element with the Window content
  31. * @example
  32. * <div id="window">
  33. * Content of the Window
  34. * </div>
  35. *
  36. * @exampleTitle Initialize the Window using a selector
  37. * @example
  38. * $(document).ready(function() {
  39. * $("#window").kendoWindow();
  40. * });
  41. *
  42. * @section
  43. * <p>
  44. * When a <strong>Window</strong> is initialized, it will automatically be displayed open near the location of the
  45. * DOM element that was used to initialize the content.
  46. * </p>
  47. * <h3>Configuring Window Behaviors</h3>
  48. * <p>
  49. * A <strong>Window</strong> provides many configuration options that can be easily set during initialization.
  50. * Among the properties that can be controlled:
  51. * </p>
  52. * <ul>
  53. * <li>Minimum height/width</li>
  54. * <li>Available user actions (close/refresh/maximize/minimize) and ability to define custom ones</li>
  55. * <li>Title</li>
  56. * <li>Draggable and resizable behaviors</li>
  57. * </ul>
  58. *
  59. * @exampleTitle Create a modal Window with all user actions enabled
  60. * @example
  61. * $("#window").kendoWindow({
  62. * actions: ["Custom", "Refresh", "Maximize", "Minimize", "Close"],
  63. * draggable: false,
  64. * height: "300px",
  65. * modal: true,
  66. * resizable: false,
  67. * title: "Modal Window",
  68. * width: "500px"
  69. * });
  70. *
  71. * @section
  72. * <p>
  73. * The order of the values in the actions array determines the order in which the action buttons will be rendered
  74. * in the title of a <strong>Window</strong>. The maximize action serves both as a button for expanding a
  75. * <strong>Window</strong> to fill the screen and as a button to restore a <strong>Window</strong> to its previous
  76. * size. The minimize action collapses a <strong>Window</strong> to its title.
  77. * </p>
  78. * <p>If a non-recognized action name is supplied, it is treated as a custom action - <strong>k-icon</strong> and <strong>k-actionname</strong>
  79. * CSS classes are rendered for it and no click event handler is attached automatically. The Kendo stylesheets have a supplied icon for
  80. * actions with the name "Custom", but any name can be used. Click events can be captured and handled in a standard way:</p>
  81. *
  82. * @exampleTitle Custom actions
  83. * @example
  84. * $("#window").kendoWindow({
  85. * actions: ["Custom", "Minimize", "Maximize", "Close"],
  86. * title: "Window Title"
  87. * }).data("kendoWindow").wrapper.find(".k-i-custom").click(function(e) {
  88. * alert("Custom action button clicked");
  89. * e.preventDefault();
  90. * });
  91. *
  92. * <h3>Positioning and Opening a Window</h3>
  93. * <p>
  94. * In some scenarios, it is preferable to center a <strong>Window</strong> rather than open it near the HTML
  95. * element used to define the content. It is also common to open a <strong>Window</strong> as the result of the
  96. * action of a user rather than on the load event of a page. The <strong>Window</strong> API provides methods for
  97. * handling these scenarios.
  98. * </p>
  99. *
  100. * @exampleTitle Centering a Window and opening on button click
  101. * @example
  102. * <div id="window">
  103. * Content of the Window
  104. * </div>
  105. * <button id="openButton">Open Window</button>
  106. *
  107. * @exampleTitle Initialize Window, center, and configure button click action
  108. * @example
  109. * $(document).ready(function(){
  110. * var win = $("#window").kendoWindow({
  111. * height: "200px",
  112. * title: "Centered Window",
  113. * visible: false,
  114. * width: "200px"
  115. * }).data("kendoWindow");
  116. * });
  117. *
  118. * $("#openButton").click(function(){
  119. * var win = $("#window").data("kendoWindow");
  120. * win.center();
  121. * win.open();
  122. * });
  123. *
  124. * @section
  125. * <h3>Loading Window content via AJAX</h3>
  126. * <p>
  127. * A <strong>Window</strong> provides built-in support for asynchronously loading content from a URL. This URL
  128. * should return a HTML fragment that can be loaded in a Window content area.
  129. * </p>
  130. *
  131. * @exampleTitle Load Window content asynchronously
  132. * @example
  133. * <div id="window"></div>
  134. *
  135. * @exampleTitle Initialize window and configure content loading
  136. * @example
  137. * $(document).ready(function(){
  138. * $("#window").kendoWindow({
  139. * content: "html-content-snippet.html",
  140. * title: "Async Window Content"
  141. * });
  142. * });
  143. *
  144. * @section
  145. * <h3>Accessing an Existing Window</h3>
  146. * <p>
  147. * You can reference an existing <b>Window</b> instance via
  148. * <a href="http://api.jquery.com/jQuery.data/">jQuery.data()</a>. Once a reference has been established, you can
  149. * use the API to control its behavior.
  150. * </p>
  151. *
  152. * @exampleTitle Accessing an existing Window instance
  153. * @example
  154. * var win = $("#window").data("kendoWindow");
  155. *
  156. */
  157. var kendo = window.kendo,
  158. Widget = kendo.ui.Widget,
  159. Draggable = kendo.ui.Draggable,
  160. isPlainObject = $.isPlainObject,
  161. proxy = $.proxy,
  162. extend = $.extend,
  163. each = $.each,
  164. template = kendo.template,
  165. BODY = "body",
  166. templates,
  167. // classNames
  168. KWINDOW = ".k-window",
  169. KWINDOWTITLEBAR = ".k-window-titlebar",
  170. KWINDOWCONTENT = ".k-window-content",
  171. KWINDOWRESIZEHANDLES = ".k-resize-handle",
  172. KOVERLAY = ".k-overlay",
  173. KCONTENTFRAME = "k-content-frame",
  174. LOADING = "k-loading",
  175. KHOVERSTATE = "k-state-hover",
  176. // constants
  177. VISIBLE = ":visible",
  178. HIDDEN = "hidden",
  179. CURSOR = "cursor",
  180. // events
  181. OPEN = "open",
  182. ACTIVATE = "activate",
  183. DEACTIVATE = "deactivate",
  184. CLOSE = "close",
  185. REFRESH = "refresh",
  186. RESIZE = "resize",
  187. DRAGSTART = "dragstart",
  188. DRAGEND = "dragend",
  189. ERROR = "error",
  190. OVERFLOW = "overflow",
  191. ZINDEX = "zIndex",
  192. MINIMIZE_MAXIMIZE = ".k-window-actions .k-i-minimize,.k-window-actions .k-i-maximize",
  193. isLocalUrl = kendo.isLocalUrl;
  194. function constrain(value, low, high) {
  195. return Math.max(Math.min(value, high), low);
  196. }
  197. function windowObject(element) {
  198. return element.children(KWINDOWCONTENT).data("kendoWindow");
  199. }
  200. function openedModalWindows() {
  201. return $(KWINDOW).filter(function() {
  202. var wnd = $(this);
  203. return wnd.is(VISIBLE) && windowObject(wnd).options.modal;
  204. }).sort(function(a, b){
  205. return +$(a).css("zIndex") - +$(b).css("zIndex");
  206. });
  207. }
  208. function sizingAction(actionId, callback) {
  209. return function() {
  210. var that = this,
  211. wrapper = that.wrapper,
  212. style = wrapper[0].style,
  213. options = that.options;
  214. if (options.isMaximized || options.isMinimized) {
  215. return;
  216. }
  217. that.restoreOptions = {
  218. width: style.width,
  219. height: style.height
  220. };
  221. wrapper
  222. .find(KWINDOWRESIZEHANDLES).hide().end()
  223. .find(MINIMIZE_MAXIMIZE).parent().hide()
  224. .eq(0).before(templates.action({ name: "Restore" }));
  225. callback.call(that);
  226. return that;
  227. };
  228. }
  229. var Window = Widget.extend(/** @lends kendo.ui.Window.prototype */ {
  230. /**
  231. *
  232. * @constructs
  233. * @extends kendo.ui.Widget
  234. *
  235. * @param {Element} element
  236. * DOM element
  237. *
  238. * @param {Object} options
  239. * Configuration options.
  240. *
  241. * @option {Boolean} [modal] <false>
  242. * Specifies whether the window should show a modal overlay over the page.
  243. *
  244. * @option {Boolean} [visible] <true>
  245. * Specifies whether the window will be initially visible.
  246. *
  247. * @option {Boolean} [draggable] <true>
  248. * Enables (<strong>true</strong>) or disables (<strong>false</strong>) the ability for users to move/drag a
  249. * <strong>Window</strong>.
  250. *
  251. * @option {Boolean} [resizable] <true>
  252. * Enables (<strong>true</strong>) or disables (<strong>false</strong>) the ability for users to resize a
  253. * <strong>Window</strong>.
  254. *
  255. * @option {Number} [minWidth] <50>
  256. * The minimum width (in pixels) that may be achieved by resizing the window.
  257. *
  258. * @option {Number} [minHeight] <50>
  259. * The minimum height (in pixels) that may be achieved by resizing the window.
  260. *
  261. * @option {Number} [maxWidth] <Infinity>
  262. * The maximum width (in pixels) that may be achieved by resizing the window.
  263. *
  264. * @option {Number} [maxHeight] <Infinity>
  265. * The maximum height (in pixels) that may be achieved by resizing the window.
  266. *
  267. * @option {Object|String} [content]
  268. * Specifies a URL or request options that the window should load its content from. For remote URLs, a
  269. * container iframe element is automatically created.
  270. *
  271. * @option {String} [content.template]
  272. * Template for the content of a <strong>Window</strong>.
  273. *
  274. * @option {Boolean} [iframe]
  275. * Explicitly states whether content iframe should be created.
  276. *
  277. * @option {Array} [actions] <["Close"]>
  278. * The buttons for interacting with the window. Predefined array values are "Close", "Refresh", "Minimize",
  279. * and "Maximize".
  280. *
  281. * @option {String} [title]
  282. * The text in the window title bar.
  283. *
  284. * @option {Object} [appendTo] <document.body>
  285. * The element that the Window will be appended to.
  286. *
  287. * @option {Object} [animation]
  288. * A collection of {Animation} objects, used to change default animations. A value of <strong>false</strong>
  289. * will disable all animations in the widget.
  290. *
  291. * @option {Animation} [animation.open]
  292. * The animation that will be used when a Window opens.
  293. *
  294. * @option {Animation} [animation.close]
  295. * The animation that will be used when a Window closes.
  296. *
  297. */
  298. init: function(element, options) {
  299. var that = this,
  300. wrapper,
  301. offset, visibility, display,
  302. isVisible = false,
  303. content;
  304. Widget.fn.init.call(that, element, options);
  305. options = that.options;
  306. element = that.element;
  307. content = options.content;
  308. that.appendTo = $(options.appendTo || document.body);
  309. that._animations();
  310. if (!isPlainObject(content)) {
  311. content = options.content = { url: content };
  312. }
  313. if (!element.parent().is(that.appendTo)) {
  314. if (element.is(VISIBLE)) {
  315. offset = element.offset();
  316. isVisible = true;
  317. } else {
  318. visibility = element.css("visibility");
  319. display = element.css("display");
  320. element.css({ visibility: HIDDEN, display: "" });
  321. offset = element.offset();
  322. element.css({ visibility: visibility, display: display });
  323. }
  324. }
  325. if (typeof options.visible == "undefined") {
  326. options.visible = element.is(VISIBLE);
  327. }
  328. wrapper = that.wrapper = element.closest(KWINDOW);
  329. if (!element.is(".k-content") || !wrapper[0]) {
  330. element.addClass("k-window-content k-content");
  331. that._createWindow(element, options);
  332. wrapper = that.wrapper = element.closest(KWINDOW);
  333. that._dimensions();
  334. }
  335. if (offset) {
  336. wrapper.css({
  337. top: offset.top,
  338. left: offset.left
  339. });
  340. }
  341. if (content) {
  342. that.refresh(content);
  343. }
  344. that.toFront();
  345. if (options.visible && options.modal) {
  346. that._overlay(wrapper.is(VISIBLE)).css({ opacity: 0.5 });
  347. }
  348. wrapper.on({
  349. mouseenter: function () { $(this).addClass(KHOVERSTATE); },
  350. mouseleave: function () { $(this).removeClass(KHOVERSTATE); },
  351. click: proxy(that._windowActionHandler, that)
  352. }, ".k-window-titlebar .k-window-action");
  353. if (options.resizable) {
  354. wrapper.on("dblclick", KWINDOWTITLEBAR, proxy(that.toggleMaximization, that));
  355. each("n e s w se sw ne nw".split(" "), function(index, handler) {
  356. wrapper.append(templates.resizeHandle(handler));
  357. });
  358. that.resizing = new WindowResizing(that);
  359. }
  360. if (options.draggable) {
  361. that.dragging = new WindowDragging(that);
  362. }
  363. wrapper.add(wrapper.find(".k-resize-handle,.k-window-titlebar"))
  364. .on("mousedown", proxy(that.toFront, that));
  365. that.touchScroller = kendo.touchScroller(element);
  366. $(window).resize(proxy(that._onDocumentResize, that));
  367. if (options.visible) {
  368. that.trigger(OPEN);
  369. that.trigger(ACTIVATE);
  370. }
  371. kendo.notify(that);
  372. },
  373. _dimensions: function() {
  374. var that = this,
  375. wrapper = that.wrapper,
  376. element = that.element,
  377. options = that.options;
  378. that.title(options.title);
  379. if (options.width) {
  380. wrapper.width(options.width);
  381. }
  382. if (options.height) {
  383. wrapper.height(options.height);
  384. }
  385. each(["minWidth","minHeight","maxWidth","maxHeight"], function(_, prop) {
  386. var value = options[prop];
  387. if (value && value != Infinity) {
  388. element.css(prop, value);
  389. }
  390. });
  391. if (!options.visible) {
  392. wrapper.hide();
  393. }
  394. },
  395. _animations: function() {
  396. var options = this.options;
  397. if (options.animation === false) {
  398. options.animation = { open: { show: true, effects: {} }, close: { hide:true, effects: {} } };
  399. }
  400. },
  401. setOptions: function(options) {
  402. Widget.fn.setOptions.call(this, options);
  403. this._animations();
  404. this._dimensions();
  405. },
  406. events:[
  407. /**
  408. *
  409. * Triggered when a Window is opened (i.e. the open() method is called).
  410. *
  411. * @name kendo.ui.Window#open
  412. * @event
  413. * @cancellable
  414. *
  415. * @param {Event} e
  416. *
  417. * @exampleTitle Attach open event handler during initialization; detach via unbind()
  418. * @example
  419. * // event handler for expand
  420. * var onOpen = function(e) {
  421. * // ...
  422. * };
  423. *
  424. * // attach open event handler during initialization
  425. * var kendoWindow = $("#window").kendoWindow({
  426. * open: onOpen
  427. * });
  428. *
  429. * // detach expand event handler via unbind()
  430. * kendoWindow.data("kendoWindow").unbind("open", onOpen);
  431. *
  432. * @exampleTitle Attach open event handler via bind(); detach via unbind()
  433. * @example
  434. * // event handler for open
  435. * var onOpen = function(e) {
  436. * // ...
  437. * };
  438. *
  439. * // attach open event handler via bind()
  440. * $("#window").data("kendoWindow").bind("open", onOpen);
  441. *
  442. * // detach open event handler via unbind()
  443. * $("#window").data("kendoWindow").unbind("open", onOpen);
  444. *
  445. */
  446. OPEN,
  447. /**
  448. *
  449. * Triggered when a Window has finished its opening animation.
  450. *
  451. * @name kendo.ui.Window#activate
  452. * @event
  453. *
  454. * @param {Event} e
  455. *
  456. * @exampleTitle Attach activate event handler during initialization; detach via unbind()
  457. * @example
  458. * // event handler for activate
  459. * var onActivate = function(e) {
  460. * // ...
  461. * };
  462. *
  463. * // attach activate event handler during initialization
  464. * var kendoWindow = $("#window").kendoWindow({
  465. * activate: onActivate
  466. * });
  467. *
  468. * // detach activate event handler via unbind()
  469. * kendoWindow.data("kendoWindow").unbind("activate", onActivate);
  470. *
  471. * @exampleTitle Attach activate event handler via bind(); detach via unbind()
  472. * @example
  473. * // event handler for activate
  474. * var onActivate = function(e) {
  475. * // ...
  476. * };
  477. *
  478. * // attach activate event handler via bind()
  479. * $("#window").data("kendoWindow").bind("activate", onActivate);
  480. *
  481. * // detach activate event handler via unbind()
  482. * $("#window").data("kendoWindow").unbind("activate", onActivate);
  483. *
  484. */
  485. ACTIVATE,
  486. /**
  487. *
  488. * Triggered when a Window has finished its closing animation.
  489. *
  490. * @name kendo.ui.Window#deactivate
  491. * @event
  492. *
  493. * @param {Event} e
  494. *
  495. * @exampleTitle Attach deactivate event handler during initialization; detach via unbind()
  496. * @example
  497. * // event handler for deactivate
  498. * var onDeactivate = function(e) {
  499. * // ...
  500. * };
  501. *
  502. * // attach deactivate event handler during initialization
  503. * var kendoWindow = $("#window").kendoWindow({
  504. * deactivate: onDeactivate
  505. * });
  506. *
  507. * // detach deactivate event handler via unbind()
  508. * kendoWindow.data("kendoWindow").unbind("deactivate", onDeactivate);
  509. *
  510. * @exampleTitle Attach deactivate event handler via bind(); detach via unbind()
  511. * @example
  512. * // event handler for deactivate
  513. * var onDeactivate = function(e) {
  514. * // ...
  515. * };
  516. *
  517. * // attach deactivate event handler via bind()
  518. * $("#window").data("kendoWindow").bind("deactivate", onDeactivate);
  519. *
  520. * // detach deactivate event handler via unbind()
  521. * $("#window").data("kendoWindow").unbind("deactivate", onDeactivate);
  522. *
  523. */
  524. DEACTIVATE,
  525. /**
  526. *
  527. * Triggered when a Window is closed (by a user or through the close() method).
  528. *
  529. * @name kendo.ui.Window#close
  530. * @event
  531. * @cancellable
  532. *
  533. * @param {Event} e
  534. *
  535. * @exampleTitle Attach close event handler during initialization; detach via unbind()
  536. * @example
  537. * // event handler for close
  538. * var onClose = function(e) {
  539. * // ...
  540. * };
  541. *
  542. * // attach close event handler during initialization
  543. * var kendoWindow = $("#window").kendoWindow({
  544. * close: onClose
  545. * });
  546. *
  547. * // detach close event handler via unbind()
  548. * kendoWindow.data("kendoWindow").unbind("close", onClose);
  549. *
  550. * @exampleTitle Attach close event handler via bind(); detach via unbind()
  551. * @example
  552. * // event handler for close
  553. * var onClose = function(e) {
  554. * // ...
  555. * };
  556. *
  557. * // attach close event handler via bind()
  558. * $("#window").data("kendoWindow").bind("close", onClose);
  559. *
  560. * // detach close event handler via unbind()
  561. * $("#window").data("kendoWindow").unbind("close", onClose);
  562. *
  563. */
  564. CLOSE,
  565. /**
  566. *
  567. * Triggered when the content of a Window have been refreshed via AJAX.
  568. *
  569. * @name kendo.ui.Window#refresh
  570. * @event
  571. *
  572. * @param {Event} e
  573. *
  574. * @exampleTitle Attach refresh event handler during initialization; detach via unbind()
  575. * @example
  576. * // event handler for refresh
  577. * var onRefresh = function(e) {
  578. * // ...
  579. * };
  580. *
  581. * // attach refresh event handler during initialization
  582. * var kendoWindow = $("#window").kendoWindow({
  583. * refresh: onRefresh
  584. * });
  585. *
  586. * // detach refresh event handler via unbind()
  587. * kendoWindow.data("kendoWindow").unbind("refresh", onRefresh);
  588. *
  589. * @exampleTitle Attach refresh event handler via bind(); detach via unbind()
  590. * @example
  591. * // event handler for refresh
  592. * var onRefresh = function(e) {
  593. * // ...
  594. * };
  595. *
  596. * // attach refresh event handler via bind()
  597. * $("#window").data("kendoWindow").bind("refresh", onRefresh);
  598. *
  599. * // detach refresh event handler via unbind()
  600. * $("#window").data("kendoWindow").unbind("refresh", onRefresh);
  601. *
  602. */
  603. REFRESH,
  604. /**
  605. *
  606. * Triggered when a Window has been resized by a user.
  607. *
  608. * @name kendo.ui.Window#resize
  609. * @event
  610. *
  611. * @param {Event} e
  612. *
  613. * @exampleTitle Attach resize event handler during initialization; detach via unbind()
  614. * @example
  615. * // event handler for resize
  616. * var onResize = function(e) {
  617. * // ...
  618. * };
  619. *
  620. * // attach resize event handler during initialization
  621. * var kendoWindow = $("#window").kendoWindow({
  622. * resize: onResize
  623. * });
  624. *
  625. * // detach resize event handler via unbind()
  626. * kendoWindow.data("kendoWindow").unbind("resize", onResize);
  627. *
  628. * @exampleTitle Attach resize event handler via bind(); detach via unbind()
  629. * @example
  630. * // event handler for resize
  631. * var onResize = function(e) {
  632. * // ...
  633. * };
  634. *
  635. * // attach resize event handler via bind()
  636. * $("#window").data("kendoWindow").bind("resize", onResize);
  637. *
  638. * // detach resize event handler via unbind()
  639. * $("#window").data("kendoWindow").unbind("resize", onResize);
  640. *
  641. */
  642. RESIZE,
  643. /**
  644. * Triggered when the user starts to move the window.
  645. * @name kendo.ui.Window#dragstart
  646. * @event
  647. * @param {Event} e
  648. */
  649. DRAGSTART,
  650. /**
  651. *
  652. * Triggered when a Window has been moved by a user.
  653. *
  654. * @name kendo.ui.Window#dragend
  655. * @event
  656. *
  657. * @param {Event} e
  658. *
  659. * @exampleTitle Attach dragEnd event handler during initialization; detach via unbind()
  660. * @example
  661. * // event handler for dragEnd
  662. * var onDragEnd = function(e) {
  663. * // ...
  664. * };
  665. *
  666. * // attach dragEnd event handler during initialization
  667. * var kendoWindow = $("#window").kendoWindow({
  668. * dragend: onDragEnd
  669. * });
  670. *
  671. * // detach dragEnd event handler via unbind()
  672. * kendoWindow.data("kendoWindow").unbind("dragend", onDragEnd);
  673. *
  674. * @exampleTitle Attach dragEnd event handler via bind(); detach via unbind()
  675. * @example
  676. * // event handler for dragEnd
  677. * var onDragEnd = function(e) {
  678. * // ...
  679. * };
  680. *
  681. * // attach dragEnd event handler via bind()
  682. * $("#window").data("kendoWindow").bind("dragend", onDragEnd);
  683. *
  684. * // detach dragEnd event handler via unbind()
  685. * $("#window").data("kendoWindow").unbind("dragend", onDragEnd);
  686. *
  687. */
  688. DRAGEND,
  689. /**
  690. *
  691. * Triggered when an AJAX request for content fails.
  692. *
  693. * @name kendo.ui.Window#error
  694. * @event
  695. *
  696. * @param {Event} e
  697. *
  698. * @exampleTitle Attach error event handler during initialization; detach via unbind()
  699. * @example
  700. * // event handler for error
  701. * var onError = function(e) {
  702. * // ...
  703. * };
  704. *
  705. * // attach dragEnd event handler during initialization
  706. * var kendoWindow = $("#window").kendoWindow({
  707. * error: onError
  708. * });
  709. *
  710. * // detach error event handler via unbind()
  711. * kendoWindow.data("kendoWindow").unbind("error", onError);
  712. *
  713. * @exampleTitle Attach error event handler via bind(); detach via unbind()
  714. * @example
  715. * // event handler for error
  716. * var onError = function(e) {
  717. * // ...
  718. * };
  719. *
  720. * // attach error event handler via bind()
  721. * $("#window").data("kendoWindow").bind("error", onError);
  722. *
  723. * // detach error event handler via unbind()
  724. * $("#window").data("kendoWindow").unbind("error", onError);
  725. *
  726. */
  727. ERROR
  728. ],
  729. options: {
  730. name: "Window",
  731. animation: {
  732. open: {
  733. effects: { zoom: { direction: "in" }, fade: { direction: "in" } },
  734. duration: 350,
  735. show: true
  736. },
  737. close: {
  738. effects: { zoom: { direction: "out", properties: { scale: 0.7 } }, fade: { direction: "out" } },
  739. duration: 350,
  740. hide: true
  741. }
  742. },
  743. title: "",
  744. actions: ["Close"],
  745. modal: false,
  746. resizable: true,
  747. draggable: true,
  748. minWidth: 90,
  749. minHeight: 50,
  750. maxWidth: Infinity,
  751. maxHeight: Infinity
  752. },
  753. _overlay: function (visible) {
  754. var overlay = this.appendTo.children(".k-overlay"),
  755. wrapper = this.wrapper;
  756. if (!overlay.length) {
  757. overlay = $("<div class='k-overlay' />");
  758. }
  759. overlay
  760. .insertBefore(wrapper[0])
  761. .toggle(visible)
  762. .css(ZINDEX, parseInt(wrapper.css(ZINDEX), 10) - 1);
  763. return overlay;
  764. },
  765. _windowActionHandler: function (e) {
  766. var target = $(e.target).closest(".k-window-action").find(".k-icon"),
  767. that = this;
  768. each({
  769. "k-i-close": that.close,
  770. "k-i-maximize": that.maximize,
  771. "k-i-minimize": that.minimize,
  772. "k-i-restore": that.restore,
  773. "k-i-refresh": that.refresh
  774. }, function (commandName, handler) {
  775. if (target.hasClass(commandName)) {
  776. e.preventDefault();
  777. handler.call(that);
  778. return false;
  779. }
  780. });
  781. },
  782. /**
  783. *
  784. * Centers a <strong>Window</strong> within the viewport.
  785. *
  786. * @returns {Window}
  787. * Returns the (Kendo UI) Window object to support chaining.
  788. *
  789. * @example
  790. * var kendoWindow = $("#window").data("kendoWindow");
  791. * kendoWindow.center();
  792. *
  793. */
  794. center: function () {
  795. var wrapper = this.wrapper,
  796. documentWindow = $(window);
  797. wrapper.css({
  798. left: documentWindow.scrollLeft() + Math.max(0, (documentWindow.width() - wrapper.width()) / 2),
  799. top: documentWindow.scrollTop() + Math.max(0, (documentWindow.height() - wrapper.height()) / 2)
  800. });
  801. return this;
  802. },
  803. /**
  804. *
  805. * Gets or set the title of a <strong>Window</strong>.
  806. *
  807. * @param {String} [text]
  808. * The title of the Window.
  809. *
  810. * @returns {Window}
  811. * If a title is provided, this method will return the (Kendo UI) Window object to support chaining. Otherwise,
  812. * it will return the current title of the (Kendo UI) Window.
  813. *
  814. * @exampleTitle Get the existing title of the Window
  815. * @example
  816. * var kendoWindow = $("#window").data("kendoWindow");
  817. * var windowTitle = kendoWindow.title();
  818. *
  819. * @exampleTitle Set the title of a Window; utilize chaining (if necessary)
  820. * @example
  821. * var kendoWindow = $("#window").data("kendoWindow").title("Do a barrel roll!");
  822. *
  823. */
  824. title: function (text) {
  825. var that = this,
  826. wrapper = that.wrapper,
  827. options = that.options,
  828. titleBar = wrapper.find(KWINDOWTITLEBAR),
  829. title = titleBar.children(".k-window-title"),
  830. titleBarHeight = titleBar.outerHeight();
  831. if (!arguments.length) {
  832. return title.text();
  833. }
  834. if (text === false) {
  835. wrapper.addClass("k-window-titleless");
  836. titleBar.remove();
  837. } else {
  838. if (!titleBar.length) {
  839. wrapper.prepend(templates.titlebar(extend(templates, options)));
  840. }
  841. wrapper.css("padding-top", titleBarHeight);
  842. titleBar.css("margin-top", -titleBarHeight);
  843. }
  844. title.text(text);
  845. return that;
  846. },
  847. /**
  848. *
  849. * Gets or set the content of a <strong>Window</strong>.
  850. *
  851. * @param {String} [content]
  852. * The content of the Window.
  853. *
  854. * @returns {Window}
  855. * If content is provided, this method will return the (Kendo UI) Window object to support chaining. Otherwise,
  856. * it will return the current content of the (Kendo UI) Window.
  857. *
  858. * @exampleTitle Get the existing content of the Window
  859. * @example
  860. * var kendoWindow = $("#window").data("kendoWindow");
  861. * var windowContent = kendoWindow.content();
  862. *
  863. * @exampleTitle Set the title of a Window; utilize chaining (if necessary)
  864. * @example
  865. * var kendoWindow = $("#window").data("kendoWindow").content("Kendo UI for all the things!");
  866. *
  867. */
  868. content: function (html) {
  869. var content = this.wrapper.children(KWINDOWCONTENT);
  870. if (!html) {
  871. return content.html();
  872. }
  873. content.html(html);
  874. return this;
  875. },
  876. /**
  877. *
  878. * Opens a Window.
  879. *
  880. * @returns {Window}
  881. * Returns the (Kendo UI) Window object to support chaining.
  882. *
  883. * @exampleTitle Open a Window; utilize chaining (if necessary)
  884. * @example
  885. * var kendoWindow = $("#window").data("kendoWindow").open();
  886. *
  887. */
  888. open: function () {
  889. var that = this,
  890. wrapper = that.wrapper,
  891. options = that.options,
  892. showOptions = options.animation.open,
  893. contentElement = wrapper.children(KWINDOWCONTENT),
  894. initialOverflow = contentElement.css(OVERFLOW),
  895. overlay;
  896. if (!that.trigger(OPEN)) {
  897. that.toFront();
  898. options.visible = true;
  899. if (options.modal) {
  900. overlay = that._overlay(false);
  901. if (showOptions.duration) {
  902. overlay.kendoStop().kendoAnimate({
  903. effects: { fade: { direction: "out", properties: { opacity: 0.5 } } },
  904. duration: showOptions.duration,
  905. show: true
  906. });
  907. } else {
  908. overlay.css("opacity", 0.5).show();
  909. }
  910. }
  911. if (!wrapper.is(VISIBLE)) {
  912. contentElement.css(OVERFLOW, HIDDEN);
  913. wrapper.show().kendoStop().kendoAnimate({
  914. effects: showOptions.effects,
  915. duration: showOptions.duration,
  916. complete: function() {
  917. that.trigger(ACTIVATE);
  918. contentElement.css(OVERFLOW, initialOverflow);
  919. }
  920. });
  921. }
  922. }
  923. if (options.isMaximized) {
  924. that._documentScrollTop = $(document).scrollTop();
  925. $("html, body").css(OVERFLOW, HIDDEN);
  926. }
  927. return that;
  928. },
  929. /**
  930. *
  931. * Closes a Window.
  932. *
  933. * @returns {Window}
  934. * Returns the (Kendo UI) Window object to support chaining.
  935. *
  936. * @exampleTitle Close a Window; utilize chaining (if necessary)
  937. * @example
  938. * var kendoWindow = $("#window").data("kendoWindow").close();
  939. *
  940. */
  941. close: function () {
  942. var that = this,
  943. wrapper = that.wrapper,
  944. options = that.options,
  945. showOptions = options.animation.open,
  946. hideOptions = options.animation.close,
  947. modalWindows,
  948. shouldHideOverlay, overlay;
  949. if (wrapper.is(VISIBLE) && !that.trigger(CLOSE)) {
  950. options.visible = false;
  951. modalWindows = openedModalWindows();
  952. shouldHideOverlay = options.modal && modalWindows.length == 1;
  953. overlay = options.modal ? that._overlay(true) : $(undefined);
  954. if (shouldHideOverlay) {
  955. if (hideOptions.duration) {
  956. overlay.kendoStop().kendoAnimate({
  957. effects: { fadeOut: { properties: { opacity: 0 } } },
  958. duration: hideOptions.duration,
  959. hide: true
  960. });
  961. } else {
  962. overlay.hide();
  963. }
  964. } else if (modalWindows.length) {
  965. windowObject(modalWindows.eq(modalWindows.length - 2))._overlay(true);
  966. }
  967. wrapper.kendoStop().kendoAnimate({
  968. effects: hideOptions.effects || showOptions.effects,
  969. reverse: hideOptions.reverse === true,
  970. duration: hideOptions.duration,
  971. complete: function() {
  972. wrapper.hide();
  973. that.trigger(DEACTIVATE);
  974. }
  975. });
  976. }
  977. if (that.options.isMaximized) {
  978. $("html, body").css(OVERFLOW, "");
  979. if (this._documentScrollTop && this._documentScrollTop > 0) {
  980. $(document).scrollTop(this._documentScrollTop);
  981. }
  982. }
  983. return that;
  984. },
  985. /**
  986. *
  987. * Brings forward a Window to the top of the z-index.
  988. *
  989. * @returns {Window}
  990. * Returns the (Kendo UI) Window object to support chaining.
  991. *
  992. * @exampleTitle Bring forward a Window; utilize chaining (if necessary)
  993. * @example
  994. * var kendoWindow = $("#window").data("kendoWindow").toFront();
  995. *
  996. */
  997. toFront: function () {
  998. var that = this,
  999. wrapper = that.wrapper,
  1000. currentWindow = wrapper[0],
  1001. zIndex = +wrapper.css(ZINDEX),
  1002. originalZIndex = zIndex;
  1003. $(KWINDOW).each(function(i, element) {
  1004. var windowObject = $(element),
  1005. zIndexNew = windowObject.css(ZINDEX),
  1006. contentElement = windowObject.find(KWINDOWCONTENT);
  1007. if (!isNaN(zIndexNew)) {
  1008. zIndex = Math.max(+zIndexNew, zIndex);
  1009. }
  1010. // Add overlay to windows with iframes and lower z-index to prevent
  1011. // trapping of events when resizing / dragging
  1012. if (element != currentWindow && contentElement.find("> ." + KCONTENTFRAME).length > 0) {
  1013. contentElement.append(templates.overlay);
  1014. }
  1015. });
  1016. if (zIndex == 10001 || originalZIndex < zIndex) {
  1017. wrapper.css(ZINDEX, zIndex + 2);
  1018. that.element.find("> .k-overlay").remove();
  1019. }
  1020. return that;
  1021. },
  1022. /**
  1023. *
  1024. * Toggles a Window between a maximized and restored state. Triggers the resize event.
  1025. *
  1026. * @returns {Window}
  1027. * Returns the (Kendo UI) Window object to support chaining.
  1028. *
  1029. * @exampleTitle Toggle the state of a Window; utilize chaining (if necessary)
  1030. * @example
  1031. * var kendoWindow = $("#window").data("kendoWindow").toggleMaximization();
  1032. *
  1033. */
  1034. toggleMaximization: function () {
  1035. return this[this.options.isMaximized ? "restore" : "maximize"]();
  1036. },
  1037. /**
  1038. *
  1039. * Restores a maximized or minimized Window to its previous state. Triggers the resize event.
  1040. *
  1041. * @returns {Window}
  1042. * Returns the (Kendo UI) Window object to support chaining.
  1043. *
  1044. * @exampleTitle Restore the state of a Window; utilize chaining (if necessary)
  1045. * @example
  1046. * var kendoWindow = $("#window").data("kendoWindow").restore();
  1047. *
  1048. */
  1049. restore: function () {
  1050. var that = this,
  1051. options = that.options,
  1052. restoreOptions = that.restoreOptions;
  1053. if (!options.isMaximized && !options.isMinimized) {
  1054. return;
  1055. }
  1056. that.wrapper
  1057. .css({
  1058. position: "absolute",
  1059. left: restoreOptions.left,
  1060. top: restoreOptions.top,
  1061. width: restoreOptions.width,
  1062. height: restoreOptions.height
  1063. })
  1064. .find(".k-window-content,.k-resize-handle").show().end()
  1065. .find(".k-window-titlebar .k-i-restore").parent().remove().end().end()
  1066. .find(MINIMIZE_MAXIMIZE).parent().show();
  1067. $("html, body").css(OVERFLOW, "");
  1068. if (this._documentScrollTop && this._documentScrollTop > 0) {
  1069. $(document).scrollTop(this._documentScrollTop);
  1070. }
  1071. options.isMaximized = options.isMinimized = false;
  1072. that.trigger(RESIZE);
  1073. return that;
  1074. },
  1075. /**
  1076. *
  1077. * Maximizes a Window to the entire viewing area of the user agent. Triggers the resize event.
  1078. *
  1079. * @function
  1080. * @returns {Window}
  1081. * Returns the (Kendo UI) Window object to support chaining.
  1082. *
  1083. * @exampleTitle Maximize a Window
  1084. * @example
  1085. * $("#window").data("kendoWindow").maximize();
  1086. *
  1087. */
  1088. maximize: sizingAction("maximize", function() {
  1089. var that = this,
  1090. wrapper = that.wrapper,
  1091. position = wrapper.position();
  1092. extend(that.restoreOptions, {
  1093. left: position.left,
  1094. top: position.top
  1095. });
  1096. wrapper.css({
  1097. left: 0,
  1098. top: 0,
  1099. position: "fixed"
  1100. });
  1101. this._documentScrollTop = $(document).scrollTop();
  1102. $("html, body").css(OVERFLOW, HIDDEN);
  1103. that.options.isMaximized = true;
  1104. that._onDocumentResize();
  1105. }),
  1106. /**
  1107. *
  1108. * Maximizes a Window to its title bar.
  1109. *
  1110. * @function
  1111. * @returns {Window}
  1112. * Returns the (Kendo UI) Window object to support chaining.
  1113. *
  1114. * @exampleTitle Minimize a Window
  1115. * @example
  1116. * $("#window").data("kendoWindow").minimize();
  1117. *
  1118. */
  1119. minimize: sizingAction("minimize", function() {
  1120. var that = this;
  1121. that.wrapper.css("height", "");
  1122. that.element.hide();
  1123. that.options.isMinimized = true;
  1124. }),
  1125. _onDocumentResize: function () {
  1126. var that = this,
  1127. wrapper = that.wrapper,
  1128. wnd = $(window);
  1129. if (!that.options.isMaximized) {
  1130. return;
  1131. }
  1132. wrapper.css({
  1133. width: wnd.width(),
  1134. height: wnd.height() - parseInt(wrapper.css("padding-top"), 10)
  1135. });
  1136. that.trigger(RESIZE);
  1137. },
  1138. /**
  1139. *
  1140. * Refreshes the content of a Window from a remote URL.
  1141. *
  1142. * @param {Object|String} options
  1143. * Options for requesting data from the server.
  1144. * If omitted, the window uses the <code>content</code> property
  1145. * that was supplied when the window was created.
  1146. * Any options specified here are passed to jQuery.ajax().
  1147. *
  1148. * @param {String} options.url
  1149. * The server URL that will be requested.
  1150. *
  1151. * @param {Object} options.data
  1152. * A JSON object containing the data that will be passed to the server.
  1153. *
  1154. * @param {String} options.type
  1155. * The HTTP request method ("GET", "POST").
  1156. *
  1157. * @param {String} options.template
  1158. * A template to be used for displaying the requested data.
  1159. *
  1160. * @returns {Window}
  1161. * Returns the (Kendo UI) Window object to support chaining.
  1162. *
  1163. * @example
  1164. * var windowObject = $("#window").data("kendoWindow");
  1165. * windowObject.refresh("/feedbackForm");
  1166. *
  1167. * windowObject.refresh({
  1168. * url: "/feedbackForm",
  1169. * data: { userId: 42 }
  1170. * });
  1171. *
  1172. * windowObject.refresh({
  1173. * url: "/userInfo",
  1174. * data: { userId: 42 },
  1175. * template: "Hello, #= firstName # #= lastName #"
  1176. * });
  1177. *
  1178. */
  1179. refresh: function (options) {
  1180. var that = this,
  1181. initOptions = that.options,
  1182. element = $(that.element),
  1183. iframe,
  1184. showIframe = initOptions.iframe,
  1185. url;
  1186. if (!isPlainObject(options)) {
  1187. options = { url: options };
  1188. }
  1189. options = extend({}, initOptions.content, options);
  1190. url = options.url;
  1191. if (url) {
  1192. if (typeof showIframe == "undefined") {
  1193. showIframe = !isLocalUrl(url);
  1194. }
  1195. if (!showIframe) {
  1196. // perform AJAX request
  1197. that._ajaxRequest(options);
  1198. } else {
  1199. iframe = element.find("." + KCONTENTFRAME)[0];
  1200. if (iframe) {
  1201. // refresh existing iframe
  1202. iframe.src = url || iframe.src;
  1203. } else {
  1204. // render new iframe
  1205. element.html(templates.contentFrame(extend({}, initOptions, { content: options })));
  1206. }
  1207. }
  1208. } else if (options.template) {
  1209. // refresh template
  1210. that.content(template(options.template)({}));
  1211. }
  1212. return that;
  1213. },
  1214. _ajaxRequest: function (options) {
  1215. var that = this,
  1216. contentTemplate = options.template,
  1217. refreshIcon = that.wrapper.find(".k-window-titlebar .k-i-refresh"),
  1218. loadingIconTimeout = setTimeout(function () {
  1219. refreshIcon.addClass(LOADING);
  1220. }, 100);
  1221. $.ajax(extend({
  1222. type: "GET",
  1223. dataType: "html",
  1224. cache: false,
  1225. error: proxy(function (xhr, status) {
  1226. that.trigger(ERROR);
  1227. }, that),
  1228. complete: function () {
  1229. clearTimeout(loadingIconTimeout);
  1230. refreshIcon.removeClass(LOADING);
  1231. },
  1232. success: proxy(function (data, textStatus) {
  1233. if (contentTemplate) {
  1234. data = template(contentTemplate)(data || {});
  1235. }
  1236. that.element.html(data);
  1237. that.trigger(REFRESH);
  1238. }, that)
  1239. }, options));
  1240. },
  1241. /**
  1242. * Destroys the window and its modal overlay, if necessary. Removes the Window HTML elements from the DOM.
  1243. */
  1244. destroy: function () {
  1245. var that = this,
  1246. modalWindows,
  1247. shouldHideOverlay;
  1248. that.wrapper.remove();
  1249. modalWindows = openedModalWindows();
  1250. shouldHideOverlay = that.options.modal && !modalWindows.length;
  1251. if (shouldHideOverlay) {
  1252. that._overlay(false).remove();
  1253. } else if (modalWindows.length > 0) {
  1254. windowObject(modalWindows.eq(modalWindows.length - 2))._overlay(true);
  1255. }
  1256. },
  1257. _createWindow: function