diff --git a/common/schemas/keyman-touch-layout/README.md b/common/schemas/keyman-touch-layout/README.md index 193dc6a3b8..ba33ce9cb2 100644 --- a/common/schemas/keyman-touch-layout/README.md +++ b/common/schemas/keyman-touch-layout/README.md @@ -42,7 +42,8 @@ The general structure of a .keyman-touch-layout file is: ## `root` object The `root` object may contain up to three properties, each being a [`platform` -object](#platform-object), named `"phone"`, `"tablet"` or `"desktop"`. +object](#platform-object), named `"phone"`, `"tablet"` or `"desktop"`. There +must be at least one property. ## `platform` object @@ -68,7 +69,7 @@ optionally contain three additional properties: `font`, `fontsize`, and `displayUnderlying`. * `layer` -: An array of [`layer` objects](#layer-object). Required. +: A non-empty array of [`layer` objects](#layer-object). Required. * `font` : An optional CSS-style font-family specification, being the name of the font to @@ -83,6 +84,29 @@ optionally contain three additional properties: `font`, `fontsize`, and : A boolean value, if `true`, then the base layout's key cap will be displayed in the top left of the key cap. Defaults to `false`. +* `defaultHint` + +: A string value. Default is `"dot"`. Controls the display of the hint text on + the key cap, which is shown at the top right of the key cap. + + * `"none"`: show no hint on the key cap. + * `"dot"`: show a dot on top-right of key cap if a longpress menu is + available, default. Matches behavior for Keyman 15.0 and earlier. + * `"longpress"`: show the default longpress key cap, if it exists. + * `"multitap"`: show the first multitap key cap, if it exists. + * `"flick"`: show the first flick key cap, selected in clockwise order, + starting from North. + * `"flick-n"`: show the key cap from the North flick, if it exists. + * `"flick-ne"`: show the key cap from the North-East flick, if it exists. + * `"flick-e"`: show the key cap from the East flick, if it exists. + * `"flick-se"`: show the key cap from the South-East flick, if it exists. + * `"flick-s"`: show the key cap from the South flick, if it exists. + * `"flick-sw"`: show the key cap from the South-West flick, if it exists. + * `"flick-w"`: show the key cap from the West flick, if it exists. + * `"flick-nw"`: show the key cap from the North-West flick, if it exists. + + Introduced in Keyman 16.0. + ## `layer` object The `layer` object describes one visible layer on a touch keyboard. It has two @@ -140,7 +164,7 @@ affect the modifiers in any key events generated by keys on the layer. * `row` -: An array of [`row` objects](#row-object). Required. +: A non-empty array of [`row` objects](#row-object). Required. ## `row` object @@ -150,19 +174,19 @@ properties: `id` and `key`. * `id` : An non-negative integer denoting where the row appears, with `0` being the top - row. + row. Required. Legacy: this value was sometimes an integer in a string. This string format is deprecated and will not be supported in future versions of Keyman Developer. * `key` -: An array of [`key` objects](#key-object). +: A non-empty array of [`key` objects](#key-object). Required. ## `key` object Describes a single key on a touch layout row. See also [`sk` -object](#sk-object). A `key` object has no required properties. +object](#sk-object). A `key` object must include either an `id` or `sp` property. * `id` @@ -201,6 +225,13 @@ object](#sk-object). A `key` object has no required properties. : String. The string displayed on the key cap. +* `hint` + +: String. If present, a small hint, often shown at top right of key cap. + + Introduced in Keyman 16.0. + + * `layer` : String. If specified, overrides the modifier associated with the layer (this @@ -291,19 +322,24 @@ object](#sk-object). A `key` object has no required properties. : If present, defines additional keys that may be selected when using a flick gesture on the key, with a [`flick` object](#flick-object). Flicks - should not be used on modifier keys, special keys, or the Spacebar. Keyman 16+. + should not be used on modifier keys, special keys, or the Spacebar. + + Introduced in Keyman 16.0. * `multitap` : If present, defines an array of keys that may be selected sequentially when tapping multiple times on the key, an array of [`sk` objects](#sk-object). - Multitaps generally should not be used on modifier keys, special keys, or the + Multitaps may not be used on layer switch keys, special keys such as the globe key, or the Spacebar. Beware of mixing multitaps with layer switching, as this can lead to - a confusing user experience. Keyman 16+. + a confusing user experience. Keyman 15+: the Shift key has a predefined multitap sequence to access the `caps` layer, which is available if the `caps` layer is present. This is the - only multitap sequence supported in Keyman 15. + only multitap sequence supported in Keyman 15. This multitap sequence cannot + be overridden, and is the sole case where multitap input may cause a layer switch. + + Introduced in Keyman 16.0. ## `sk` object @@ -314,7 +350,9 @@ properties are not fully supported as of Keyman 15: `font`, `fontsize`, `pad`, and `width`. * `id` -: A string identifier for the longpress key. See `key` object for details. + +: String. Required. An identifier for the longpress key. See `key` object for + details. * `text` @@ -408,7 +446,7 @@ string") into the appropriate spec format. # .keyman-touch-layout version history ## 2022-06-30 2.0 stable -* Add support for flick and multitap. Aligns with Keyman 16.0. +* Add support for flick, multitap, hint, defaultHint. Aligns with Keyman 16.0. ## 2022-06-27 1.0 stable * Initial schema version and full documentation diff --git a/common/schemas/keyman-touch-layout/keyman-touch-layout.clean.spec.json b/common/schemas/keyman-touch-layout/keyman-touch-layout.clean.spec.json index 4647b57c53..0aec7c9d1c 100644 --- a/common/schemas/keyman-touch-layout/keyman-touch-layout.clean.spec.json +++ b/common/schemas/keyman-touch-layout/keyman-touch-layout.clean.spec.json @@ -11,7 +11,9 @@ "tablet": { "$ref": "#/definitions/platform" }, "phone": { "$ref": "#/definitions/platform" }, "desktop": { "$ref": "#/definitions/platform" } - } + }, + "minProperties": 1, + "additionalProperties": false }, "platform": { @@ -20,7 +22,8 @@ "font": { "$ref": "#/definitions/font-spec" }, "fontsize": { "$ref": "#/definitions/fontsize-spec" }, "layer": { "$ref": "#/definitions/layers" }, - "displayUnderlying": { "type": "boolean" } + "displayUnderlying": { "type": "boolean" }, + "defaultHint": { "type": "string", "enum": ["none","dot","longpress","multitap","flick","flick-n","flick-ne","flick-e","flick-se","flick-s","flick-sw","flick-w","flick-nw"] } }, "required": ["layer"], "additionalProperties": false @@ -28,7 +31,8 @@ "layers": { "type": "array", - "items": { "$ref": "#/definitions/layer" } + "items": { "$ref": "#/definitions/layer" }, + "minItems": 1 }, "layer": { @@ -48,7 +52,8 @@ "rows": { "type": "array", - "items": { "$ref": "#/definitions/row" } + "items": { "$ref": "#/definitions/row" }, + "minItems": 1 }, "row": { @@ -69,7 +74,8 @@ "keys": { "type": "array", - "items": { "$ref": "#/definitions/key" } + "items": { "$ref": "#/definitions/key" }, + "minItems": 1 }, "key": { @@ -86,8 +92,16 @@ "width": { "$ref" : "#/definitions/key-width" }, "sk": { "$ref": "#/definitions/subkeys" }, "flick": { "$ref": "#/definitions/flick" }, - "multitap": { "$ref": "#/definitions/subkeys" } + "multitap": { "$ref": "#/definitions/subkeys" }, + "hint": { "type": "string" } }, + "anyOf": [ + {"required": ["id"]}, + {"required": ["sp"]}, + {"required": ["sk"]}, + {"required": ["flick"]}, + {"required": ["multitap"]} + ], "additionalProperties": false }, @@ -98,24 +112,25 @@ "key-sp": { "type": "integer", - "enum": [0, 1, 2, 8, 9, 10], + "enum": [0, 1, 2, 8, 9, 10] }, "key-pad": { "type": "number", "minimum": 0, - "maximum": 10000 + "maximum": 100000 }, "key-width": { "type": "number", "minimum": 0, - "maximum": 1000 + "maximum": 100000 }, "subkeys": { "type": "array", - "items": { "$ref": "#/definitions/subkey" } + "items": { "$ref": "#/definitions/subkey" }, + "minItems": 1 }, "subkey": { @@ -140,6 +155,7 @@ "patternProperties": { "^(n|s|e|w|ne|nw|se|sw)$": { "$ref": "#/definitions/subkey" } }, + "minProperties": 1, "additionalProperties": false }, diff --git a/common/schemas/keyman-touch-layout/keyman-touch-layout.spec.json b/common/schemas/keyman-touch-layout/keyman-touch-layout.spec.json index 6fa427181a..a7fc1772dc 100644 --- a/common/schemas/keyman-touch-layout/keyman-touch-layout.spec.json +++ b/common/schemas/keyman-touch-layout/keyman-touch-layout.spec.json @@ -20,7 +20,8 @@ "font": { "$ref": "#/definitions/font-spec" }, "fontsize": { "$ref": "#/definitions/fontsize-spec" }, "layer": { "$ref": "#/definitions/layers" }, - "displayUnderlying": { "type": "boolean" } + "displayUnderlying": { "type": "boolean" }, + "defaultHint": { "type": "string", "enum": ["none","dot","longpress","multitap","flick","flick-n","flick-ne","flick-e","flick-se","flick-s","flick-sw","flick-w","flick-nw"] } }, "required": ["layer"], "additionalProperties": false @@ -95,7 +96,8 @@ "width": { "$ref" : "#/definitions/numeric" }, "sk": { "$ref": "#/definitions/subkeys" }, "flick": { "$ref": "#/definitions/flick" }, - "multitap": { "$ref": "#/definitions/subkeys" } + "multitap": { "$ref": "#/definitions/subkeys" }, + "hint": { "type": "string" } }, "additionalProperties": false }, diff --git a/developer/src/tike/child/UfrmKeymanWizard.pas b/developer/src/tike/child/UfrmKeymanWizard.pas index 859692b833..c7d81d5fc1 100644 --- a/developer/src/tike/child/UfrmKeymanWizard.pas +++ b/developer/src/tike/child/UfrmKeymanWizard.pas @@ -3323,6 +3323,7 @@ begin PromptChange := APromptChange; if ShowModal = mrOk then begin + frameTouchLayout.SaveToString; frameTouchLayout.TemplateFileName := TemplateFileName; frameTouchLayout.Load('', True, False); // I4034 Self.Modified := True; diff --git a/developer/src/tike/compile/CompileKeymanWeb.pas b/developer/src/tike/compile/CompileKeymanWeb.pas index c8c354012c..76fcd8398f 100644 --- a/developer/src/tike/compile/CompileKeymanWeb.pas +++ b/developer/src/tike/compile/CompileKeymanWeb.pas @@ -1672,6 +1672,7 @@ var FSubKey: TTouchLayoutSubKey; FRequiredKeys: set of TRequiredKey; FDictionary: TStringList; + FDirection: TTouchLayoutFlickDirection; function IsValidUnicodeValue(ch: Integer): Boolean; // I4198 begin @@ -1873,6 +1874,11 @@ begin CheckKey(FKey.Id, FKey.Text, FKey.NextLayer, FKey.SpT); // I4119 for FSubKey in FKey.Sk do CheckKey(FSubKey.Id, FKey.Text, FSubKey.NextLayer, FSubKey.SpT); // I4119 + for FDirection in FKey.Flick.Keys do + CheckKey(FKey.Flick[FDirection].Id, FKey.Flick[FDirection].Text, + FKey.Flick[FDirection].NextLayer, FKey.Flick[FDirection].SpT); + for FSubKey in FKey.MultiTap do + CheckKey(FSubKey.Id, FKey.Text, FSubKey.NextLayer, FSubKey.SpT); end; if FRequiredKeys <> CRequiredKeys then diff --git a/developer/src/tike/http/Keyman.Developer.System.HttpServer.AppSource.pas b/developer/src/tike/http/Keyman.Developer.System.HttpServer.AppSource.pas index 088b2062fd..723d1ec369 100644 --- a/developer/src/tike/http/Keyman.Developer.System.HttpServer.AppSource.pas +++ b/developer/src/tike/http/Keyman.Developer.System.HttpServer.AppSource.pas @@ -191,7 +191,7 @@ var begin doc := ARequestInfo.Document; Delete(doc, 1, Length('/app/source/toucheditor/lib/')); - if (Pos('/', doc) > 0) or (Pos('\', doc) > 0) then + if Pos('..', doc) > 0 then Respond404(AContext, ARequestInfo, AResponseInfo) else RespondFile(GetLayoutBuilderPath + doc, AContext, ARequestInfo, AResponseInfo); diff --git a/developer/src/tike/main/Keyman.Developer.System.KeymanDeveloperPaths.pas b/developer/src/tike/main/Keyman.Developer.System.KeymanDeveloperPaths.pas index 0d273ad6d7..0e6b63c379 100644 --- a/developer/src/tike/main/Keyman.Developer.System.KeymanDeveloperPaths.pas +++ b/developer/src/tike/main/Keyman.Developer.System.KeymanDeveloperPaths.pas @@ -36,7 +36,7 @@ var KeymanRoot: string; begin if TKeymanPaths.RunningFromSource(KeymanRoot) - then Result := KeymanRoot + 'developer\src\inst\dist\node.exe' + then Result := KeymanRoot + 'developer\src\inst\node\dist\node.exe' else Result := ExtractFilePath(ParamStr(0)) + 'node.js\node.exe'; end; diff --git a/developer/src/tike/oskbuilder/TouchLayout.pas b/developer/src/tike/oskbuilder/TouchLayout.pas index f7aa833d26..e335c7634d 100644 --- a/developer/src/tike/oskbuilder/TouchLayout.pas +++ b/developer/src/tike/oskbuilder/TouchLayout.pas @@ -1,18 +1,18 @@ (* Name: TouchLayout Copyright: Copyright (C) SIL International. - Documentation: - Description: + Documentation: + Description: Create Date: 29 Nov 2013 Modified Date: 27 May 2015 Authors: mcdurdin - Related Files: - Dependencies: + Related Files: + Dependencies: - Bugs: - Todo: - Notes: + Bugs: + Todo: + Notes: History: 29 Nov 2013 - mcdurdin - I3982 - V9.0 - Touch layout editor should not override special keys when swapping layouts 07 Feb 2014 - mcdurdin - I4035 - V9.0 - Parsing of UTF-8 in JSON layout file crashes TIKE 21 Feb 2014 - mcdurdin - I4060 - V9.0 - KeymanWeb compiler should validate the layout file @@ -34,6 +34,19 @@ type ETouchLayoutValidate = class(Exception) end; + TTouchLayoutFlickDirection = ( + tlfdNorth, tlfdSouth, tlfdEast, tlfdWest, + tlfdNorthEast, tlfdNorthWest, + tlfdSouthEast, tlfdSouthWest + ); + +const + STouchLayoutFlickDirectionName: array[TTouchLayoutFlickDirection] of string = ( + 'n', 's', 'e', 'w', + 'ne', 'nw', + 'se', 'sw' + ); + type // TouchKeyType TTouchKeyType = (tktNormal = 0, tktSpecial = 1, tktSpecialActive = 2, tktDeadkey = 8, tktBlank = 9, tktSpacer = 10); // I4119 @@ -105,6 +118,12 @@ type TTouchLayoutSubKeys = class(TObjectList) end; + TTouchLayoutMultiTaps = class(TObjectList) + end; + + TTouchLayoutFlicks = class(TObjectDictionary) + end; + TTouchLayoutKey = class(TTouchLayoutObject) private FNextLayer: string; @@ -117,7 +136,10 @@ type FPad: Integer; FSp: Integer; FSk: TTouchlayoutSubKeys; + FFlick: TTouchLayoutFlicks; + FMultiTap: TTouchLayoutMultiTaps; FText: string; + FHint: string; function GetSpT: TTouchKeyType; // I4119 procedure SetSpT(const Value: TTouchKeyType); // I4119 protected @@ -128,6 +150,7 @@ type destructor Destroy; override; property Id: string read FId write FId; property Text: string read FText write FText; + property Hint: string read FHint write FHint; property Sp: Integer read FSp write FSp; property SpT: TTouchKeyType read GetSpT write SetSpT; // I4119 property Width: Integer read FWidth write FWidth; @@ -138,6 +161,8 @@ type property Font: string read FFont write FFont; property FontSize: string read FFontSize write FFontSize; property Sk: TTouchlayoutSubKeys read FSk; + property Flick: TTouchLayoutFlicks read FFlick; + property MultiTap: TTouchLayoutMultiTaps read FMultiTap; end; TTouchLayoutKeys = class(TObjectList) @@ -181,12 +206,26 @@ type function IndexOfId(const AId: string): Integer; end; + TTouchLayoutDefaultHint = ( + tldhNone, tldhLongpress, tldhMultitap, tldhFlick, + tldhFlickN, tldhFlickNE, tldhFlickE, tldhFlickSE, tldhFlickS, tldhFlickSW, tldhFlickW, tldhFlickNW + ); + +const + STouchLayoutDefaultHintName: array[TTouchLayoutDefaultHint] of string = + ('none','longpress','multitap','flick','flick-n','flick-ne','flick-e','flick-se','flick-s','flick-sw','flick-w','flick-nw'); + + +function DefaultHintFromString(const s: string): TTouchLayoutDefaultHint; + +type TTouchLayoutPlatform = class(TTouchLayoutObject) private FName: string; FLayers: TTouchLayoutLayers; FFontSize: string; // I4062 FDisplayUnderlying: Boolean; + FDefaultHint: TTouchLayoutDefaultHint; FFont: string; protected procedure DoRead; override; @@ -195,6 +234,7 @@ type constructor Create(AParent: TTouchLayoutObject); override; destructor Destroy; override; property DisplayUnderlying: Boolean read FDisplayUnderlying write FDisplayUnderlying; + property DefaultHint: TTouchLayoutDefaultHint read FDefaultHint write FDefaultHint; property Name: string read FName write FName; property Font: string read FFont write FFont; property FontSize: string read FFontSize write FFontSize; // I4062 @@ -747,10 +787,15 @@ begin end; procedure TTouchLayoutPlatform.DoRead; +var + s: string; begin GetValue('font', FFont); GetValue('fontsize', FFontSize); GetValue('displayUnderlying', FDisplayUnderlying); + if GetValue('defaultHint', s) + then FDefaultHint := DefaultHintFromString(s) + else FDefaultHint := tldhNone; ReadArray('layer', TTouchLayoutLayer, procedure (obj: TTouchLayoutObject) begin FLayers.Add(obj as TTouchLayoutLayer); end); end; @@ -764,6 +809,8 @@ begin AddJSONValue(JSON, 'font', FFont); AddJSONValue(JSON, 'fontsize', FFontSize); AddJSONValue(JSON, 'displayUnderlying', FDisplayUnderlying); + if FDefaultHint <> tldhNone then + AddJSONValue(JSON, 'defaultHint', STouchLayoutDefaultHintName[FDefaultHint]); if FLayers.Count > 0 then begin @@ -831,15 +878,24 @@ constructor TTouchLayoutKey.Create(AParent: TTouchLayoutObject); begin inherited Create(AParent); FSk := TTouchLayoutSubKeys.Create; + FFlick := TTouchLayoutFlicks.Create; + FMultiTap := TTouchLayoutMultiTaps.Create; end; destructor TTouchLayoutKey.Destroy; begin FreeAndNil(FSk); + FreeAndNil(FFlick); + FreeAndNil(FMultiTap); inherited Destroy; end; procedure TTouchLayoutKey.DoRead; +var + v: TJSONValue; + o: TJSONObject; + d: TTouchLayoutFlickDirection; + sk: TTouchLayoutSubKey; begin GetValue('nextlayer', FNextLayer); GetValue('fontsize', FFontSize); @@ -851,15 +907,33 @@ begin GetValue('pad', FPad); GetValue('sp', FSp); GetValue('text', FText); + GetValue('hint', FHint); ReadArray('sk', TTouchLayoutSubKey, procedure (obj: TTouchLayoutObject) begin FSk.Add(obj as TTouchLayoutSubKey); end); + if GetValue('flick', v) and (v is TJSONObject) then + begin + o := v as TJSONObject; + for d := Low(TTouchLayoutFlickDirection) to High(TTouchLayoutFlickDirection) do + begin + v := o.GetValue(STouchLayoutFlickDirectionName[d]); + if Assigned(v) and (v is TJSONObject) then + begin + sk := TTouchLayoutSubKey.Create(Self); + sk.Read(v as TJSONObject); + FFlick.Add(d, sk); + end; + end; + end; + ReadArray('multitap', TTouchLayoutSubKey, + procedure (obj: TTouchLayoutObject) begin FMultiTap.Add(obj as TTouchLayoutSubKey); end); end; procedure TTouchLayoutKey.DoWrite(JSON: TJSONObject); var i: Integer; v: TJSONArray; - o: TJSONObject; + o, f: TJSONObject; + d: TTouchLayoutFlickDirection; begin AddJSONValue(JSON, 'nextlayer', FNextLayer); AddJSONValue(JSON, 'fontsize', FFontSize); @@ -871,6 +945,7 @@ begin if FPad <> 0 then AddJSONValue(JSON, 'pad', IntToStr(FPad)); if FSp <> 0 then AddJSONValue(JSON, 'sp', IntToStr(FSp)); AddJSONValue(JSON, 'text', FText); + AddJSONValue(JSON, 'hint', FHint); if FSk.Count > 0 then begin @@ -883,6 +958,31 @@ begin end; JSON.AddPair('sk', v); end; + + if FFlick.Count > 0 then + begin + f := TJSONObject.Create; + for d in FFlick.Keys do + begin + o := TJSONObject.Create; + FFlick[d].Write(o); + f.AddPair(STouchLayoutFlickDirectionName[d], o); + end; + JSON.AddPair('flick', f); + end; + + if FMultiTap.Count > 0 then + begin + v := TJSONArray.Create; + for i := 0 to FMultiTap.Count - 1 do + begin + o := TJSONObject.Create; + FMultiTap[i].Write(o); + v.Add(o); + end; + JSON.AddPair('multitap', v); + end; + end; function TTouchLayoutKey.GetSpT: TTouchKeyType; // I4119 @@ -1016,4 +1116,11 @@ begin Result := -1; end; +function DefaultHintFromString(const s: string): TTouchLayoutDefaultHint; +begin + for Result := Low(TTouchLayoutDefaultHint) to High(TTouchLayoutDefaultHint) do + if s = STouchLayoutDefaultHintName[Result] then Exit; + Result := tldhNone; +end; + end. diff --git a/developer/src/tike/oskbuilder/TouchLayoutDefinitions.pas b/developer/src/tike/oskbuilder/TouchLayoutDefinitions.pas index 29d08b6098..eecfb09129 100644 --- a/developer/src/tike/oskbuilder/TouchLayoutDefinitions.pas +++ b/developer/src/tike/oskbuilder/TouchLayoutDefinitions.pas @@ -49,9 +49,21 @@ const (Name: 'fontsize'; ClassType: TJSONString) ); - KeyDef: array[0..10] of TJSONDef = ( + FlickDef: array[0..7] of TJSONDef = ( + (Name: 'nw'; ClassType: TJSONObject; Value: @SKDef; ValueSize: Length(SkDef)), + (Name: 'n'; ClassType: TJSONObject; Value: @SKDef; ValueSize: Length(SkDef)), + (Name: 'ne'; ClassType: TJSONObject; Value: @SKDef; ValueSize: Length(SkDef)), + (Name: 'w'; ClassType: TJSONObject; Value: @SKDef; ValueSize: Length(SkDef)), + (Name: 'e'; ClassType: TJSONObject; Value: @SKDef; ValueSize: Length(SkDef)), + (Name: 'sw'; ClassType: TJSONObject; Value: @SKDef; ValueSize: Length(SkDef)), + (Name: 's'; ClassType: TJSONObject; Value: @SKDef; ValueSize: Length(SkDef)), + (Name: 'se'; ClassType: TJSONObject; Value: @SKDef; ValueSize: Length(SkDef)) + ); + + KeyDef: array[0..13] of TJSONDef = ( (Name: 'id'; ClassType: TJSONString), (Name: 'text'; ClassType: TJSONString), + (Name: 'hint'; ClassType: TJSONString), (Name: 'sp'; ClassType: TJSONValue), (Name: 'width'; ClassType: TJSONValue), (Name: 'pad'; ClassType: TJSONValue), @@ -60,7 +72,9 @@ const (Name: 'nextlayer'; ClassType: TJSONString), (Name: 'font'; ClassType: TJSONString), (Name: 'fontsize'; ClassType: TJSONString), - (Name: 'sk'; ClassType: TJSONArray; Value: @SkDef[0]; ValueSize: Length(SkDef)) + (Name: 'sk'; ClassType: TJSONArray; Value: @SkDef[0]; ValueSize: Length(SkDef)), + (Name: 'flick'; ClassType: TJSONObject; Value: @FlickDef[0]; ValueSize: Length(FlickDef)), + (Name: 'multitap'; ClassType: TJSONArray; Value: @SkDef[0]; ValueSize: Length(SkDef)) ); RowDef: array[0..1] of TJSONDef = ( @@ -73,10 +87,11 @@ const (Name: 'row'; ClassType: TJSONArray; Required: True; Value: @RowDef[0]; ValueSize: Length(RowDef)) ); - PlatformDef: array[0..3] of TJSONDef = ( + PlatformDef: array[0..4] of TJSONDef = ( (Name: 'font'; ClassType: TJSONString), (Name: 'fontsize'; ClassType: TJSONString), // I4062 (Name: 'displayUnderlying'; ClassType: TJSONBool), + (Name: 'defaultHint'; ClassType: TJSONString), (Name: 'layer'; ClassType: TJSONArray; Required: True; Value: @LayerDef[0]; ValueSize: Length(LayerDef)) ); diff --git a/developer/src/tike/xml/layoutbuilder/builder-charmap.js b/developer/src/tike/xml/layoutbuilder/builder-charmap.js index 18e458229b..9e21054ab7 100644 --- a/developer/src/tike/xml/layoutbuilder/builder-charmap.js +++ b/developer/src/tike/xml/layoutbuilder/builder-charmap.js @@ -5,7 +5,7 @@ builder.dragDrop = {}; (function(builder, dragDrop) { dragDrop.isSubKey = function(key) { - return key.parent().attr('id') == 'sk'; + return key.data('type') != 'key'; }; dragDrop.getKeyElementFromElement = function(elem) { @@ -26,21 +26,24 @@ builder.dragDrop = {}; dragDrop.getKeyElementFromDragTarget = function(target) { let key = dragDrop.getKeyElementFromElement(target); - let isIdField = false; + let fieldType = 'text'; if(key) { key = $(key); } else { - if(target.id == 'inpKeyCap') { + if(target.id == 'inpKeyCap' || target.id == 'inpKeyCapUnicode') { key = builder.selectedKey(); } else if(target.id == 'inpKeyName') { key = builder.selectedKey(); - isIdField = true; - } else if(target.id == 'inpSubKeyCap') { + fieldType = 'id'; + } else if(target.id == 'inpKeyHint' || target.id == 'inpKeyHintUnicode') { + key = builder.selectedKey(); + fieldType = 'hint'; + } else if(target.id == 'inpSubKeyCap' || target.id == 'inpSubKeyCapUnicode') { key = builder.selectedSubKey(); } else if(target.id == 'inpSubKeyName') { key = builder.selectedSubKey(); - isIdField = true; + fieldType = 'id'; } if(!key) { @@ -48,7 +51,7 @@ builder.dragDrop = {}; } } - return { key: key, isIdField: isIdField }; + return { key: key, fieldType: fieldType }; }; dragDrop.charToUnicodeValue = function(s) { @@ -126,9 +129,12 @@ builder.dragDrop = {}; } } else { // Double-click insertion, so use last focused control - key = { key: builder.selectedSubKey(), isIdField: false }; - if(!key.key || !key.key.length) { - key = { key: builder.selectedKey(), isIdField: false }; + if(builder.lastFocus?.id == '#inpKeyHint' || builder.lastFocus?.id == '#inpKeyHintUnicode') { + key = { key: builder.selectedKey(), fieldType: 'hint' }; + } else if($.contains($('#subKeyToolbar')[0], builder.lastFocus)) { + key = { key: builder.selectedSubKey(), fieldType: 'text' }; + } else { + key = { key: builder.selectedKey(), fieldType: 'text' }; } } @@ -136,23 +142,27 @@ builder.dragDrop = {}; return false; } - const target = $(dragDrop.isSubKey(key.key) ? '#inpSubKeyCap' : '#inpKeyCap'); + const target = $( + key.fieldType == 'hint' ? '#inpKeyHint' : + dragDrop.isSubKey(key.key) ? '#inpSubKeyCap' : + '#inpKeyCap'); + const text = (o.shift ? target.val() : '') + o.text; // Focus the control and add the text - if(key.isIdField || key.key.data('id').startsWith('T_new_') || o.ctrl) { + if(key.fieldType == 'id' || key.key.data('id').startsWith('T_new_') || o.ctrl) { const idTarget = $(dragDrop.isSubKey(key.key) ? '#inpSubKeyName' : '#inpKeyName'); const chars = [...text]; // Split o.text into array of codepoints, keeping surrogate pairs together let id = chars.reduce((prev,curr) => prev+'_'+dragDrop.charToUnicodeValue(curr).toUpperCase(), 'U'); idTarget.val(id); - if(key.isIdField) { + if(key.fieldType == 'id') { idTarget.focus(); } idTarget.change(); } - if(!key.isIdField) { + if(!key.fieldType != 'id') { target.focus(); target.val(text); target.change(); diff --git a/developer/src/tike/xml/layoutbuilder/builder.css b/developer/src/tike/xml/layoutbuilder/builder.css index 71214e6791..60daff8f3c 100644 --- a/developer/src/tike/xml/layoutbuilder/builder.css +++ b/developer/src/tike/xml/layoutbuilder/builder.css @@ -1,4 +1,3 @@ - @font-face { font-family: KeymanwebOsk; font-style: normal; @@ -6,11 +5,23 @@ src: url('keymanweb-osk.ttf') format('truetype'); } +* { + box-sizing: border-box; +} + +#selKeyCapType, +#selSubKeyCapType { + font-family: KeymanwebOsk, Tahoma; + font-size: 10pt; +} + body { font-family: Tahoma; font-size: 18pt; padding: 0; margin: 0; + display: grid; + grid-template-columns: 152px 1fr; } .ui-dialog { @@ -33,6 +44,7 @@ body { padding-left: 97px; padding-bottom: 88px; padding-right: 108px; + width: 1024px; } #kbd.tablet-ipad-portrait { @@ -42,7 +54,8 @@ body { padding-top: 34px; padding-left: 99px; padding-bottom: 98px; - padding-right: 200px; + padding-right: 168px; + width: 800px; } #kbd.phone-iphone5-landscape { @@ -52,7 +65,8 @@ body { padding-left: 144px; padding-bottom: 40px; padding-top: 66px; - padding-right: 158px; + padding-right: 88px; + width: 1042px; } #kbd.phone-iphone5-portrait { @@ -62,7 +76,39 @@ body { padding-left: 92px; padding-bottom: 170px; padding-top: 70px; - padding-right: 108px; + padding-right: 116px; + width: 200px; +} + +.toolbar-item { + display: grid; + grid-template-columns: 90px 1fr; + vertical-align: baseline; + padding-bottom: 2px; +} + +.toolbar-item.toolbar-single-column { + grid-template-columns: 1fr; +} + +.toolbar-item.toolbar-2-small-buttons { + grid-template-columns: 1fr 24px 24px; + column-gap: 4px; +} + +.toolbar-item label { + padding: 0.75em 0; +} + +.toolbar-item select, +.toolbar-item input, +.toolbar-item button { + padding: 6px; + width: 100%; +} + +.toolbar-item button.emoji-button { + padding: 6px 0; } .key-droppable @@ -83,7 +129,8 @@ body { .key-droppable-hover { border: solid 1px #cccccc; margin-left: 3px; - width: 50px; + width: 75px; + background: #eeffee; } .key-dragging @@ -91,7 +138,8 @@ body { background: #cccccc !important; } -.key { +.key, +.key-placeholder { box-sizing: border-box; -moz-box-sizing: border-box; display: inline-block; @@ -109,13 +157,26 @@ body { left: 0; top: 0; } +.key-placeholder { + border-radius: 24px; + border-color: #cccccc; + color: #cccccc; +} + +.key-placeholder:hover { + background: #80ff80; + color: rgb(75, 185, 75); + border-color: rgb(75, 185, 75); + box-shadow: 0px 0px 20px rgba(75, 185, 75, 0.5); +} + .key .id { font-family: Tahoma; font-size: 10px; color: #8080f0; position: absolute; - bottom: 2px; - right: 4px; + bottom: 4px; + right: 3px; text-align: right; cursor: pointer; } @@ -130,25 +191,118 @@ body { text-align: left; } +.key .hint { + font-size: 12px; + position: absolute; + top: 2px; + right: 4px; + text-align: right; +} + +.key .hint.custom-hint { + color: #0cb901; +} + .key.key-modifier .id { color: #808080; } -.key .text { - +.has-multitap { + background: no-repeat url('multitap.svg') 0 0 / 100%; + position: absolute; + right: 2px; + bottom: 12px; + width: 10px; + height: 6px; } -.hasSubKeyArray { - background-image: url('skflag.png'); - background-position: top right; - background-repeat: no-repeat; +.has-longpress { + background: no-repeat url('longpress.svg') 0 0 / 100%; + position: absolute; + margin-left: 50%; + left: -5px; + top: 1px; + width: 10px; + height: 10px; } -.hasSubKeyArray.selected { - background-image: url('skflags.png'); +/* If we have both flick-n and longpress, we need to move the longpress icon down */ +.has-flick-n ~ .has-longpress { + top: 5px; +} + +.has-flick { + position: absolute; + display: block; + width: 5px; + height: 5px; +} + +.has-flick-nw { + background:no-repeat url('flick-nw.svg') 0 0 / 100%; + left: 1px; + top: 1px; +} + +.has-flick-n { + background:no-repeat url('flick-n.svg') 0 0 / 100%; + left: 50%; + margin-left: -2.5px; + top: 1px; +} + +.has-flick-ne { + background:no-repeat url('flick-ne.svg') 0 0 / 100%; + right: 1px; + top: 1px; +} + +.has-flick-w { + background:no-repeat url('flick-w.svg') 0 0 / 50%; + left: 1px; + top: 50%; + width: 7.5px; + height: 7.5px; + margin-top: -2.5px; +} + +.has-flick-e { + background:no-repeat url('flick-e.svg') 0 0 / 50%; + right: -1px; + top: 50%; + width: 7.5px; + height: 7.5px; + margin-top: -2.5px; +} + +.has-flick-sw { + background:no-repeat url('flick-sw.svg') 0 0 / 100%; + left: 1px; + bottom: 1px; +} + +.has-flick-s { + background:no-repeat url('flick-s.svg') 0 0 / 100%; + left: 50%; + margin-left: -2.5px; + bottom: -1px; +} + +.has-flick-se { + background:no-repeat url('flick-se.svg') 0 0 / 100%; + right: 1px; + bottom: 1px; +} + +.key:hover { + background: #e0e0ff; + color: #8080ff; + border-color: #8080ff !important; + box-shadow: 0px 0px 20px rgba(150, 150, 255, 0.5); } .key.selected { + background: #d0d0ff; border-color: #4040ff !important; box-shadow: 0px 0px 20px rgba(100, 100, 255, 0.5); } @@ -159,34 +313,105 @@ body { position: relative; } -#sk { - clear:left; +#sub-key-container { + display: grid; + grid-template-columns: 1fr 250px; + white-space: nowrap; + border-bottom: solid 1px black; + border-top: solid 1px black; +} + +#sub-key-groups > div, +#subKeyToolbar { + background-color: white; +} + +#sub-key-groups { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + column-gap: 1px; + background-color: black; +} + +#longpress, +#multitap { padding: 8px; margin: 0px 0px 8px; - min-height: 69px; - background: #eeeeee; + min-height: 64px; + display: flex; + flex-direction: row; + flex-wrap: wrap; +} + +#longpress, +#multitap, +#flick { + padding: 8px 0 8px 8px; + min-width: 256px; + box-sizing: border-box; +} + +#longpress .key-placeholder, +#multitap .key-placeholder { + order: 1; +} + +#kbd-container { + display: grid; + grid-template-columns: 1fr 250px; +} + +#kbd-scroll-container { overflow-x: auto; - white-space: nowrap; - border-top: solid 1px #333333; - position: relative; } #kbd { - float: left; padding: 8px; margin: 0px 0px 8px; background: #eeeeee; - overflow-x: auto; white-space: nowrap; + min-width: 770px; + box-sizing: border-box; } -#sk .key -{ +#longpress .key, +#flick .key, +.key-placeholder, +#multitap .key { height: 48px; - padding-top: 5px; margin-left: 3px; } +#longpress .key, +#flick .key, +#multitap .key { + padding-top: 5px; +} + +#flick { + display: grid; + grid-template-columns: max-content max-content max-content; + padding: 8px; + position: relative; +} + +#longpress .key, +#flick .key, +#multitap .key, +.key-placeholder { + width: 70px; + margin-right: 6px; + margin-bottom: 6px; + margin-top: 3px; +} + +.key-placeholder#flick-center, +.key-placeholder#flick-center:hover { + background-color: #cccccc; + border-color: #cccccc; + box-shadow: none; +} + .key-modifier { background: #dddddd; } .key-modifier-selected { background: #ddddff; } .key-deadkey { color: #000080; } @@ -210,23 +435,36 @@ br.clear { clear: both; } +#kbd-container, +#sub-key-container { + min-width: 1020px; +} + #toolbar div { background: #DCDCDD; - margin: -1px -1px -1px 0; - padding: 8px; - float: left; +} + +#toolbar h3 { + margin: 0; + padding: 0 0 4px 0; + font-size: 10pt; +} + +#toolbar #controlToolbar > div { + margin: 4px 0; + padding: 4px; + line-height: 1.4em; } #toolbar #layoutToolbar > div { - margin: 0; - padding: 0 8px; - border-left: 1px solid #444444; - line-height: 24px; + margin: 4px 0; + padding: 4px; + border-top: 1px solid #444444; + line-height: 1.4em; } button, input, select { font: 9pt Tahoma; - margin: 1px 2px; } button { @@ -240,9 +478,7 @@ button { } #keyToolbar, #subKeyToolbar { - margin: -9px 0px 0; padding: 8px; - clear: left; } #data { @@ -315,11 +551,11 @@ div#btnDelKey, div#btnDelSubKey { color: #FFFFFF; font-family: Tahoma; font-size: 10px; - height: 9px; - line-height: 6px; + height: 13px; + line-height: 8px; position: absolute; text-align: center; - width: 9px; + width: 13px; } div#btnDelKey:hover, div#btnDelSubKey:hover { @@ -327,7 +563,13 @@ div#btnDelKey:hover, div#btnDelSubKey:hover { border: 1px solid #ff0000; } -input#inpKeyCap, input#inpSubKeyCap { +body:not(.text-controls-in-toolbar) #key-cap-toolbar-item label, +body:not(.text-controls-in-toolbar) #sub-key-cap-toolbar-item label { + display: none; +} + +body:not(.text-controls-in-toolbar) input#inpKeyCap, +body:not(.text-controls-in-toolbar) input#inpSubKeyCap { font-size: 24px; z-index: 100; position: absolute; @@ -337,32 +579,90 @@ input#inpKeyCap, input#inpSubKeyCap { } .key-size { - color: white; - font: 9pt Calibri; - left: 100%; - margin-left: 16px; - margin-top: 16px; + font-family: Calibri; position: absolute; - top: 0; z-index: 10; line-height: 1em; } #kbd.phone-iphone5-portrait .key-size { - color: black; - margin-left: 48px; + left: 567px; + top: 16px; font-size: 8pt; + color: black; } #kbd.phone-iphone5-landscape .key-size { + left: 737px; + top: 8px; font-size: 8pt; - margin-left: 16px; - margin-top: 8px; - background: rgba(0,0,0,0.5); - border-radius: 2px; + color: white; } #kbd.tablet-ipad-portrait .key-size { - color: black; - margin-left: 90px; + left: 607px; + top: 20px; + font-size: 8pt; + color: white; } + +#kbd.tablet-ipad-landscape .key-size { + left: 836px; + top: 16px; + font-size: 9pt; + color: white; +} + +/* Position flick keys relative to the flick grid, by hand */ + +#flick .key { + position: absolute; +} + +.key.flick-nw { + left: 8px; + top: 8px; +} + +.key.flick-n { + left: 87px; + top: 8px; +} + +.key.flick-ne { + left: 166px; + top: 8px; +} + +.key.flick-w { + left: 8px; + top: 65px; +} + +.key.flick-e { + left: 166px; + top: 65px; +} + +.key.flick-sw { + left: 8px; + top: 122px; +} + +.key.flick-s { + left: 87px; + top: 122px; +} + +.key.flick-se { + left: 166px; + top: 122px; +} + +.tab { + font-size: 16px; + padding: 4px 0 0 4px; + display: block; + background: #DCDCDD; + padding: 4px 8px; +} \ No newline at end of file diff --git a/developer/src/tike/xml/layoutbuilder/builder.js b/developer/src/tike/xml/layoutbuilder/builder.js index a509bce809..561c4d6d0a 100644 --- a/developer/src/tike/xml/layoutbuilder/builder.js +++ b/developer/src/tike/xml/layoutbuilder/builder.js @@ -1,5 +1,3 @@ -window.builder = {}; - $(function() { (function(search) { var q = search.match(/Filename=(.+)(&|$)/); @@ -8,720 +6,10 @@ $(function() { } })(location.search); - this.undoStack = []; - this.redoStack = []; this.xscale = 1; this.yscale = 1; this.uniqId = 1; - this.standardKeyNames = [ - 'K_?00', // &H0 - 'K_LBUTTON', // &H1 - 'K_RBUTTON', // &H2 - 'K_CANCEL', // &H3 - 'K_MBUTTON', // &H4 - 'K_?05', // &H5 - 'K_?06', // &H6 - 'K_?07', // &H7 - 'K_BKSP', // &H8 - 'K_TAB', // &H9 - 'K_?0A', // &HA - 'K_?0B', // &HB - 'K_KP5', // &HC - 'K_ENTER', // &HD - 'K_?0E', // &HE - 'K_?0F', // &HF - 'K_SHIFT', // &H10 - 'K_CONTROL', // &H11 - 'K_ALT', // &H12 - 'K_PAUSE', // &H13 - 'K_CAPS', // &H14 - 'K_KANJI?15', // &H15 - 'K_KANJI?16', // &H16 - 'K_KANJI?17', // &H17 - 'K_KANJI?18', // &H18 - 'K_KANJI?19', // &H19 - 'K_?1A', // &H1A - 'K_ESC', // &H1B - 'K_KANJI?1C', // &H1C - 'K_KANJI?1D', // &H1D - 'K_KANJI?1E', // &H1E - 'K_KANJI?1F', // &H1F - 'K_SPACE', // &H20 - 'K_PGUP', // &H21 - 'K_PGDN', // &H22 - 'K_END', // &H23 - 'K_HOME', // &H24 - 'K_LEFT', // &H25 - 'K_UP', // &H26 - 'K_RIGHT', // &H27 - 'K_DOWN', // &H28 - 'K_SEL', // &H29 - 'K_PRINT', // &H2A - 'K_EXEC', // &H2B - 'K_PRTSCN', // &H2C - 'K_INS', // &H2D - 'K_DEL', // &H2E - 'K_HELP', // &H2F - 'K_0', // &H30 - 'K_1', // &H31 - 'K_2', // &H32 - 'K_3', // &H33 - 'K_4', // &H34 - 'K_5', // &H35 - 'K_6', // &H36 - 'K_7', // &H37 - 'K_8', // &H38 - 'K_9', // &H39 - 'K_?3A', // &H3A - 'K_?3B', // &H3B - 'K_?3C', // &H3C - 'K_?3D', // &H3D - 'K_?3E', // &H3E - 'K_?3F', // &H3F - 'K_?40', // &H40 - - 'K_A', // &H41 - 'K_B', // &H42 - 'K_C', // &H43 - 'K_D', // &H44 - 'K_E', // &H45 - 'K_F', // &H46 - 'K_G', // &H47 - 'K_H', // &H48 - 'K_I', // &H49 - 'K_J', // &H4A - 'K_K', // &H4B - 'K_L', // &H4C - 'K_M', // &H4D - 'K_N', // &H4E - 'K_O', // &H4F - 'K_P', // &H50 - 'K_Q', // &H51 - 'K_R', // &H52 - 'K_S', // &H53 - 'K_T', // &H54 - 'K_U', // &H55 - 'K_V', // &H56 - 'K_W', // &H57 - 'K_X', // &H58 - 'K_Y', // &H59 - 'K_Z', // &H5A - 'K_?5B', // &H5B - 'K_?5C', // &H5C - 'K_?5D', // &H5D - 'K_?5E', // &H5E - 'K_?5F', // &H5F - 'K_NP0', // &H60 - 'K_NP1', // &H61 - 'K_NP2', // &H62 - 'K_NP3', // &H63 - 'K_NP4', // &H64 - 'K_NP5', // &H65 - 'K_NP6', // &H66 - 'K_NP7', // &H67 - 'K_NP8', // &H68 - 'K_NP9', // &H69 - 'K_NPSTAR', // &H6A - 'K_NPPLUS', // &H6B - 'K_SEPARATOR', // &H6C - 'K_NPMINUS', // &H6D - 'K_NPDOT', // &H6E - 'K_NPSLASH', // &H6F - 'K_F1', // &H70 - 'K_F2', // &H71 - 'K_F3', // &H72 - 'K_F4', // &H73 - 'K_F5', // &H74 - 'K_F6', // &H75 - 'K_F7', // &H76 - 'K_F8', // &H77 - 'K_F9', // &H78 - 'K_F10', // &H79 - 'K_F11', // &H7A - 'K_F12', // &H7B - 'K_F13', // &H7C - 'K_F14', // &H7D - 'K_F15', // &H7E - 'K_F16', // &H7F - 'K_F17', // &H80 - 'K_F18', // &H81 - 'K_F19', // &H82 - 'K_F20', // &H83 - 'K_F21', // &H84 - 'K_F22', // &H85 - 'K_F23', // &H86 - 'K_F24', // &H87 - - 'K_?88', // &H88 - 'K_?89', // &H89 - 'K_?8A', // &H8A - 'K_?8B', // &H8B - 'K_?8C', // &H8C - 'K_?8D', // &H8D - 'K_?8E', // &H8E - 'K_?8F', // &H8F - - 'K_NUMLOCK', // &H90 - 'K_SCROLL', // &H91 - - 'K_?92', // &H92 - 'K_?93', // &H93 - 'K_?94', // &H94 - 'K_?95', // &H95 - 'K_?96', // &H96 - 'K_?97', // &H97 - 'K_?98', // &H98 - 'K_?99', // &H99 - 'K_?9A', // &H9A - 'K_?9B', // &H9B - 'K_?9C', // &H9C - 'K_?9D', // &H9D - 'K_?9E', // &H9E - 'K_?9F', // &H9F - 'K_?A0', // &HA0 - 'K_?A1', // &HA1 - 'K_?A2', // &HA2 - 'K_?A3', // &HA3 - 'K_?A4', // &HA4 - 'K_?A5', // &HA5 - 'K_?A6', // &HA6 - 'K_?A7', // &HA7 - 'K_?A8', // &HA8 - 'K_?A9', // &HA9 - 'K_?AA', // &HAA - 'K_?AB', // &HAB - 'K_?AC', // &HAC - 'K_?AD', // &HAD - 'K_?AE', // &HAE - 'K_?AF', // &HAF - 'K_?B0', // &HB0 - 'K_?B1', // &HB1 - 'K_?B2', // &HB2 - 'K_?B3', // &HB3 - 'K_?B4', // &HB4 - 'K_?B5', // &HB5 - 'K_?B6', // &HB6 - 'K_?B7', // &HB7 - 'K_?B8', // &HB8 - 'K_?B9', // &HB9 - - 'K_COLON', // &HBA - 'K_EQUAL', // &HBB - 'K_COMMA', // &HBC - 'K_HYPHEN', // &HBD - 'K_PERIOD', // &HBE - 'K_SLASH', // &HBF - 'K_BKQUOTE', // &HC0 - - 'K_?C1', // &HC1 - 'K_?C2', // &HC2 - 'K_?C3', // &HC3 - 'K_?C4', // &HC4 - 'K_?C5', // &HC5 - 'K_?C6', // &HC6 - 'K_?C7', // &HC7 - 'K_?C8', // &HC8 - 'K_?C9', // &HC9 - 'K_?CA', // &HCA - 'K_?CB', // &HCB - 'K_?CC', // &HCC - 'K_?CD', // &HCD - 'K_?CE', // &HCE - 'K_?CF', // &HCF - 'K_?D0', // &HD0 - 'K_?D1', // &HD1 - 'K_?D2', // &HD2 - 'K_?D3', // &HD3 - 'K_?D4', // &HD4 - 'K_?D5', // &HD5 - 'K_?D6', // &HD6 - 'K_?D7', // &HD7 - 'K_?D8', // &HD8 - 'K_?D9', // &HD9 - 'K_?DA', // &HDA - - 'K_LBRKT', // &HDB - 'K_BKSLASH', // &HDC - 'K_RBRKT', // &HDD - 'K_QUOTE', // &HDE - 'K_oDF', // &HDF - 'K_oE0', // &HE0 - 'K_oE1', // &HE1 - 'K_oE2', // &HE2 - 'K_oE3', // &HE3 - 'K_oE4', // &HE4 - - 'K_?E5', // &HE5 - - 'K_oE6', // &HE6 - - 'K_?E7', // &HE7 - 'K_?E8', // &HE8 - - 'K_oE9', // &HE9 - 'K_oEA', // &HEA - 'K_oEB', // &HEB - 'K_oEC', // &HEC - 'K_oED', // &HED - 'K_oEE', // &HEE - 'K_oEF', // &HEF - 'K_oF0', // &HF0 - 'K_oF1', // &HF1 - 'K_oF2', // &HF2 - 'K_oF3', // &HF3 - 'K_oF4', // &HF4 - 'K_oF5', // &HF5 - - 'K_?F6', // &HF6 - 'K_?F7', // &HF7 - 'K_?F8', // &HF8 - 'K_?F9', // &HF9 - 'K_?FA', // &HFA - 'K_?FB', // &HFB - 'K_?FC', // &HFC - 'K_?FD', // &HFD - 'K_?FE', // &HFE - 'K_?FF' // &HFF - ]; - - this.standardKeyCaps = [ - ['',''], // 'K_?00', // &H0 - ['',''], // 'K_LBUTTON', // &H1 - ['',''], // 'K_RBUTTON', // &H2 - ['',''], // 'K_CANCEL', // &H3 - ['',''], // 'K_MBUTTON', // &H4 - ['',''], // 'K_?05', // &H5 - ['',''], // 'K_?06', // &H6 - ['',''], // 'K_?07', // &H7 - ['',''], // 'K_BKSP', // &H8 - ['',''], // 'K_TAB', // &H9 - ['',''], // 'K_?0A', // &HA - ['',''], // 'K_?0B', // &HB - ['',''], // 'K_KP5', // &HC - ['',''], // 'K_ENTER', // &HD - ['',''], // 'K_?0E', // &HE - ['',''], // 'K_?0F', // &HF - ['',''], // 'K_SHIFT', // &H10 - ['',''], // 'K_CONTROL', // &H11 - ['',''], // 'K_ALT', // &H12 - ['',''], // 'K_PAUSE', // &H13 - ['',''], // 'K_CAPS', // &H14 - ['',''], // 'K_KANJI?15', // &H15 - ['',''], // 'K_KANJI?16', // &H16 - ['',''], // 'K_KANJI?17', // &H17 - ['',''], // 'K_KANJI?18', // &H18 - ['',''], // 'K_KANJI?19', // &H19 - ['',''], // 'K_?1A', // &H1A - ['',''], // 'K_ESC', // &H1B - ['',''], // 'K_KANJI?1C', // &H1C - ['',''], // 'K_KANJI?1D', // &H1D - ['',''], // 'K_KANJI?1E', // &H1E - ['',''], // 'K_KANJI?1F', // &H1F - [' ',' '], // 'K_SPACE', // &H20 - ['',''], // 'K_PGUP', // &H21 - ['',''], // 'K_PGDN', // &H22 - ['',''], // 'K_END', // &H23 - ['',''], // 'K_HOME', // &H24 - ['',''], // 'K_LEFT', // &H25 - ['',''], // 'K_UP', // &H26 - ['',''], // 'K_RIGHT', // &H27 - ['',''], // 'K_DOWN', // &H28 - ['',''], // 'K_SEL', // &H29 - ['',''], // 'K_PRINT', // &H2A - ['',''], // 'K_EXEC', // &H2B - ['',''], // 'K_PRTSCN', // &H2C - ['',''], // 'K_INS', // &H2D - ['',''], // 'K_DEL', // &H2E - ['',''], // 'K_HELP', // &H2F - ['0',')'], // 'K_0', // &H30 - ['1','!'], // 'K_1', // &H31 - ['2','@'], // 'K_2', // &H32 - ['3','#'], // 'K_3', // &H33 - ['4','$'], // 'K_4', // &H34 - ['5','%'], // 'K_5', // &H35 - ['6','^'], // 'K_6', // &H36 - ['7','&'], // 'K_7', // &H37 - ['8','*'], // 'K_8', // &H38 - ['9','('], // 'K_9', // &H39 - ['',''], // 'K_?3A', // &H3A - ['',''], // 'K_?3B', // &H3B - ['',''], // 'K_?3C', // &H3C - ['',''], // 'K_?3D', // &H3D - ['',''], // 'K_?3E', // &H3E - ['',''], // 'K_?3F', // &H3F - ['',''], // 'K_?40', // &H40 - - ['a','A'], // 'K_A', // &H41 - ['b','B'], // 'K_B', // &H42 - ['c','C'], // 'K_C', // &H43 - ['d','D'], // 'K_D', // &H44 - ['e','E'], // 'K_E', // &H45 - ['f','F'], // 'K_F', // &H46 - ['g','G'], // 'K_G', // &H47 - ['h','H'], // 'K_H', // &H48 - ['i','I'], // 'K_I', // &H49 - ['j','J'], // 'K_J', // &H4A - ['k','K'], // 'K_K', // &H4B - ['l','L'], // 'K_L', // &H4C - ['m','M'], // 'K_M', // &H4D - ['n','N'], // 'K_N', // &H4E - ['o','O'], // 'K_O', // &H4F - ['p','P'], // 'K_P', // &H50 - ['q','Q'], // 'K_Q', // &H51 - ['r','R'], // 'K_R', // &H52 - ['s','S'], // 'K_S', // &H53 - ['t','T'], // 'K_T', // &H54 - ['u','U'], // 'K_U', // &H55 - ['v','V'], // 'K_V', // &H56 - ['w','W'], // 'K_W', // &H57 - ['x','X'], // 'K_X', // &H58 - ['y','Y'], // 'K_Y', // &H59 - ['z','Z'], // 'K_Z', // &H5A - ['',''], // 'K_?5B', // &H5B - ['',''], // 'K_?5C', // &H5C - ['',''], // 'K_?5D', // &H5D - ['',''], // 'K_?5E', // &H5E - ['',''], // 'K_?5F', // &H5F - ['',''], // 'K_NP0', // &H60 - ['',''], // 'K_NP1', // &H61 - ['',''], // 'K_NP2', // &H62 - ['',''], // 'K_NP3', // &H63 - ['',''], // 'K_NP4', // &H64 - ['',''], // 'K_NP5', // &H65 - ['',''], // 'K_NP6', // &H66 - ['',''], // 'K_NP7', // &H67 - ['',''], // 'K_NP8', // &H68 - ['',''], // 'K_NP9', // &H69 - ['',''], // 'K_NPSTAR', // &H6A - ['',''], // 'K_NPPLUS', // &H6B - ['',''], // 'K_SEPARATOR', // &H6C - ['',''], // 'K_NPMINUS', // &H6D - ['',''], // 'K_NPDOT', // &H6E - ['',''], // 'K_NPSLASH', // &H6F - ['',''], // 'K_F1', // &H70 - ['',''], // 'K_F2', // &H71 - ['',''], // 'K_F3', // &H72 - ['',''], // 'K_F4', // &H73 - ['',''], // 'K_F5', // &H74 - ['',''], // 'K_F6', // &H75 - ['',''], // 'K_F7', // &H76 - ['',''], // 'K_F8', // &H77 - ['',''], // 'K_F9', // &H78 - ['',''], // 'K_F10', // &H79 - ['',''], // 'K_F11', // &H7A - ['',''], // 'K_F12', // &H7B - ['',''], // 'K_F13', // &H7C - ['',''], // 'K_F14', // &H7D - ['',''], // 'K_F15', // &H7E - ['',''], // 'K_F16', // &H7F - ['',''], // 'K_F17', // &H80 - ['',''], // 'K_F18', // &H81 - ['',''], // 'K_F19', // &H82 - ['',''], // 'K_F20', // &H83 - ['',''], // 'K_F21', // &H84 - ['',''], // 'K_F22', // &H85 - ['',''], // 'K_F23', // &H86 - ['',''], // 'K_F24', // &H87 - - ['',''], // 'K_?88', // &H88 - ['',''], // 'K_?89', // &H89 - ['',''], // 'K_?8A', // &H8A - ['',''], // 'K_?8B', // &H8B - ['',''], // 'K_?8C', // &H8C - ['',''], // 'K_?8D', // &H8D - ['',''], // 'K_?8E', // &H8E - ['',''], // 'K_?8F', // &H8F - - ['',''], // 'K_NUMLOCK', // &H90 - ['',''], // 'K_SCROLL', // &H91 - - ['',''], // 'K_?92', // &H92 - ['',''], // 'K_?93', // &H93 - ['',''], // 'K_?94', // &H94 - ['',''], // 'K_?95', // &H95 - ['',''], // 'K_?96', // &H96 - ['',''], // 'K_?97', // &H97 - ['',''], // 'K_?98', // &H98 - ['',''], // 'K_?99', // &H99 - ['',''], // 'K_?9A', // &H9A - ['',''], // 'K_?9B', // &H9B - ['',''], // 'K_?9C', // &H9C - ['',''], // 'K_?9D', // &H9D - ['',''], // 'K_?9E', // &H9E - ['',''], // 'K_?9F', // &H9F - ['',''], // 'K_?A0', // &HA0 - ['',''], // 'K_?A1', // &HA1 - ['',''], // 'K_?A2', // &HA2 - ['',''], // 'K_?A3', // &HA3 - ['',''], // 'K_?A4', // &HA4 - ['',''], // 'K_?A5', // &HA5 - ['',''], // 'K_?A6', // &HA6 - ['',''], // 'K_?A7', // &HA7 - ['',''], // 'K_?A8', // &HA8 - ['',''], // 'K_?A9', // &HA9 - ['',''], // 'K_?AA', // &HAA - ['',''], // 'K_?AB', // &HAB - ['',''], // 'K_?AC', // &HAC - ['',''], // 'K_?AD', // &HAD - ['',''], // 'K_?AE', // &HAE - ['',''], // 'K_?AF', // &HAF - ['',''], // 'K_?B0', // &HB0 - ['',''], // 'K_?B1', // &HB1 - ['',''], // 'K_?B2', // &HB2 - ['',''], // 'K_?B3', // &HB3 - ['',''], // 'K_?B4', // &HB4 - ['',''], // 'K_?B5', // &HB5 - ['',''], // 'K_?B6', // &HB6 - ['',''], // 'K_?B7', // &HB7 - ['',''], // 'K_?B8', // &HB8 - ['',''], // 'K_?B9', // &HB9 - - [';',':'], // 'K_COLON', // &HBA - ['=','+'], // 'K_EQUAL', // &HBB - [',','<'], // 'K_COMMA', // &HBC - ['-','_'], // 'K_HYPHEN', // &HBD - ['.','>'], // 'K_PERIOD', // &HBE - ['/','?'], // 'K_SLASH', // &HBF - ['`','~'], // 'K_BKQUOTE', // &HC0 - - ['',''], // 'K_?C1', // &HC1 - ['',''], // 'K_?C2', // &HC2 - ['',''], // 'K_?C3', // &HC3 - ['',''], // 'K_?C4', // &HC4 - ['',''], // 'K_?C5', // &HC5 - ['',''], // 'K_?C6', // &HC6 - ['',''], // 'K_?C7', // &HC7 - ['',''], // 'K_?C8', // &HC8 - ['',''], // 'K_?C9', // &HC9 - ['',''], // 'K_?CA', // &HCA - ['',''], // 'K_?CB', // &HCB - ['',''], // 'K_?CC', // &HCC - ['',''], // 'K_?CD', // &HCD - ['',''], // 'K_?CE', // &HCE - ['',''], // 'K_?CF', // &HCF - ['',''], // 'K_?D0', // &HD0 - ['',''], // 'K_?D1', // &HD1 - ['',''], // 'K_?D2', // &HD2 - ['',''], // 'K_?D3', // &HD3 - ['',''], // 'K_?D4', // &HD4 - ['',''], // 'K_?D5', // &HD5 - ['',''], // 'K_?D6', // &HD6 - ['',''], // 'K_?D7', // &HD7 - ['',''], // 'K_?D8', // &HD8 - ['',''], // 'K_?D9', // &HD9 - ['',''], // 'K_?DA', // &HDA - - ['[','{'], // 'K_LBRKT', // &HDB - ['\\','|'], // 'K_BKSLASH', // &HDC - [']','}'], // 'K_RBRKT', // &HDD - ['\'','"'], // 'K_QUOTE', // &HDE - ['',''], // 'K_oDF', // &HDF - ['',''], // 'K_oE0', // &HE0 - ['',''], // 'K_oE1', // &HE1 - ['\\','|'], // 'K_oE2', // &HE2 - ['',''], // 'K_oE3', // &HE3 - ['',''], // 'K_oE4', // &HE4 - - ['',''], // 'K_?E5', // &HE5 - - ['',''], // 'K_oE6', // &HE6 - - ['',''], // 'K_?E7', // &HE7 - ['',''], // 'K_?E8', // &HE8 - - ['',''], // 'K_oE9', // &HE9 - ['',''], // 'K_oEA', // &HEA - ['',''], // 'K_oEB', // &HEB - ['',''], // 'K_oEC', // &HEC - ['',''], // 'K_oED', // &HED - ['',''], // 'K_oEE', // &HEE - ['',''], // 'K_oEF', // &HEF - ['',''], // 'K_oF0', // &HF0 - ['',''], // 'K_oF1', // &HF1 - ['',''], // 'K_oF2', // &HF2 - ['',''], // 'K_oF3', // &HF3 - ['',''], // 'K_oF4', // &HF4 - ['',''], // 'K_oF5', // &HF5 - - ['',''], // 'K_?F6', // &HF6 - ['',''], // 'K_?F7', // &HF7 - ['',''], // 'K_?F8', // &HF8 - ['',''], // 'K_?F9', // &HF9 - ['',''], // 'K_?FA', // &HFA - ['',''], // 'K_?FB', // &HFB - ['',''], // 'K_?FC', // &HFC - ['',''], // 'K_?FD', // &HFD - ['',''], // 'K_?FE', // &HFE - ['',''], // 'K_?FF' // &HFF - ]; - - - this.lookupKeyNames = []; - - for (var i = 0; i < this.standardKeyNames.length; i++) { - if (this.standardKeyNames[i].indexOf('?') < 0) { - this.lookupKeyNames.push(this.standardKeyNames[i]); - } - } - this.lookupKeyNames.sort(); - - // Defines the PUA code mapping for the various 'special' modifier/control keys on keyboards. - // This is lifted directly from visualKeyboard.ts and must be kept in sync. See also CompileKeymanWeb.pas: CSpecialText10 - this.specialCharacters = { - '*Shift*': 8, - '*Enter*': 5, - '*Tab*': 6, - '*BkSp*': 4, - '*Menu*': 11, - '*Hide*': 10, - '*Alt*': 25, - '*Ctrl*': 1, - '*Caps*': 3, - '*ABC*': 16, - '*abc*': 17, - '*123*': 19, - '*Symbol*': 21, - '*Currency*': 20, - '*Shifted*': 9, - '*AltGr*': 2, - '*TabLeft*': 7, - '*LAlt*': 0x56, - '*RAlt*': 0x57, - '*LCtrl*': 0x58, - '*RCtrl*': 0x59, - '*LAltCtrl*': 0x60, - '*RAltCtrl*': 0x61, - '*LAltCtrlShift*': 0x62, - '*RAltCtrlShift*': 0x63, - '*AltShift*': 0x64, - '*CtrlShift*': 0x65, - '*AltCtrlShift*': 0x66, - '*LAltShift*': 0x67, - '*RAltShift*': 0x68, - '*LCtrlShift*': 0x69, - '*RCtrlShift*': 0x70, - // Following codes introduced in Keyman 14.0 - '*RTLEnter*': 0x71, - '*RTLBkSp*': 0x72, - '*ShiftLock*': 0x73, - '*ShiftedLock*': 0x74, - '*ZWNJ*': 0x75, // * If this one is specified, auto-detection will kick in. - '*ZWNJiOS*': 0x75, // The iOS version will be used by default, but the - '*ZWNJAndroid*': 0x76, // Android platform has its own default glyph. - '*LTREnter*': 5, // * Forces LTR shaping for the Enter/BkSp keys regardless - '*LTRBkSp*': 4, // of layout's directionality. - }; - - this.specialKeyNames = Object.entries(this.specialCharacters).map(ch => ch[0]); - - this.presentations = { - "tablet-ipad-landscape": { "x": 829, "y": 299, "name": "iPad (landscape)" }, // 829x622 = iPad tablet box size; (97,101)-(926,723) - "tablet-ipad-portrait": { "x": 605, "y": 300, "name": "iPad (portrait)" }, // 605x806 = iPad tablet box size; (98,94)-(703,900) - "phone-iphone5-landscape": { "x": 731, "y": 196, "name": "iPhone 5 (landscape)" }, // 731x412 = iPhone box size; (144,39)-(875,451) - "phone-iphone5-portrait": { "x": 526, "y": 266, "name": "iPhone 5 (portrait)"} // 528x936 = iPhone box size; (90,204)-(618,1040) - }; - - this.keyMargin = 15; - - // from kmwosk.js: - this.modifierCodes = { - "LCTRL":0x0001, - "RCTRL":0x0002, - "LALT":0x0004, - "RALT":0x0008, - "SHIFT":0x0010, - "CTRL":0x0020, - "ALT":0x0040, - "CAPS":0x0100, - "NO_CAPS":0x0200 - /*"NUM_LOCK":0x0400, We don't support these in the designer - "NO_NUM_LOCK":0x0800, - "SCROLL_LOCK":0x1000, - "NO_SCROLL_LOCK":0x2000, - "VIRTUAL_KEY":0x4000*/ - }; - - // Lists the combinations that we allow users to use. Some are mutually exclusive, - // such as Left+Right modifiers, or chiral and non-chiral modifiers (excl. Shift) - this.validModifierCombinations = [ - 0, - - this.modifierCodes.LCTRL, - this.modifierCodes.RCTRL, - - this.modifierCodes.LALT, - this.modifierCodes.LCTRL | this.modifierCodes.LALT, - - this.modifierCodes.RALT, - this.modifierCodes.RCTRL | this.modifierCodes.RALT, - - this.modifierCodes.SHIFT, - - this.modifierCodes.LCTRL | this.modifierCodes.SHIFT, - this.modifierCodes.LALT | this.modifierCodes.SHIFT, - this.modifierCodes.LCTRL | this.modifierCodes.LALT | this.modifierCodes.SHIFT, - - this.modifierCodes.RCTRL | this.modifierCodes.SHIFT, - this.modifierCodes.RALT | this.modifierCodes.SHIFT, - this.modifierCodes.RCTRL | this.modifierCodes.RALT | this.modifierCodes.SHIFT, - - this.modifierCodes.CTRL, - this.modifierCodes.CTRL | this.modifierCodes.SHIFT, - - this.modifierCodes.ALT, - this.modifierCodes.CTRL | this.modifierCodes.ALT, - this.modifierCodes.SHIFT | this.modifierCodes.ALT, - this.modifierCodes.SHIFT | this.modifierCodes.CTRL | this.modifierCodes.ALT, - this.modifierCodes.CAPS - ]; - - this.minimalModifierCombinations = [ - 0, - this.modifierCodes.RALT, - this.modifierCodes.SHIFT, - this.modifierCodes.RALT | this.modifierCodes.SHIFT, - this.modifierCodes.CAPS - ]; - - this.showAllModifierCombinations = false; - - // Add CAPS and NO_CAPS variants for all of the above - (function(c, codes) { - var i, n = c.length; - for(i = 0; i < n; i++) - c.push(c[i] | codes.CAPS); - for(i = 0; i < n; i++) - c.push(c[i] | codes.NO_CAPS); - })(this.validModifierCombinations, this.modifierCodes); - - this.modifierNames = [ - 'leftctrl', // 0x001 - 'rightctrl', // 0x002 - 'leftalt', // 0x004 - 'rightalt', // 0x008 - 'shift', // 0x010 - 'ctrl', // 0x020 - 'alt', // 0x040 - '', // 0x080 - reserved - 'caps', // 0x100 - 'nocaps' // 0x200 - ]; - - /** - * Get kebab-cased full name of a modifier combination given a bitmask - * - * @param {Number} c - * @return {string} - **/ - this.getModifierCombinationName = function(c) { - var r = ''; - if(c == 0) return 'default'; - for(var i = 0; i < this.modifierNames.length; i++) { - if(c & (1<'+builder.renameSpecialKey(name)+'     '+name+''; + } + $(types).append(opts); + $(subTypes).append(opts); + }; this.preparePlatforms = function () { var firstPlatform = null; @@ -916,6 +238,85 @@ $(function() { return (builder.getModifierCombinationFromLayerId(id) & this.modifierCodes.SHIFT) != 0; }; + /** + * Adds annotating images to a key cap to indicate when it has sub keys + */ + this.addKeyAnnotations = function(key) { + const longpress = $(key).data('longpress'), flick = $(key).data('flick'), multitap = $(key).data('multitap'), hint = $(key).data('hint'); + + $('.has-flick', key).remove(); + if (flick && flick.length) { + for(let f of flick) { + $(key).append('
'); + } + } + + // We add longpress after flick so that the longpress icon can be shifted down if there is a visual conflict + $('.has-longpress', key).remove(); + if (longpress && longpress.length) { + $(key).append('
'); + } + + $('.has-multitap', key).remove(); + if (multitap && multitap.length) { + $(key).append('
'); + } + + if(hint && hint.length) { + $('.hint', key).addClass('custom-hint'); + } else { + $('.hint', key).removeClass('custom-hint'); + } + } + + this.inferKeyText = function(key) { + let code = key.id ? String.fromCharCode(parseInt(key.id.substring(2), 16)) : 0; + let text = typeof key.text == 'string' ? key.text : (code == '' || code.charCodeAt(0) < 32 ? '' : code); + return text; + } + + this.inferKeyHintText = function(keyHint, longpress, flick, multitap) { + let hint = keyHint; + if(!hint) { + switch(KVKL[builder.lastPlatform].defaultHint ?? 'dot') { + case 'none': + break; + case 'dot': + // Default for Keyman 15 + if(longpress && longpress.length) hint = '•'; + break; + case 'longpress': + if(longpress && longpress.length) hint = builder.inferKeyText(longpress[0]); + break; + case 'multitap': + if(multitap && multitap.length) hint = builder.inferKeyText(multitap[0]); + break; + case 'flick': + for(let direction of ['n','ne','e','se','s','sw','w','nw']) { + if(flick && flick[direction]) { + hint = builder.inferKeyText(flick[direction]); + break; + } + } + break; + case 'flick-n': + case 'flick-ne': + case 'flick-e': + case 'flick-se': + case 'flick-s': + case 'flick-sw': + case 'flick-w': + case 'flick-nw': + let direction = source.substr(6); + if(flick && flick[direction]) hint = builder.inferKeyText(flick[direction]); + break; + } + } + + if(hint == null) return ''; + return hint; + } + this.prepareLayer = function () { var layer = KVKL[builder.lastPlatform].layer[builder.lastLayerIndex]; @@ -947,7 +348,7 @@ $(function() { this.yscale = 0.5; } - $('#kbd,#sk') + $('#kbd,#sub-key-groups') .css('font-family', KVKL[builder.lastPlatform].font) .css('font-size', KVKL[builder.lastPlatform].fontsize || "1em"); @@ -961,12 +362,10 @@ $(function() { var calcKeyWidth = 0, calcGapWidth = 0; for (var j = 0; j < layer.row[i].key.length; j++) { var key = layer.row[i].key[j]; - var nkey = builder.addKey(row, false, key.sp); + var nkey = builder.addKey('key', row, key.sp); var w = key.width ? key.width : 100; var p = (key.pad ? key.pad : builder.keyMargin) * this.xscale; - if (key.sk) $(nkey).addClass('hasSubKeyArray'); - var code = key.id ? String.fromCharCode(parseInt(key.id.substring(2), 16)) : 0; - var text = typeof key.text == 'string' ? key.text : (code == '' || code.charCodeAt(0) < 32 ? '' : code); + let text = builder.inferKeyText(key); calcKeyWidth += parseInt(w, 10); calcGapWidth += parseInt(key.pad ? key.pad : builder.keyMargin, 10); @@ -981,7 +380,11 @@ $(function() { .data('nextlayer', key.nextlayer) .data('layer', key.layer) .data('text', text) - .data('sk', key.sk) + .data('hint', key.hint) + .data('longpress', key.sk) + .data('flick', builder.translateFlickObjectToArray(key.flick)) + .data('multitap', key.multitap) + .data('type', 'key') .css('width', (w * this.xscale) + 'px') .css('height', (100 * this.yscale) + 'px') @@ -993,27 +396,42 @@ $(function() { if(this.specialCharacters[text]) $(nkey).addClass('key-special-text'); + builder.addKeyAnnotations(nkey); + $('.text', nkey).text(this.renameSpecialKey(text)); + $('.hint', nkey).text(this.inferKeyHintText(key.hint, key.sk, key.flick, key.multitap)); if(KVKL[builder.lastPlatform].displayUnderlying) $('.underlying', nkey).text(this.getStandardKeyCap(key.id, key.layer ? builder.isLayerIdShifted(key.layer) : isLayerShifted)); + builder.updateKeyId(nkey); } var calcWidth = calcKeyWidth + calcGapWidth; - $('.key-size', row).html(layer.row[i].key.length + ' keys
' + - calcKeyWidth + ' key width
' + - calcGapWidth + ' padding
' + - calcWidth + ' total'); - - $('#kbd').attr('class', builder.getPresentation()); //builder.lastPlatform); //css('background-position-y', '-200px'); + $('#kbd').attr('class', builder.getPresentation()); } - var div = document.createElement('div'); - $(div).css('clear', 'both'); - $('#kbd').append(div); + builder.updateKeySizeInfo(); }; + + this.updateKeySizeInfo = function() { + let rows = $('#kbd div.row'); + rows.each(function() { + let keys = $('.key', this), keyWidth = 0, gapWidth = 0; + keys.each(function() { + let width = $(this).data('width'), pad = $(this).data('pad'); + keyWidth += width ? parseInt(width, 10) : 100; + gapWidth += pad ? parseInt(pad, 10) : builder.keyMargin; + }); + let count = keys.length, totalWidth = keyWidth + gapWidth; + $('.key-size', this).html(count + ' keys
' + + keyWidth + ' key width
' + + gapWidth + ' padding
' + + totalWidth + ' total'); + }); + } + this.getStandardKeyCap = function (id, shifted) { id = id ? id.toUpperCase() : ''; var i = this.standardKeyNames.findIndex(function(x) { return x.toUpperCase() == id }); @@ -1039,17 +457,16 @@ $(function() { listContainer.append(option); } - $('#chkDisplayUnderlying')[0].checked = KVKL[builder.lastPlatform].displayUnderlying; - builder.prepareLayers(); builder.selectLayer(0); } this.selectLayer = function (val) { + let selection = builder.saveSelection(); if(val) $('#selLayer').val(val); builder.lastLayerIndex = $('#selLayer').val(); builder.prepareLayer(); - builder.selectKey($('#kbd > div.row > div.key')[0]); + builder.restoreSelection(selection); } this.selectLayerByName = function (name) { @@ -1061,62 +478,6 @@ $(function() { } } - this.undo = function () { - if (builder.undoStack.length == 0) { - return; - } - builder.saveUndo(1); - var s = builder.undoStack.pop(); - this.loadUndo(s); - } - - this.redo = function () { - if (builder.redoStack.length == 0) { - return; - } - builder.saveUndo(2); - var s = builder.redoStack.pop(); - this.loadUndo(s); - } - - this.loadUndo = function (s) { - KVKL = JSON.parse(s.KVKL); - - builder.preparePlatforms(); - builder.enableUndoControls(); - - $('#selPlatform').val(s.platform); - builder.selectPlatform(); - $('#selLayer').val(s.layer); - builder.selectLayer(); - builder.selectKey($('#kbd .key').filter(function (index) { return $(this).data('id') === s.id; }).first()); - if (s.subkey) builder.selectSubKey($('#sk .key').filter(function (index) { return $(this).data('id') === s.subkey; }).first()); - } - - this.saveUndo = function (saveToRedo) { - if (!saveToRedo) { - builder.redoStack = []; - } - builder.generate(true,false); - var s = { - KVKL: JSON.stringify(KVKL), - platform: builder.lastPlatform, - layer: builder.lastLayerIndex, - key: builder.selectedKey().data('id') - }; - var key = builder.selectedSubKey(); - if (key.length > 0) { - s.subkey = $(key).data('id'); - } - - var stack = (saveToRedo == 1 ? builder.redoStack : builder.undoStack); - stack.push(s); - if (stack.length > 100) { - stack.shift(); - } - builder.enableUndoControls(); - builder.command('modified'); - } this.commands = []; @@ -1138,23 +499,6 @@ $(function() { builder.commands.push(cmd); } - this.enableUndoControls = function () { - if (builder.undoStack.length == 0) { - builder.command('undo-disable'); - $('#btnUndo').attr('disabled', 'disabled'); - } else { - builder.command('undo-enable'); - $('#btnUndo').removeAttr('disabled'); - } - if (builder.redoStack.length == 0) { - builder.command('redo-disable'); - $('#btnRedo').attr('disabled', 'disabled'); - } else { - builder.command('redo-enable'); - $('#btnRedo').removeAttr('disabled'); - } - } - this.addRow = function (position) { var row = document.createElement('div'); $(row).addClass('row'); @@ -1175,152 +519,6 @@ $(function() { return row; }; - this.addKey = function (position, isSubKey, sp) { - var key = document.createElement('div'); - var ktext = document.createElement('div'); - var kid = document.createElement('div'); - var kunderlying = document.createElement('div'); - $(kid).addClass('id'); - $(ktext).addClass('text'); - $(kunderlying).addClass('underlying'); - $(key).append(kid); - $(key).append(ktext); - $(key).append(kunderlying); - $(key).addClass('key'); - $(key).data('id', 'T_new_' + this.uniqId); - builder.uniqId++; - builder.updateKeyId(key); - - if (isSubKey) { - $(key).click(function (event) { - event.stopPropagation(); - builder.selectSubKey(this); - if (builder.lastFocus) { - $(builder.lastFocus).focus().select(); - } - }).dblclick(function (event) { - event.stopPropagation(); - var layer = $(this).data('nextlayer'); - if (layer) builder.selectLayerByName(layer); - }); - $(kid).click(function (event) { - event.stopPropagation(); - builder.selectSubKey(key); - $('#inpSubKeyName').focus().select(); - }); - } else { - $(key).click(function (event) { - event.stopPropagation(); - builder.selectKey(this); - if (builder.lastFocus) { - $(builder.lastFocus).focus().select(); - } - }).dblclick(function (event) { - event.stopPropagation(); - var layer = $(this).data('nextlayer'); - if (layer) builder.selectLayerByName(layer); - }); - $(kid).click(function (event) { - event.stopPropagation(); - builder.selectKey(key); - $('#inpKeyName').focus().select(); - }); - } - - - if (position == 'before') { - builder.selectedKey().before(key); - } else if (position == 'after') { - builder.selectedKey().after(key); - } else if (position == 'before-subkey') { - builder.selectedSubKey().before(key); - } else if (position == 'after-subkey') { - builder.selectedSubKey().after(key); - } else { - $(position).append(key); - } - - $(key).draggable({ - revert: "invalid", - stack: ".key", - zIndex: 100, - helper: "clone", - //appendTo: "body", - start: function (event, ui) { - var isSubKey = ($(this).parent().attr('id') == 'sk'); - if (isSubKey) - builder.selectSubKey(null); - else - builder.selectKey(null, false); - var parent = isSubKey ? '#sk' : '#kbd'; - var drag = this; - drag.overList = []; - var pos = $(this).position(); - $(this).addClass('key-dragging'); - $(parent + ' .key').before(function (index) { - if (this == drag) return ''; - if ($(this).prev()[0] == drag) return '
'; - return '
'; - }); - $(isSubKey ? '#sk' : '.row').append('
'); - - $('.key-droppable').css('margin-top', $(this).css('margin-top')).css('height', $(this).css('height')).droppable({ - accept: ".key", - tolerance: "touch", - over: function (event, ui) { - drag.overList.push(this); - $(drag.overList[0]).addClass('key-droppable-hover'); - }, - out: function (event, ui) { - var n = drag.overList.indexOf(this); - if (n >= 0) - drag.overList.splice(n, 1); - $(this).removeClass('key-droppable-hover'); - if (drag.overList.length > 0) $(drag.overList[0]).addClass('key-droppable-hover'); - }, - drop: function (event, ui) { - // - // Drop the selected key into its new position - // - builder.saveUndo(); - $(drag).detach().removeClass('key-dragging'); - $(drag.overList[0]).after(drag); - //builder.selectKey(drag); - if (!isSubKey) builder.rescale(); else builder.generateSubKeys(); - builder.post(); - } - }); - $('.key-current').css('width', $(drag).width() + 'px').css('margin-left', -($(drag).width()) + 'px'); - }, - stop: function (event, ui) { - $('.key-droppable').remove(); - $(this).removeClass('key-dragging'); - //builder.rescale(); - } - }); - - builder.formatKey(key, sp); - - return key; - }; - - this.formatKey = function (key, sp) { - $(key) - .removeClass('key-modifier') - .removeClass('key-modifier-selected') - .removeClass('key-deadkey') - .removeClass('key-blank') - .removeClass('key-spacer'); - if (sp) { - switch (parseInt(sp, 10)) { - case 1: $(key).addClass('key-modifier'); break; - case 2: $(key).addClass('key-modifier-selected'); break; - case 8: $(key).addClass('key-deadkey'); break; - case 9: $(key).addClass('key-blank'); break; - case 10: $(key).addClass('key-spacer'); break; - } - } - } this.delSelectedKey = function () { var key = builder.selectedKey(); @@ -1346,38 +544,23 @@ $(function() { $(parentRow).remove(); } - this.selectSubKey = function (key) { - builder.selectedSubKey().removeClass('selected'); - if (key) { - $(key).addClass('selected'); - $('.skcontrol.wedge-horz,.skcontrol.wedge-vert,input#inpSubKeyCap').css('display', 'block'); - $('div#btnDelSubKey').css('display', ($('#sk > div').length > 1) ? 'block' : ''); - var offset = $(key).offset(); - - $('#wedgeAddSubKeyLeft').offset({ left: offset.left - 9, top: offset.top + $(key).outerHeight() + 2 }); - $('#wedgeAddSubKeyRight').offset({ left: offset.left + $(key).outerWidth() - 7, top: offset.top + $(key).outerHeight() + 2 }); - $('div#btnDelSubKey').offset({ left: offset.left + $(key).outerWidth() - 14, top: offset.top + 3 }); - $('input#inpSubKeyCap').offset({ left: offset.left + 16, top: offset.top + 4 }).width($(key).width() - 32); - builder.lastFocus = $('input#inpSubKeyCap'); - this.prepareSubKey(); - builder.enableSubKeyControls(); - } else { - $('.skcontrol.wedge-horz,.skcontrol.wedge-vert,div#btnDelSubKey,input#inpSubKeyCap').css('display', ''); - builder.enableSubKeyControls(); - } - builder.saveState(); - } this.selectKey = function (key, adjustResizable) { if (arguments.length == 1 || adjustResizable) builder.selectedKey().resizable('destroy'); + if(!builder.textControlsInToolbar()) { + $('input#inpSubKeyCap').css('display', ''); + } $('.skcontrol.wedge-horz,.skcontrol.wedge-vert,div#btnDelSubKey,input#inpSubKeyCap').css('display', ''); builder.selectedKey().removeClass('selected'); if (key && $(key).length) { $(key).addClass('selected'); - $('.kcontrol.wedge-horz,.kcontrol.wedge-vert,div#btnDelKey,input#inpKeyCap').css('display', 'block'); + if(!builder.textControlsInToolbar()) { + $('input#inpKeyCap').css('display', 'block'); + } + $('.kcontrol.wedge-horz,.kcontrol.wedge-vert,div#btnDelKey').css('display', 'block'); var rowOffset = $(key).parent().offset(); var offset = $(key).offset(); @@ -1385,13 +568,21 @@ $(function() { $('#wedgeAddRowBelow').offset({ left: rowOffset.left - 18, top: rowOffset.top + $(key).parent().outerHeight() - 7 }); $('#wedgeAddKeyLeft').offset({ left: offset.left - 9, top: offset.top + $(key).outerHeight() + 2 }); $('#wedgeAddKeyRight').offset({ left: offset.left + $(key).outerWidth() - 7, top: offset.top + $(key).outerHeight() + 2 }); - $('div#btnDelKey').offset({ left: offset.left + $(key).outerWidth() - 14, top: offset.top + 3 }); - $('input#inpKeyCap').offset({ left: offset.left + 16, top: offset.top + 4 }).width($(key).width() - 32); + $('div#btnDelKey').offset({ left: offset.left + $(key).outerWidth() - 5, top: offset.top - 8 }); + if(!builder.textControlsInToolbar()) { + $('input#inpKeyCap').offset({ left: offset.left + 16, top: offset.top + 4 }).width($(key).width() - 32); + } this.prepareKey(); - builder.lastFocus = $('input#inpKeyCap'); + let subKeys = $('#sub-key-groups div.key'); + if(subKeys.length) { + builder.selectSubKey(subKeys[0]); + } } else { - $('.kcontrol.wedge-horz,.kcontrol.wedge-vert,div#btnDelKey,input#inpKeyCap').css('display', ''); - $('#sk div').remove(); + if(!builder.textControlsInToolbar()) { + $('input#inpKeyCap').css('display', ''); + } + $('.kcontrol.wedge-horz,.kcontrol.wedge-vert,div#btnDelKey').css('display', ''); + builder.removeAllSubKeys(); builder.enableKeyControls(); builder.enableSubKeyControls(); } @@ -1409,16 +600,16 @@ $(function() { builder.saveUndo(); builder.hasSavedKeyUndo = true; } else { - builder.command('modified'); - } + builder.command('modified'); + } } else { builder.saveUndo(); } - var r = f.apply(this); + var r = f.apply(this, arguments); if(typeof opt == 'object' && opt.rescale) { builder.rescale(); } - builder.post(); + builder.generate(); return r; } }; @@ -1446,7 +637,7 @@ $(function() { builder.updateKeyId(builder.selectedKey()); }, {saveOnce: true}); - const wrapInstant = function(f) { + builder.wrapInstant = function(f) { return function() { window.setTimeout(f.bind(this), 0); } @@ -1457,7 +648,7 @@ $(function() { .autocomplete({ source: builder.lookupKeyNames, change: inpKeyNameChange, - select: wrapInstant(inpKeyNameChange) + select: builder.wrapInstant(inpKeyNameChange) }) .on('input', inpKeyNameChange) .blur(function () { @@ -1481,29 +672,91 @@ $(function() { } } - const inpKeyCapChange = builder.wrapChange(function (e) { - const val = $(this).val(); - var k = builder.selectedKey(); + builder.toUnicodeString = function(s) { + if(typeof s != 'string') return ''; + let r = ''; + for(let ch of s) { + let code = ch.codePointAt(0).toString(16).toUpperCase(); + r += 'U+' + code.padStart(4, '0') + ' '; + } + return r.trim(); + } + + builder.fromUnicodeString = function(s) { + if(typeof s != 'string') return ''; + let chars = s.split(' '), r = ''; + for(let ch of chars) { + if(!ch.match(/^u\+[0-9a-f]{1,6}$/i)) continue; + r += String.fromCodePoint(parseInt(ch.substring(2), 16)); + } + return r; + } + + const keyCapChange = function(val) { + const k = builder.selectedKey(); $('.text', k).text(builder.renameSpecialKey(val)); k.data('text', val); - if(builder.specialCharacters[val]) { k.addClass('key-special-text'); } else { k.removeClass('key-special-text'); } + builder.updateCharacterMap(val, false); + } + + const inpKeyCapChange = builder.wrapChange(function (e) { + const val = $(this).val(); + $('#inpKeyCapUnicode').val(builder.toUnicodeString(val)); + keyCapChange(val); + }, {saveOnce: true}); + + const inpKeyCapUnicodeChange = builder.wrapChange(function (e) { + const val = builder.fromUnicodeString($(this).val()); + $('#inpKeyCap').val(val); + keyCapChange(val); + }, {saveOnce: true}); + + const keyHintChange = function(val) { + const key = builder.selectedKey(); + key.data('hint', val); + $('.hint', key).text(builder.inferKeyHintText(val, $(key).data('longpress'), $(key).data('flick'), $(key).data('multitap'))); + if(val && val.length) { + $('.hint', key).addClass('custom-hint'); + } else { + $('.hint', key).removeClass('custom-hint'); + } builder.updateCharacterMap(val, false); + } + + const inpKeyHintChange = builder.wrapChange(function (e) { + const val = $(this).val(); + $('#inpKeyHintUnicode').val(builder.toUnicodeString(val)); + keyHintChange(val); }, {saveOnce: true}); + const inpKeyHintUnicodeChange = builder.wrapChange(function (e) { + const val = builder.fromUnicodeString($(this).val()); + $('#inpKeyHint').val(val); + keyHintChange(val); + }, {saveOnce: true}); + + + const selKeyCapTypeChange = builder.wrapChange(function () { + var val = $(this).val(); + $('#inpKeyCap').val(val); + $('#inpKeyCapUnicode').val(builder.toUnicodeString(val)); + keyCapChange(val); + // We only EnableControls here because if the user types *BkSp* into the + // text field, we shouldn't hide the text field until next time the key is selected + builder.enableKeyControls(); + }); + + $('#selKeyCapType').on('change', selKeyCapTypeChange); + $('#inpKeyCap') .on('input', inpKeyCapChange) .change(inpKeyCapChange) - .autocomplete({ - source: builder.specialKeyNames, - change: inpKeyCapChange, - select: wrapInstant(inpKeyCapChange) - }) .mouseup(function () { builder.updateCharacterMap($(this).val(), false); }).focus(function () { @@ -1512,6 +765,39 @@ $(function() { builder.hasSavedKeyUndo = false; }); + $('#inpKeyCapUnicode') + .on('input', inpKeyCapUnicodeChange) + .change(inpKeyCapUnicodeChange) + .mouseup(function () { + builder.updateCharacterMap(builder.fromUnicodeString($(this).val()), false); + }).focus(function () { + builder.updateCharacterMap(builder.fromUnicodeString($(this).val()), false); + }).blur(function () { + builder.hasSavedKeyUndo = false; + }); + + $('#inpKeyHint') + .on('input', inpKeyHintChange) + .change(inpKeyHintChange) + .mouseup(function () { + builder.updateCharacterMap($(this).val(), false); + }).focus(function () { + builder.updateCharacterMap($(this).val(), false); + }).blur(function () { + builder.hasSavedKeyUndo = false; + }); + + $('#inpKeyHintUnicode') + .on('input', inpKeyHintUnicodeChange) + .change(inpKeyHintUnicodeChange) + .mouseup(function () { + builder.updateCharacterMap(builder.fromUnicodeString($(this).val()), false); + }).focus(function () { + builder.updateCharacterMap(builder.fromUnicodeString($(this).val()), false); + }).blur(function () { + builder.hasSavedKeyUndo = false; + }); + const selKeyTypeChange = builder.wrapChange(function () { var sp = $(this).val(); if (sp == 0) { @@ -1541,105 +827,17 @@ $(function() { $('#selKeyLayerOverride').change(selKeyLayerOverrideChange); - this.prepareKey = function () { - builder.enableKeyControls(); - var key = builder.selectedKey(); - builder.hasSavedKeyUndo = false; - $('#inpKeyCap').val($(key).data('text')); - $('#inpKeyName').val($(key).data('id')); - $('#inpKeyWidth').val($(key).data('width')); - $('#inpKeyPadding').val($(key).data('pad')); - $('#selKeyType').val($(key).data('sp') ? $(key).data('sp') : 0); - $('#selKeyNextLayer').val($(key).data('nextlayer')); - $('#selKeyLayerOverride').val($(key).data('layer')); - - $(key).resizable({ - minWidth: 10 * this.xscale, - minHeight: 100 * this.yscale, - maxWidth: 500 * this.xscale, - maxHeight: 100 * this.yscale, - ghost: false, - handles: "e", - resize: function (event, ui) { - builder.selectedKey().data('width', Math.round(ui.size.width / builder.xscale, 0)); - $('#inpKeyWidth').val(Math.round(ui.size.width / builder.xscale, 0)); - }, - start: function (event, ui) { - builder.saveUndo(); - $(ui.originalElement).css('position', 'relative'); - $(ui.originalElement).css('left', ''); - }, - stop: function (event, ui) { - builder.rescale(); - builder.post(); - } - }); - - // - // Prepare sub-key array - // - - $('#sk div').remove(); - var skContainer = $('#sk'); - var sk = $(key).data('sk'); - if (typeof sk != 'object') { - $(key).removeClass('hasSubKeyArray'); - builder.enableSubKeyControls(); - return; - } - - $(key).addClass('hasSubKeyArray'); - for (var i = 0; i < sk.length; i++) { - var nkey = builder.addKey(skContainer, true); - var key = sk[i]; - - var code = key.id ? String.fromCharCode(parseInt(key.id.substring(2), 16)) : 0; - var text = typeof key.text == 'string' ? key.text : (code.charCodeAt(0) < 32 ? '' : code); - - $(nkey) - .data('text', text) - .data('id', key.id) - .data('sp', key.sp) - .data('font', key.font) - .data('fontsize', key.fontsize) - .data('nextlayer', key.nextlayer) - .data('layer', key.layer) - .css('width', (100 * 0.7) + 'px') - .css('font-family', KVKL[builder.lastPlatform].font); - - if(this.specialCharacters[text]) - $(nkey).addClass('key-special-text'); - - $('.text', nkey).text(this.renameSpecialKey(text)); - builder.updateKeyId(nkey); - } - builder.prepareSubKey(); - builder.enableSubKeyControls(); - } - this.enableKeyControls = function () { var key = builder.selectedKey(); if (key.length == 0) { $('#keyToolbar *').attr('disabled', 'disabled'); - $('#btnAddSubKeyArray').css('display', ''); - $('#btnDelSubKeyArray').css('display', 'none'); + $('#sub-key-container').css('display', 'none'); + $('#key-cap-unicode-toolbar-item, #key-cap-toolbar-item').css('display', 'none'); } else { + let val = $(key).data('text'); $('#keyToolbar *').removeAttr('disabled'); - if (builder.selectedKey().hasClass('hasSubKeyArray')) { - $('#btnAddSubKeyArray').css('display', 'none'); - $('#btnDelSubKeyArray').css('display', ''); - } else { - $('#btnAddSubKeyArray').css('display', ''); - $('#btnDelSubKeyArray').css('display', 'none'); - } - } - } - this.enableSubKeyControls = function () { - var key = builder.selectedSubKey(); - if (key.length == 0) { - $('#subKeyToolbar').css('visibility', 'hidden'); - } else { - $('#subKeyToolbar').css('visibility', ''); + $('#sub-key-container').css('display', ''); + $('#key-cap-unicode-toolbar-item, #key-cap-toolbar-item').css('display', builder.specialCharacters[val] ? 'none' : ''); } } @@ -1651,174 +849,30 @@ $(function() { builder.selectKey($('#kbd .key').filter(function (index) { return $(this).data('id') === keyId; }).first()); }; - // - // Popup keys - // - - this.addSubKeyArray = function () { - var key = builder.selectedKey(); - if ($(key).data('sk')) return; - var sk = [{ id: 'T_new_' + builder.uniqId}]; - builder.uniqId++; - $(key).data('sk', sk); - builder.prepareKey(); - } - - this.delSubKeyArray = function () { - var key = builder.selectedKey(); - $(key).removeData('sk'); - builder.prepareKey(); - builder.selectSubKey(null); - builder.enableSubKeyControls(); - } - - this.delSelectedSubKey = function () { - var key = builder.selectedSubKey(); - if (key.length == 0) return; - var nextKey = $(key).next('.key'); - if (nextKey.length == 0) nextKey = $(key).prev('.key'); - if (nextKey.length == 0) return; - $(key).remove(); - builder.selectSubKey(nextKey); - }; - - this.selectedSubKey = function () { - return $('#sk .selected'); - }; - - this.generateSubKeys = function () { - var key = builder.selectedKey(); - var sk = []; - var keys = $('#sk > div.key').filter(':not(.ui-draggable-dragging)'); - for (var i = 0; i < keys.length; i++) { - sk.push({ - text: $(keys[i]).data('text'), - id: $(keys[i]).data('id'), - sp: $(keys[i]).data('sp'), - font: $(keys[i]).data('font'), - fontsize: $(keys[i]).data('fontsize'), - nextlayer: $(keys[i]).data('nextlayer'), - layer: $(keys[i]).data('layer') - }); + this.translateFlickArrayToObject = function(flicks) { + let res = {}; + for(let flick of flicks) { + const {direction, ...item} = flick; + res[direction] = item; } - key.data('sk', sk); - } - - this.prepareSubKey = function () { - var key = builder.selectedSubKey(); - - $('#inpSubKeyCap').val($(key).data('text')); - $('#inpSubKeyName').val($(key).data('id')); - $('#selSubKeyType').val($(key).data('sp') ? $(key).data('sp') : 0); - $('#selSubKeyNextLayer').val($(key).data('nextlayer')); - $('#selSubKeyLayerOverride').val($(key).data('layer')); - } - - var subKeyNameChange = builder.wrapChange(function () { - var nkey = builder.selectedSubKey(); - if (nkey.length == 0) return; - nkey.data('id', $(this).val()); - builder.generateSubKeys(); - builder.updateKeyId(nkey); - }, {saveOnce: true}); - - $('#inpSubKeyName') - .change(subKeyNameChange) - .on('input', subKeyNameChange) - .autocomplete({ - source: builder.lookupKeyNames, - change: subKeyNameChange, - select: wrapInstant(subKeyNameChange) - }).blur(function () { - builder.hasSavedKeyUndo = false; - }); - - builder.updateSubKeyCap = function (val) { - var k = builder.selectedSubKey(); - if (k.length == 0) return; - $('.text', k).text(builder.renameSpecialKey(val)); - k.data('text', val); - - builder.updateCharacterMap(val, true); - builder.generateSubKeys(); + return res; }; - const inpSubKeyCapChange = builder.wrapChange(function () { - builder.updateSubKeyCap($(this).val()); - }, {saveOnce: true}); - - $('#inpSubKeyCap') - .change(inpSubKeyCapChange) - .autocomplete({ - source: builder.specialKeyNames, - change: inpSubKeyCapChange, - select: wrapInstant(inpSubKeyCapChange) - }) - .on('input', inpSubKeyCapChange) - .mouseup(function () { - builder.updateCharacterMap($(this).val(), false); - }).focus(function () { - builder.updateCharacterMap($(this).val(), false); - }).blur(function () { - builder.hasSavedSubKeyUndo = false; - }); - - const selSubKeyNextLayerChange = builder.wrapChange(function () { - $(this).val() === '' ? - builder.selectedSubKey().removeData('nextlayer') : - builder.selectedSubKey().data('nextlayer', $(this).val()); - builder.generateSubKeys(); - }); - - $('#selSubKeyNextLayer').change(selSubKeyNextLayerChange); - - const selSubKeyLayerOverrideChange = builder.wrapChange(function () { - $(this).val() === '' ? - builder.selectedSubKey().removeData('layer') : - builder.selectedSubKey().data('layer', $(this).val()); - builder.updateKeyId(builder.selectedSubKey()); - builder.generateSubKeys(); - }); - - $('#selSubKeyLayerOverride').change(selSubKeyLayerOverrideChange); - - $('#wedgeAddSubKeyLeft').click(builder.wrapChange(function () { - builder.selectSubKey(builder.addKey('before-subkey', true)); - builder.generateSubKeys(); - })); - - $('#wedgeAddSubKeyRight').click(builder.wrapChange(function () { - builder.selectSubKey(builder.addKey('after-subkey', true)); - builder.generateSubKeys(); - })); - - $('#btnDelSubKey').click(builder.wrapChange(function () { - builder.delSelectedSubKey(); - builder.generateSubKeys(); - })); - - const selSubKeyTypeChange = builder.wrapChange(function () { - var sp = $(this).val(), key = builder.selectedSubKey(); - if (key.length == 0) return; - if (sp == 0) { - key.removeData('sp'); - } else { - key.data('sp', $(this).val()); + this.translateFlickObjectToArray = function(flicks) { + if(!flicks) { + return []; } - builder.formatKey(key, $(this).val()); - builder.generateSubKeys(); - }); - $('#selSubKeyType').change(selSubKeyTypeChange); + return Object.getOwnPropertyNames(flicks).map( + direction => { + return {...flicks[direction], direction: direction}; + } + ); + } this.generate = function (display, force) { var json = JSON.stringify(KVKL, null, ' '); - if(!display) { - // Save changed settings -- only when not saving undo - KVKL[builder.lastPlatform].displayUnderlying = $('#chkDisplayUnderlying')[0].checked; - } - var layer = KVKL[builder.lastPlatform].layer[builder.lastLayerIndex]; layer.row = []; @@ -1835,7 +889,13 @@ $(function() { key.fontsize = $(this).data('fontsize'); key.nextlayer = $(this).data('nextlayer'); key.layer = $(this).data('layer'); - key.sk = $(this).data('sk'); + key.hint = $(this).data('hint'); + let longpress = $(this).data('longpress'); + if(longpress && longpress.length) key.sk = longpress; + let flick = $(this).data('flick'); + if(flick && flick.length) key.flick = builder.translateFlickArrayToObject(flick); + let multitap = $(this).data('multitap'); + if(multitap && multitap.length) key.multitap = multitap; row.key.push(key); }); layer.row.push(row); @@ -1845,7 +905,7 @@ $(function() { }; this.saveJSON = function(force) { - builder.removeEmptyRows(); + builder.cleanupKVKL(); var newJson = JSON.stringify(KVKL, null, ' '); if(force || newJson != json) { // When adding or deleting layers and platforms, we need to force because @@ -1861,287 +921,32 @@ $(function() { } }; - this.post = this.generate; - $('#wedgeAddRowAbove').click(builder.wrapChange(function () { - var row = builder.addRow('above'); builder.selectKey(builder.addKey(row, false)); + var row = builder.addRow('above'); builder.selectKey(builder.addKey('key', row)); }, {rescale: true})); $('#wedgeAddRowBelow').click(builder.wrapChange(function () { - var row = builder.addRow('below'); builder.selectKey(builder.addKey(row, false)); + var row = builder.addRow('below'); builder.selectKey(builder.addKey('key', row)); }, {rescale: true})); $('#wedgeAddKeyLeft').click(builder.wrapChange(function () { - builder.selectKey(builder.addKey('before', false)); + builder.selectKey(builder.addKey('key', 'before')); }, {rescale: true})); $('#wedgeAddKeyRight').click(builder.wrapChange(function () { - builder.selectKey(builder.addKey('after', false)); + builder.selectKey(builder.addKey('key', 'after')); }, {rescale: true})); $('#btnDelKey').click(builder.wrapChange(function () { builder.delSelectedKey(); }, {rescale: true})); - $('#btnAddSubKeyArray').click(builder.wrapChange(function () { - builder.addSubKeyArray(); - builder.selectSubKey($('#sk > div')[0]); - if (builder.lastFocus) builder.lastFocus.focus(); - builder.enableKeyControls(); - })); - - $('#btnDelSubKeyArray').click(builder.wrapChange(function () { - builder.delSubKeyArray(); - builder.enableKeyControls(); - })); - $('#btnGenerate').click(function () { builder.generate(false,false); }); - $('#selPlatform').change(function () { - if (builder.lastPlatform) builder.generate(false,false); - builder.selectPlatform(); - builder.saveState(); - }); - - $('#selLayer').change(function () { - if (builder.lastPlatform) builder.generate(false,false); - builder.selectLayer(); - builder.saveState(); - }); - - // - // Platform dialogs - // - - $('#addPlatformDialog').dialog({ - autoOpen: false, - height: 300, - width: 350, - modal: true, - buttons: { - "OK": function () { - builder.saveUndo(); - - var platform = $('#selAddPlatform').val(); - KVKL[platform] = $.extend(true, {}, KVKL[builder.lastPlatform]); // copy existing platform - - builder.preparePlatforms(); - $('#selPlatform').val(platform); - builder.selectPlatform(); - - builder.generate(false,true); - - $(this).dialog('close'); - }, - "Cancel": function () { - $(this).dialog('close'); - } - } - }); - - $('#btnAddPlatform').click(function () { - $('#selAddPlatform option').remove(); - var platforms = { 'tablet': 1, 'desktop': 1, 'phone': 1 }; - for (var platform in KVKL) { - platforms[platform] = 0; - } - for (platform in platforms) { - if (platforms[platform]) { - var opt = document.createElement('option'); - $(opt).text(platform); - $('#selAddPlatform').append(opt); - } - } - $('#addPlatformDialog').dialog('open') - }); - - $('#btnDelPlatform').click(function () { - if ($('#selPlatform option').length == 1) return; - builder.saveUndo(); - var platform = $('#selPlatform').val(); - delete KVKL[platform]; - builder.lastPlatform = null; - builder.preparePlatforms(); - builder.generate(false,true); - }); - - $('#chkDisplayUnderlying').click(function () { - builder.saveUndo(); - var platform = $('#selPlatform').val(); - builder.post(); - builder.prepareLayer(); - }); - - // - // Layer dialogs - // - - $('#layerPropertiesDialog').dialog({ - autoOpen: false, - height: 300, - width: 350, - modal: true, - buttons: { - "OK": function () { - var newLayerName = $('#layerName').val(); - if (!newLayerName.match(/^[a-zA-Z0-9_-]+$/)) { - alert('Layer name must contain only alphanumerics, underscore and hyphen.'); - return; - } - - builder.saveUndo(); - builder.generate(); - - var platform = KVKL[builder.lastPlatform]; - var oldLayerName = platform.layer[builder.lastLayerIndex].id; - - for (var i = 0; i < platform.layer.length; i++) { - var layer = platform.layer[i]; - if (layer.row) { - for (var j = 0; j < layer.row.length; j++) { - var row = layer.row[j]; - if (row.key) { - for (var k = 0; k < row.key.length; k++) { - var key = row.key[k]; - if (key.layer == oldLayerName) { - key.layer = newLayerName; - } - if (key.nextlayer == oldLayerName) { - key.nextlayer = newLayerName; - } - - if (key.sk) { - for (var l = 0; l < key.sk.length; l++) { - if (key.sk[l].layer == oldLayerName) { - key.sk[l].layer = newLayerName; - } - if (key.sk[l].nextlayer == oldLayerName) { - key.sk[l].nextlayer = newLayerName; - } - } - } - } - } - } - } - } - - platform.layer[builder.lastLayerIndex].id = newLayerName; - builder.prepareLayers(); - $('#selLayer').val(builder.lastLayerIndex); - builder.selectLayer(); - builder.post(); - $(this).dialog('close'); - }, - "Cancel": function () { - $(this).dialog('close'); - } - } - }); - - $('#selectKeyDialog').dialog({ - autoOpen: false, - height: 140, - width: 240, - modal: true, - buttons: { - "Cancel": function () { - builder.nextKeySelects = false; - $(this).dialog('close'); - } - } - }); - - - $('#addLayerName').on('input', function() { - var layerName = $(this).val(); - $('#addLayerList').val(layerName); - if($('#addLayerList')[0].selectedIndex < 0) { - $('#addLayerList').val('(custom)'); - $('#addLayerNote').text(''); - } else { - $('#addLayerNote').text(layerName+' is a recognised modifier-aware layer name.'); - } - }); - - $('#addLayerList').change(function() { - var v = $(this).val(); - if(v == '(custom)') { - $('#addLayerName').val(''); - $('#addLayerNote').text(''); - } else { - $('#addLayerName').val(v); - $('#addLayerNote').text(v+' is a recognised modifier-aware layer name.'); - } - }); - - $('#addLayerDialog').dialog({ - autoOpen: false, - height: 300, - width: 350, - modal: true, - buttons: { - "OK": function () { - var id = $('#addLayerName').val(); - if (!id.match(/^[a-zA-Z0-9_-]+$/)) { - alert('Layer name must contain only alphanumerics, underscore and hyphen.'); - return; - } - for(var i = 0; i < KVKL[builder.lastPlatform].layer.length; i++) { - if(KVKL[builder.lastPlatform].layer[i].id == id) { - alert('Layer name must not already be in use for the current platform.'); - return; - } - } - builder.saveUndo(); - var layer = $.extend(true, {}, KVKL[builder.lastPlatform].layer[builder.lastLayerIndex]); - layer.id = id; - var n = KVKL[builder.lastPlatform].layer.push(layer) - 1; - builder.selectPlatform(); - $('#selLayer').val(n); - builder.selectLayer(); - builder.generate(false,true); - $(this).dialog('close'); - }, - "Cancel": function () { - $(this).dialog('close'); - } - } - }); - - $('#btnAddLayer').click(function () { - $('#addLayerDialog').dialog('open'); - }); - - $('#btnDelLayer').click(function () { - if ($('#selLayer option').length == 1) return; - builder.saveUndo(); - KVKL[builder.lastPlatform].layer.splice(builder.lastLayerIndex, 1); - builder.selectPlatform(); - builder.generate(false,true); - }); - - $('#btnEditLayer').click(function () { - $('#layerName').val(KVKL[builder.lastPlatform].layer[builder.lastLayerIndex].id); - $('#layerPropertiesDialog').dialog('open'); - }); - - $('input').blur(function () { - builder.lastFocus = this; - }); - $('input').focus(function () { builder.lastFocus = this; }); - $('#btnUndo').click(function () { - builder.undo(); - }); - - $('#btnRedo').click(function () { - builder.redo(); - }); - $('#btnTemplate').click(function () { builder.command('template'); }); @@ -2154,10 +959,6 @@ $(function() { builder.selectKey(null); }); - $('#sk').click(function () { - builder.selectSubKey(null); - }); - builder.ctrlDown = false; builder.nextKeySelects = false; @@ -2233,10 +1034,15 @@ $(function() { $('#selPlatform').val(data.platform); } builder.selectPlatform(); - if(data.presentation && builder.presentations[data.presentation]) { + if(data.presentation && + builder.presentations[data.presentation] && + $('#selPlatformPresentation option[value="'+data.presentation+'"]').length) { $('#selPlatformPresentation').val(data.presentation); - builder.prepareLayer(); + } else { + // The last selected presentation is no longer available; select the first option instead + $('#selPlatformPresentation').val($('#selPlatformPresentation option:first').val()); } + builder.prepareLayer(); if(data.layer && KVKL[builder.lastPlatform][data.layer]) { $('#selLayer').val(data.layer); builder.selectLayer(); @@ -2245,32 +1051,26 @@ $(function() { builder.selectKey($('#kbd .key').filter(function (index) { return $(this).data('id') === data.key; }).first()); } if(data.subkey) { - builder.selectSubKey($('#sk .key').filter(function (index) { return $(this).data('id') === data.subkey; }).first()); + builder.selectSubKey($('#sub-key-groups .key').filter(function (index) { return $(this).data('id') === data.subkey; }).first()); } } } ); }; - builder.removeEmptyRows = function() { - var json = JSON.stringify(KVKL, null, ' '); - for (var platform in KVKL) { - for (let layer of KVKL[platform].layer) { - let newRow = [], n = 1; - for(let row of layer.row) { - if(row.key.length > 0) { - row.id = n; - n++; - newRow.push(row); - } - } - layer.row = newRow; - } - } - }; + builder.textControlsInToolbar = function() { + return $('body').hasClass('text-controls-in-toolbar'); + } - builder.preparePlatforms(); - builder.enableUndoControls(); - builder.loadState(); }.bind(builder)); + +function initBuilder() { + $(function() { + builder.cleanupKVKL(); + builder.prepareKeyCapTypes(); + builder.preparePlatforms(); + builder.enableUndoControls(); + builder.loadState(); + }); +} \ No newline at end of file diff --git a/developer/src/tike/xml/layoutbuilder/builder.xsl b/developer/src/tike/xml/layoutbuilder/builder.xsl index 31312068ba..70d78a19d2 100644 --- a/developer/src/tike/xml/layoutbuilder/builder.xsl +++ b/developer/src/tike/xml/layoutbuilder/builder.xsl @@ -2,131 +2,343 @@ - + - - <!DOCTYPE html> - - - - - - On Screen Keyboard Builder - jquery-ui.css - builder.css - - - - - - - -
+
-
+
-
+
-
+
-
x
+ -
-
- - -
-
-
- Platform: - - - -
-
- Layer: - - - -
-
- Presentation: - -
-
-
-
-
-
- - - - - - - - - - - -
-
+<!DOCTYPE html> + + + + + + On Screen Keyboard Builder + jquery-ui/jquery-ui.css + builder.css + + + + + + + + + + + + + + + + + +
+
+
+
+ +
+
+ +
+
+
+
+
+

View Controls

+
+ +
+
+ +
+
+
+

Platform

+
+ + + +
+
+ +
+
+
+

Layer

+
+ + + +
+
+ +
+
+
+
+
-
+
-
+
-
x
+
-
-
- - - - - -
-
+ -
-
-
- Platform: -
-
-
-
-
-
-
-
-
-
- -
-
-
-
- Press any key to select it on the keyboard -
-
-
-
- Name: -
-
-
- - - +
+
+
+
+ + + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + + +
+
+
+
+
+
+
+
+
x
+
+ + + + +
+
+
+ Longpress Keys + +
+
+
+
+
+ +
+ Flicks +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+ Multitaps +
+
+
+
+
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + +
+
+
+
+
x
+ +
+ +
+ +
+
+
+ Platform: +
+
+
+ +
+
+
+
+
+
+
+ +
+
+
+ +
+ Press any key to select it on the keyboard +
+ +
+
+
+
By default, only common modifiers are shown in the modifier lists. If + access to more unusual modifier combinations are required, check this option.

+ This option only affects the controls within the Touch Layout Editor; it has no impact on the layout itself.

+
+ + +
+
+
+ +
+
+
+
Displays the underlying keyboard label on top-left of the key

+ + +
+
+
Default hint source for keys for this platform. These can be + overridden on a key-by-key basis. "Show a dot if a longpress is present" + is the behavior in Keyman 15 and earlier versions and is the default option.

+
+ + +
+
+
+ +
+
+
+ Name: +
+
+
+ + + +
diff --git a/developer/src/tike/xml/layoutbuilder/cleanup.js b/developer/src/tike/xml/layoutbuilder/cleanup.js new file mode 100644 index 0000000000..3bd75bcd38 --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/cleanup.js @@ -0,0 +1,79 @@ +$(function() { + + builder.cleanupKVKL = function() { + let cleanupEmptyArrays = function() { + for (let platform in KVKL) { + for (let layer of KVKL[platform].layer) { + let newRow = [], n = 1; + for(let row of layer.row) { + if(row.key && Array.isArray(row.key)) { + for(let key of row.key) { + if(key.sk && (!Array.isArray(key.sk) || key.sk.length == 0)) { + delete key.sk; + } + } + if(row.key.length > 0) { + row.id = n; + n++; + newRow.push(row); + } + } + } + layer.row = newRow; + } + } + return true; + }; + + let cleanupNumericField = function(obj, prop) { + if(typeof obj[prop] == 'number') { + return true; + } + if(typeof obj[prop] == 'string') { + let v = obj[prop].trim(); + if(v != '') { + v = parseInt(v, 10); + if(isFinite(v)) { + obj[prop] = v; + return true; + } + } + } + delete obj[prop]; + return true; + } + + let cleanupKeyTypes = function(key) { + // Delete empty strings for id + if(typeof key.id != 'undefined') { + if(typeof key.id != 'string') delete key.id; + else if(key.id.trim() == '') delete key.id; + } + // Enforce numeric types for sp, pad, width + return cleanupNumericField(key, 'sp') && + cleanupNumericField(key, 'pad') && + cleanupNumericField(key, 'width'); + } + + let cleanupTypes = function() { + for(let platform in KVKL) { + for(let layer of KVKL[platform].layer) { + for(let row of layer.row) { + for(let key of row.key) { + cleanupKeyTypes(key); + if(key.sk) { + for(let sk of key.sk) { + cleanupKeyTypes(sk); + } + } + } + } + } + } + return true; + } + + return cleanupEmptyArrays() && cleanupTypes(); + }; + +}.bind(builder)); diff --git a/developer/src/tike/xml/layoutbuilder/constants.js b/developer/src/tike/xml/layoutbuilder/constants.js new file mode 100644 index 0000000000..593c7e4ca0 --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/constants.js @@ -0,0 +1,711 @@ +$(function() { + + this.standardKeyNames = [ + 'K_?00', // &H0 + 'K_LBUTTON', // &H1 + 'K_RBUTTON', // &H2 + 'K_CANCEL', // &H3 + 'K_MBUTTON', // &H4 + 'K_?05', // &H5 + 'K_?06', // &H6 + 'K_?07', // &H7 + 'K_BKSP', // &H8 + 'K_TAB', // &H9 + 'K_?0A', // &HA + 'K_?0B', // &HB + 'K_KP5', // &HC + 'K_ENTER', // &HD + 'K_?0E', // &HE + 'K_?0F', // &HF + 'K_SHIFT', // &H10 + 'K_CONTROL', // &H11 + 'K_ALT', // &H12 + 'K_PAUSE', // &H13 + 'K_CAPS', // &H14 + 'K_KANJI?15', // &H15 + 'K_KANJI?16', // &H16 + 'K_KANJI?17', // &H17 + 'K_KANJI?18', // &H18 + 'K_KANJI?19', // &H19 + 'K_?1A', // &H1A + 'K_ESC', // &H1B + 'K_KANJI?1C', // &H1C + 'K_KANJI?1D', // &H1D + 'K_KANJI?1E', // &H1E + 'K_KANJI?1F', // &H1F + 'K_SPACE', // &H20 + 'K_PGUP', // &H21 + 'K_PGDN', // &H22 + 'K_END', // &H23 + 'K_HOME', // &H24 + 'K_LEFT', // &H25 + 'K_UP', // &H26 + 'K_RIGHT', // &H27 + 'K_DOWN', // &H28 + 'K_SEL', // &H29 + 'K_PRINT', // &H2A + 'K_EXEC', // &H2B + 'K_PRTSCN', // &H2C + 'K_INS', // &H2D + 'K_DEL', // &H2E + 'K_HELP', // &H2F + 'K_0', // &H30 + 'K_1', // &H31 + 'K_2', // &H32 + 'K_3', // &H33 + 'K_4', // &H34 + 'K_5', // &H35 + 'K_6', // &H36 + 'K_7', // &H37 + 'K_8', // &H38 + 'K_9', // &H39 + 'K_?3A', // &H3A + 'K_?3B', // &H3B + 'K_?3C', // &H3C + 'K_?3D', // &H3D + 'K_?3E', // &H3E + 'K_?3F', // &H3F + 'K_?40', // &H40 + + 'K_A', // &H41 + 'K_B', // &H42 + 'K_C', // &H43 + 'K_D', // &H44 + 'K_E', // &H45 + 'K_F', // &H46 + 'K_G', // &H47 + 'K_H', // &H48 + 'K_I', // &H49 + 'K_J', // &H4A + 'K_K', // &H4B + 'K_L', // &H4C + 'K_M', // &H4D + 'K_N', // &H4E + 'K_O', // &H4F + 'K_P', // &H50 + 'K_Q', // &H51 + 'K_R', // &H52 + 'K_S', // &H53 + 'K_T', // &H54 + 'K_U', // &H55 + 'K_V', // &H56 + 'K_W', // &H57 + 'K_X', // &H58 + 'K_Y', // &H59 + 'K_Z', // &H5A + 'K_?5B', // &H5B + 'K_?5C', // &H5C + 'K_?5D', // &H5D + 'K_?5E', // &H5E + 'K_?5F', // &H5F + 'K_NP0', // &H60 + 'K_NP1', // &H61 + 'K_NP2', // &H62 + 'K_NP3', // &H63 + 'K_NP4', // &H64 + 'K_NP5', // &H65 + 'K_NP6', // &H66 + 'K_NP7', // &H67 + 'K_NP8', // &H68 + 'K_NP9', // &H69 + 'K_NPSTAR', // &H6A + 'K_NPPLUS', // &H6B + 'K_SEPARATOR', // &H6C + 'K_NPMINUS', // &H6D + 'K_NPDOT', // &H6E + 'K_NPSLASH', // &H6F + 'K_F1', // &H70 + 'K_F2', // &H71 + 'K_F3', // &H72 + 'K_F4', // &H73 + 'K_F5', // &H74 + 'K_F6', // &H75 + 'K_F7', // &H76 + 'K_F8', // &H77 + 'K_F9', // &H78 + 'K_F10', // &H79 + 'K_F11', // &H7A + 'K_F12', // &H7B + 'K_F13', // &H7C + 'K_F14', // &H7D + 'K_F15', // &H7E + 'K_F16', // &H7F + 'K_F17', // &H80 + 'K_F18', // &H81 + 'K_F19', // &H82 + 'K_F20', // &H83 + 'K_F21', // &H84 + 'K_F22', // &H85 + 'K_F23', // &H86 + 'K_F24', // &H87 + + 'K_?88', // &H88 + 'K_?89', // &H89 + 'K_?8A', // &H8A + 'K_?8B', // &H8B + 'K_?8C', // &H8C + 'K_?8D', // &H8D + 'K_?8E', // &H8E + 'K_?8F', // &H8F + + 'K_NUMLOCK', // &H90 + 'K_SCROLL', // &H91 + + 'K_?92', // &H92 + 'K_?93', // &H93 + 'K_?94', // &H94 + 'K_?95', // &H95 + 'K_?96', // &H96 + 'K_?97', // &H97 + 'K_?98', // &H98 + 'K_?99', // &H99 + 'K_?9A', // &H9A + 'K_?9B', // &H9B + 'K_?9C', // &H9C + 'K_?9D', // &H9D + 'K_?9E', // &H9E + 'K_?9F', // &H9F + 'K_?A0', // &HA0 + 'K_?A1', // &HA1 + 'K_?A2', // &HA2 + 'K_?A3', // &HA3 + 'K_?A4', // &HA4 + 'K_?A5', // &HA5 + 'K_?A6', // &HA6 + 'K_?A7', // &HA7 + 'K_?A8', // &HA8 + 'K_?A9', // &HA9 + 'K_?AA', // &HAA + 'K_?AB', // &HAB + 'K_?AC', // &HAC + 'K_?AD', // &HAD + 'K_?AE', // &HAE + 'K_?AF', // &HAF + 'K_?B0', // &HB0 + 'K_?B1', // &HB1 + 'K_?B2', // &HB2 + 'K_?B3', // &HB3 + 'K_?B4', // &HB4 + 'K_?B5', // &HB5 + 'K_?B6', // &HB6 + 'K_?B7', // &HB7 + 'K_?B8', // &HB8 + 'K_?B9', // &HB9 + + 'K_COLON', // &HBA + 'K_EQUAL', // &HBB + 'K_COMMA', // &HBC + 'K_HYPHEN', // &HBD + 'K_PERIOD', // &HBE + 'K_SLASH', // &HBF + 'K_BKQUOTE', // &HC0 + + 'K_?C1', // &HC1 + 'K_?C2', // &HC2 + 'K_?C3', // &HC3 + 'K_?C4', // &HC4 + 'K_?C5', // &HC5 + 'K_?C6', // &HC6 + 'K_?C7', // &HC7 + 'K_?C8', // &HC8 + 'K_?C9', // &HC9 + 'K_?CA', // &HCA + 'K_?CB', // &HCB + 'K_?CC', // &HCC + 'K_?CD', // &HCD + 'K_?CE', // &HCE + 'K_?CF', // &HCF + 'K_?D0', // &HD0 + 'K_?D1', // &HD1 + 'K_?D2', // &HD2 + 'K_?D3', // &HD3 + 'K_?D4', // &HD4 + 'K_?D5', // &HD5 + 'K_?D6', // &HD6 + 'K_?D7', // &HD7 + 'K_?D8', // &HD8 + 'K_?D9', // &HD9 + 'K_?DA', // &HDA + + 'K_LBRKT', // &HDB + 'K_BKSLASH', // &HDC + 'K_RBRKT', // &HDD + 'K_QUOTE', // &HDE + 'K_oDF', // &HDF + 'K_oE0', // &HE0 + 'K_oE1', // &HE1 + 'K_oE2', // &HE2 + 'K_oE3', // &HE3 + 'K_oE4', // &HE4 + + 'K_?E5', // &HE5 + + 'K_oE6', // &HE6 + + 'K_?E7', // &HE7 + 'K_?E8', // &HE8 + + 'K_oE9', // &HE9 + 'K_oEA', // &HEA + 'K_oEB', // &HEB + 'K_oEC', // &HEC + 'K_oED', // &HED + 'K_oEE', // &HEE + 'K_oEF', // &HEF + 'K_oF0', // &HF0 + 'K_oF1', // &HF1 + 'K_oF2', // &HF2 + 'K_oF3', // &HF3 + 'K_oF4', // &HF4 + 'K_oF5', // &HF5 + + 'K_?F6', // &HF6 + 'K_?F7', // &HF7 + 'K_?F8', // &HF8 + 'K_?F9', // &HF9 + 'K_?FA', // &HFA + 'K_?FB', // &HFB + 'K_?FC', // &HFC + 'K_?FD', // &HFD + 'K_?FE', // &HFE + 'K_?FF' // &HFF + ]; + + this.standardKeyCaps = [ + ['',''], // 'K_?00', // &H0 + ['',''], // 'K_LBUTTON', // &H1 + ['',''], // 'K_RBUTTON', // &H2 + ['',''], // 'K_CANCEL', // &H3 + ['',''], // 'K_MBUTTON', // &H4 + ['',''], // 'K_?05', // &H5 + ['',''], // 'K_?06', // &H6 + ['',''], // 'K_?07', // &H7 + ['',''], // 'K_BKSP', // &H8 + ['',''], // 'K_TAB', // &H9 + ['',''], // 'K_?0A', // &HA + ['',''], // 'K_?0B', // &HB + ['',''], // 'K_KP5', // &HC + ['',''], // 'K_ENTER', // &HD + ['',''], // 'K_?0E', // &HE + ['',''], // 'K_?0F', // &HF + ['',''], // 'K_SHIFT', // &H10 + ['',''], // 'K_CONTROL', // &H11 + ['',''], // 'K_ALT', // &H12 + ['',''], // 'K_PAUSE', // &H13 + ['',''], // 'K_CAPS', // &H14 + ['',''], // 'K_KANJI?15', // &H15 + ['',''], // 'K_KANJI?16', // &H16 + ['',''], // 'K_KANJI?17', // &H17 + ['',''], // 'K_KANJI?18', // &H18 + ['',''], // 'K_KANJI?19', // &H19 + ['',''], // 'K_?1A', // &H1A + ['',''], // 'K_ESC', // &H1B + ['',''], // 'K_KANJI?1C', // &H1C + ['',''], // 'K_KANJI?1D', // &H1D + ['',''], // 'K_KANJI?1E', // &H1E + ['',''], // 'K_KANJI?1F', // &H1F + [' ',' '], // 'K_SPACE', // &H20 + ['',''], // 'K_PGUP', // &H21 + ['',''], // 'K_PGDN', // &H22 + ['',''], // 'K_END', // &H23 + ['',''], // 'K_HOME', // &H24 + ['',''], // 'K_LEFT', // &H25 + ['',''], // 'K_UP', // &H26 + ['',''], // 'K_RIGHT', // &H27 + ['',''], // 'K_DOWN', // &H28 + ['',''], // 'K_SEL', // &H29 + ['',''], // 'K_PRINT', // &H2A + ['',''], // 'K_EXEC', // &H2B + ['',''], // 'K_PRTSCN', // &H2C + ['',''], // 'K_INS', // &H2D + ['',''], // 'K_DEL', // &H2E + ['',''], // 'K_HELP', // &H2F + ['0',')'], // 'K_0', // &H30 + ['1','!'], // 'K_1', // &H31 + ['2','@'], // 'K_2', // &H32 + ['3','#'], // 'K_3', // &H33 + ['4','$'], // 'K_4', // &H34 + ['5','%'], // 'K_5', // &H35 + ['6','^'], // 'K_6', // &H36 + ['7','&'], // 'K_7', // &H37 + ['8','*'], // 'K_8', // &H38 + ['9','('], // 'K_9', // &H39 + ['',''], // 'K_?3A', // &H3A + ['',''], // 'K_?3B', // &H3B + ['',''], // 'K_?3C', // &H3C + ['',''], // 'K_?3D', // &H3D + ['',''], // 'K_?3E', // &H3E + ['',''], // 'K_?3F', // &H3F + ['',''], // 'K_?40', // &H40 + + ['a','A'], // 'K_A', // &H41 + ['b','B'], // 'K_B', // &H42 + ['c','C'], // 'K_C', // &H43 + ['d','D'], // 'K_D', // &H44 + ['e','E'], // 'K_E', // &H45 + ['f','F'], // 'K_F', // &H46 + ['g','G'], // 'K_G', // &H47 + ['h','H'], // 'K_H', // &H48 + ['i','I'], // 'K_I', // &H49 + ['j','J'], // 'K_J', // &H4A + ['k','K'], // 'K_K', // &H4B + ['l','L'], // 'K_L', // &H4C + ['m','M'], // 'K_M', // &H4D + ['n','N'], // 'K_N', // &H4E + ['o','O'], // 'K_O', // &H4F + ['p','P'], // 'K_P', // &H50 + ['q','Q'], // 'K_Q', // &H51 + ['r','R'], // 'K_R', // &H52 + ['s','S'], // 'K_S', // &H53 + ['t','T'], // 'K_T', // &H54 + ['u','U'], // 'K_U', // &H55 + ['v','V'], // 'K_V', // &H56 + ['w','W'], // 'K_W', // &H57 + ['x','X'], // 'K_X', // &H58 + ['y','Y'], // 'K_Y', // &H59 + ['z','Z'], // 'K_Z', // &H5A + ['',''], // 'K_?5B', // &H5B + ['',''], // 'K_?5C', // &H5C + ['',''], // 'K_?5D', // &H5D + ['',''], // 'K_?5E', // &H5E + ['',''], // 'K_?5F', // &H5F + ['',''], // 'K_NP0', // &H60 + ['',''], // 'K_NP1', // &H61 + ['',''], // 'K_NP2', // &H62 + ['',''], // 'K_NP3', // &H63 + ['',''], // 'K_NP4', // &H64 + ['',''], // 'K_NP5', // &H65 + ['',''], // 'K_NP6', // &H66 + ['',''], // 'K_NP7', // &H67 + ['',''], // 'K_NP8', // &H68 + ['',''], // 'K_NP9', // &H69 + ['',''], // 'K_NPSTAR', // &H6A + ['',''], // 'K_NPPLUS', // &H6B + ['',''], // 'K_SEPARATOR', // &H6C + ['',''], // 'K_NPMINUS', // &H6D + ['',''], // 'K_NPDOT', // &H6E + ['',''], // 'K_NPSLASH', // &H6F + ['',''], // 'K_F1', // &H70 + ['',''], // 'K_F2', // &H71 + ['',''], // 'K_F3', // &H72 + ['',''], // 'K_F4', // &H73 + ['',''], // 'K_F5', // &H74 + ['',''], // 'K_F6', // &H75 + ['',''], // 'K_F7', // &H76 + ['',''], // 'K_F8', // &H77 + ['',''], // 'K_F9', // &H78 + ['',''], // 'K_F10', // &H79 + ['',''], // 'K_F11', // &H7A + ['',''], // 'K_F12', // &H7B + ['',''], // 'K_F13', // &H7C + ['',''], // 'K_F14', // &H7D + ['',''], // 'K_F15', // &H7E + ['',''], // 'K_F16', // &H7F + ['',''], // 'K_F17', // &H80 + ['',''], // 'K_F18', // &H81 + ['',''], // 'K_F19', // &H82 + ['',''], // 'K_F20', // &H83 + ['',''], // 'K_F21', // &H84 + ['',''], // 'K_F22', // &H85 + ['',''], // 'K_F23', // &H86 + ['',''], // 'K_F24', // &H87 + + ['',''], // 'K_?88', // &H88 + ['',''], // 'K_?89', // &H89 + ['',''], // 'K_?8A', // &H8A + ['',''], // 'K_?8B', // &H8B + ['',''], // 'K_?8C', // &H8C + ['',''], // 'K_?8D', // &H8D + ['',''], // 'K_?8E', // &H8E + ['',''], // 'K_?8F', // &H8F + + ['',''], // 'K_NUMLOCK', // &H90 + ['',''], // 'K_SCROLL', // &H91 + + ['',''], // 'K_?92', // &H92 + ['',''], // 'K_?93', // &H93 + ['',''], // 'K_?94', // &H94 + ['',''], // 'K_?95', // &H95 + ['',''], // 'K_?96', // &H96 + ['',''], // 'K_?97', // &H97 + ['',''], // 'K_?98', // &H98 + ['',''], // 'K_?99', // &H99 + ['',''], // 'K_?9A', // &H9A + ['',''], // 'K_?9B', // &H9B + ['',''], // 'K_?9C', // &H9C + ['',''], // 'K_?9D', // &H9D + ['',''], // 'K_?9E', // &H9E + ['',''], // 'K_?9F', // &H9F + ['',''], // 'K_?A0', // &HA0 + ['',''], // 'K_?A1', // &HA1 + ['',''], // 'K_?A2', // &HA2 + ['',''], // 'K_?A3', // &HA3 + ['',''], // 'K_?A4', // &HA4 + ['',''], // 'K_?A5', // &HA5 + ['',''], // 'K_?A6', // &HA6 + ['',''], // 'K_?A7', // &HA7 + ['',''], // 'K_?A8', // &HA8 + ['',''], // 'K_?A9', // &HA9 + ['',''], // 'K_?AA', // &HAA + ['',''], // 'K_?AB', // &HAB + ['',''], // 'K_?AC', // &HAC + ['',''], // 'K_?AD', // &HAD + ['',''], // 'K_?AE', // &HAE + ['',''], // 'K_?AF', // &HAF + ['',''], // 'K_?B0', // &HB0 + ['',''], // 'K_?B1', // &HB1 + ['',''], // 'K_?B2', // &HB2 + ['',''], // 'K_?B3', // &HB3 + ['',''], // 'K_?B4', // &HB4 + ['',''], // 'K_?B5', // &HB5 + ['',''], // 'K_?B6', // &HB6 + ['',''], // 'K_?B7', // &HB7 + ['',''], // 'K_?B8', // &HB8 + ['',''], // 'K_?B9', // &HB9 + + [';',':'], // 'K_COLON', // &HBA + ['=','+'], // 'K_EQUAL', // &HBB + [',','<'], // 'K_COMMA', // &HBC + ['-','_'], // 'K_HYPHEN', // &HBD + ['.','>'], // 'K_PERIOD', // &HBE + ['/','?'], // 'K_SLASH', // &HBF + ['`','~'], // 'K_BKQUOTE', // &HC0 + + ['',''], // 'K_?C1', // &HC1 + ['',''], // 'K_?C2', // &HC2 + ['',''], // 'K_?C3', // &HC3 + ['',''], // 'K_?C4', // &HC4 + ['',''], // 'K_?C5', // &HC5 + ['',''], // 'K_?C6', // &HC6 + ['',''], // 'K_?C7', // &HC7 + ['',''], // 'K_?C8', // &HC8 + ['',''], // 'K_?C9', // &HC9 + ['',''], // 'K_?CA', // &HCA + ['',''], // 'K_?CB', // &HCB + ['',''], // 'K_?CC', // &HCC + ['',''], // 'K_?CD', // &HCD + ['',''], // 'K_?CE', // &HCE + ['',''], // 'K_?CF', // &HCF + ['',''], // 'K_?D0', // &HD0 + ['',''], // 'K_?D1', // &HD1 + ['',''], // 'K_?D2', // &HD2 + ['',''], // 'K_?D3', // &HD3 + ['',''], // 'K_?D4', // &HD4 + ['',''], // 'K_?D5', // &HD5 + ['',''], // 'K_?D6', // &HD6 + ['',''], // 'K_?D7', // &HD7 + ['',''], // 'K_?D8', // &HD8 + ['',''], // 'K_?D9', // &HD9 + ['',''], // 'K_?DA', // &HDA + + ['[','{'], // 'K_LBRKT', // &HDB + ['\\','|'], // 'K_BKSLASH', // &HDC + [']','}'], // 'K_RBRKT', // &HDD + ['\'','"'], // 'K_QUOTE', // &HDE + ['',''], // 'K_oDF', // &HDF + ['',''], // 'K_oE0', // &HE0 + ['',''], // 'K_oE1', // &HE1 + ['\\','|'], // 'K_oE2', // &HE2 + ['',''], // 'K_oE3', // &HE3 + ['',''], // 'K_oE4', // &HE4 + + ['',''], // 'K_?E5', // &HE5 + + ['',''], // 'K_oE6', // &HE6 + + ['',''], // 'K_?E7', // &HE7 + ['',''], // 'K_?E8', // &HE8 + + ['',''], // 'K_oE9', // &HE9 + ['',''], // 'K_oEA', // &HEA + ['',''], // 'K_oEB', // &HEB + ['',''], // 'K_oEC', // &HEC + ['',''], // 'K_oED', // &HED + ['',''], // 'K_oEE', // &HEE + ['',''], // 'K_oEF', // &HEF + ['',''], // 'K_oF0', // &HF0 + ['',''], // 'K_oF1', // &HF1 + ['',''], // 'K_oF2', // &HF2 + ['',''], // 'K_oF3', // &HF3 + ['',''], // 'K_oF4', // &HF4 + ['',''], // 'K_oF5', // &HF5 + + ['',''], // 'K_?F6', // &HF6 + ['',''], // 'K_?F7', // &HF7 + ['',''], // 'K_?F8', // &HF8 + ['',''], // 'K_?F9', // &HF9 + ['',''], // 'K_?FA', // &HFA + ['',''], // 'K_?FB', // &HFB + ['',''], // 'K_?FC', // &HFC + ['',''], // 'K_?FD', // &HFD + ['',''], // 'K_?FE', // &HFE + ['',''], // 'K_?FF' // &HFF + ]; + + this.lookupKeyNames = []; + + for (var i = 0; i < this.standardKeyNames.length; i++) { + if (this.standardKeyNames[i].indexOf('?') < 0) { + this.lookupKeyNames.push(this.standardKeyNames[i]); + } + } + this.lookupKeyNames.sort(); + + // Defines the PUA code mapping for the various 'special' modifier/control keys on keyboards. + // This is lifted directly from visualKeyboard.ts and must be kept in sync. See also CompileKeymanWeb.pas: CSpecialText10 + this.specialCharacters = { + '*Shift*': 8, + '*Enter*': 5, + '*Tab*': 6, + '*BkSp*': 4, + '*Menu*': 11, + '*Hide*': 10, + '*Alt*': 25, + '*Ctrl*': 1, + '*Caps*': 3, + '*ABC*': 16, + '*abc*': 17, + '*123*': 19, + '*Symbol*': 21, + '*Currency*': 20, + '*Shifted*': 9, + '*AltGr*': 2, + '*TabLeft*': 7, + '*LAlt*': 0x56, + '*RAlt*': 0x57, + '*LCtrl*': 0x58, + '*RCtrl*': 0x59, + '*LAltCtrl*': 0x60, + '*RAltCtrl*': 0x61, + '*LAltCtrlShift*': 0x62, + '*RAltCtrlShift*': 0x63, + '*AltShift*': 0x64, + '*CtrlShift*': 0x65, + '*AltCtrlShift*': 0x66, + '*LAltShift*': 0x67, + '*RAltShift*': 0x68, + '*LCtrlShift*': 0x69, + '*RCtrlShift*': 0x70, + // Following codes introduced in Keyman 14.0 + '*RTLEnter*': 0x71, + '*RTLBkSp*': 0x72, + '*ShiftLock*': 0x73, + '*ShiftedLock*': 0x74, + '*ZWNJ*': 0x75, // * If this one is specified, auto-detection will kick in. + '*ZWNJiOS*': 0x75, // The iOS version will be used by default, but the + '*ZWNJAndroid*': 0x76, // Android platform has its own default glyph. + '*LTREnter*': 5, // * Forces LTR shaping for the Enter/BkSp keys regardless + '*LTRBkSp*': 4, // of layout's directionality. + }; + + this.specialKeyNames = Object.entries(this.specialCharacters).map(ch => ch[0]); + + this.presentations = { + "tablet-ipad-landscape": { "x": 829, "y": 299, "name": "iPad (landscape)" }, // 829x622 = iPad tablet box size; (97,101)-(926,723) + "tablet-ipad-portrait": { "x": 605, "y": 300, "name": "iPad (portrait)" }, // 605x806 = iPad tablet box size; (98,94)-(703,900) + "phone-iphone5-landscape": { "x": 731, "y": 196, "name": "iPhone 5 (landscape)" }, // 731x412 = iPhone box size; (144,39)-(875,451) + "phone-iphone5-portrait": { "x": 526, "y": 266, "name": "iPhone 5 (portrait)"} // 528x936 = iPhone box size; (90,204)-(618,1040) + }; + + this.keyMargin = 15; + + // from kmwosk.js: + this.modifierCodes = { + "LCTRL":0x0001, + "RCTRL":0x0002, + "LALT":0x0004, + "RALT":0x0008, + "SHIFT":0x0010, + "CTRL":0x0020, + "ALT":0x0040, + "CAPS":0x0100, + "NO_CAPS":0x0200 + /*"NUM_LOCK":0x0400, We don't support these in the designer + "NO_NUM_LOCK":0x0800, + "SCROLL_LOCK":0x1000, + "NO_SCROLL_LOCK":0x2000, + "VIRTUAL_KEY":0x4000*/ + }; + + // Lists the combinations that we allow users to use. Some are mutually exclusive, + // such as Left+Right modifiers, or chiral and non-chiral modifiers (excl. Shift) + this.validModifierCombinations = [ + 0, + + this.modifierCodes.LCTRL, + this.modifierCodes.RCTRL, + + this.modifierCodes.LALT, + this.modifierCodes.LCTRL | this.modifierCodes.LALT, + + this.modifierCodes.RALT, + this.modifierCodes.RCTRL | this.modifierCodes.RALT, + + this.modifierCodes.SHIFT, + + this.modifierCodes.LCTRL | this.modifierCodes.SHIFT, + this.modifierCodes.LALT | this.modifierCodes.SHIFT, + this.modifierCodes.LCTRL | this.modifierCodes.LALT | this.modifierCodes.SHIFT, + + this.modifierCodes.RCTRL | this.modifierCodes.SHIFT, + this.modifierCodes.RALT | this.modifierCodes.SHIFT, + this.modifierCodes.RCTRL | this.modifierCodes.RALT | this.modifierCodes.SHIFT, + + this.modifierCodes.CTRL, + this.modifierCodes.CTRL | this.modifierCodes.SHIFT, + + this.modifierCodes.ALT, + this.modifierCodes.CTRL | this.modifierCodes.ALT, + this.modifierCodes.SHIFT | this.modifierCodes.ALT, + this.modifierCodes.SHIFT | this.modifierCodes.CTRL | this.modifierCodes.ALT, + this.modifierCodes.CAPS + ]; + + this.minimalModifierCombinations = [ + 0, + this.modifierCodes.RALT, + this.modifierCodes.SHIFT, + this.modifierCodes.RALT | this.modifierCodes.SHIFT, + this.modifierCodes.CAPS + ]; + + this.showAllModifierCombinations = false; + + // Add CAPS and NO_CAPS variants for all of the above + (function(c, codes) { + var i, n = c.length; + for(i = 0; i < n; i++) + c.push(c[i] | codes.CAPS); + for(i = 0; i < n; i++) + c.push(c[i] | codes.NO_CAPS); + })(this.validModifierCombinations, this.modifierCodes); + + this.modifierNames = [ + 'leftctrl', // 0x001 + 'rightctrl', // 0x002 + 'leftalt', // 0x004 + 'rightalt', // 0x008 + 'shift', // 0x010 + 'ctrl', // 0x020 + 'alt', // 0x040 + '', // 0x080 - reserved + 'caps', // 0x100 + 'nocaps' // 0x200 + ]; + + /** + * Get kebab-cased full name of a modifier combination given a bitmask + * + * @param {Number} c + * @return {string} + **/ + this.getModifierCombinationName = function(c) { + var r = ''; + if(c == 0) return 'default'; + for(var i = 0; i < this.modifierNames.length; i++) { + if(c & (1<'; + return '
'; + }); + $(elements[1]).append('
'); + + $('.key-droppable').css('margin-top', $(this).css('margin-top')).css('height', $(this).css('height')).droppable({ + accept: ".key", + tolerance: "touch", + over: function (_event, _ui) { + drag.overList.push(this); + $(drag.overList[0]).addClass('key-droppable-hover'); + }, + out: function (_event, _ui) { + var n = drag.overList.indexOf(this); + if (n >= 0) + drag.overList.splice(n, 1); + $(this).removeClass('key-droppable-hover'); + if (drag.overList.length > 0) $(drag.overList[0]).addClass('key-droppable-hover'); + }, + drop: function (_event, _ui) { + // + // Drop the selected key into its new position + // + builder.saveUndo(); + $(drag).detach().removeClass('key-dragging'); + $(drag.overList[0]).after(drag); + if (selectedKeyType == 'key') builder.rescale(); else builder.generateSubKeys(); + builder.generate(); + } + }); + $('.key-current').css('width', $(drag).width() + 'px').css('margin-left', -($(drag).width()) + 'px'); + }, + stop: function (_event, _ui) { + $('.key-droppable').remove(); + $(this).removeClass('key-dragging'); + } + }); + } +}.bind(builder)); \ No newline at end of file diff --git a/developer/src/tike/xml/layoutbuilder/flick-e.svg b/developer/src/tike/xml/layoutbuilder/flick-e.svg new file mode 100644 index 0000000000..edba9c461c --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/flick-e.svg @@ -0,0 +1,3 @@ + + + diff --git a/developer/src/tike/xml/layoutbuilder/flick-n.svg b/developer/src/tike/xml/layoutbuilder/flick-n.svg new file mode 100644 index 0000000000..969a1e7885 --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/flick-n.svg @@ -0,0 +1,3 @@ + + + diff --git a/developer/src/tike/xml/layoutbuilder/flick-ne.svg b/developer/src/tike/xml/layoutbuilder/flick-ne.svg new file mode 100644 index 0000000000..0618808e45 --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/flick-ne.svg @@ -0,0 +1,3 @@ + + + diff --git a/developer/src/tike/xml/layoutbuilder/flick-nw.svg b/developer/src/tike/xml/layoutbuilder/flick-nw.svg new file mode 100644 index 0000000000..bb8267e254 --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/flick-nw.svg @@ -0,0 +1,3 @@ + + + diff --git a/developer/src/tike/xml/layoutbuilder/flick-s.svg b/developer/src/tike/xml/layoutbuilder/flick-s.svg new file mode 100644 index 0000000000..cba4157186 --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/flick-s.svg @@ -0,0 +1,3 @@ + + + diff --git a/developer/src/tike/xml/layoutbuilder/flick-se.svg b/developer/src/tike/xml/layoutbuilder/flick-se.svg new file mode 100644 index 0000000000..6292a793aa --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/flick-se.svg @@ -0,0 +1,3 @@ + + + diff --git a/developer/src/tike/xml/layoutbuilder/flick-sw.svg b/developer/src/tike/xml/layoutbuilder/flick-sw.svg new file mode 100644 index 0000000000..bffe48698c --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/flick-sw.svg @@ -0,0 +1,3 @@ + + + diff --git a/developer/src/tike/xml/layoutbuilder/flick-w.svg b/developer/src/tike/xml/layoutbuilder/flick-w.svg new file mode 100644 index 0000000000..068e6be025 --- /dev/null +++ b/developer/src/tike/xml/layoutbuilder/flick-w.svg @@ -0,0 +1,3 @@ + + + diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-bg_flat_0_aaaaaa_40x100.png b/developer/src/tike/xml/layoutbuilder/images/ui-bg_flat_0_aaaaaa_40x100.png new file mode 100644 index 0000000000..4743d097e1 Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-bg_flat_0_aaaaaa_40x100.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-bg_flat_75_ffffff_40x100.png b/developer/src/tike/xml/layoutbuilder/images/ui-bg_flat_75_ffffff_40x100.png new file mode 100644 index 0000000000..ca779e35d8 Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-bg_flat_75_ffffff_40x100.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_55_fbf9ee_1x400.png b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_55_fbf9ee_1x400.png new file mode 100644 index 0000000000..664038172a Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_55_fbf9ee_1x400.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_65_ffffff_1x400.png b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000000..d3277b5e96 Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_75_dadada_1x400.png b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_75_dadada_1x400.png new file mode 100644 index 0000000000..7eda20a597 Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_75_dadada_1x400.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_75_e6e6e6_1x400.png b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_75_e6e6e6_1x400.png new file mode 100644 index 0000000000..f4d86b963e Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_75_e6e6e6_1x400.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_95_fef1ec_1x400.png b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_95_fef1ec_1x400.png new file mode 100644 index 0000000000..8500938dc4 Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-bg_glass_95_fef1ec_1x400.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-bg_highlight-soft_75_cccccc_1x100.png b/developer/src/tike/xml/layoutbuilder/images/ui-bg_highlight-soft_75_cccccc_1x100.png new file mode 100644 index 0000000000..4795f69737 Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-bg_highlight-soft_75_cccccc_1x100.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-icons_222222_256x240.png b/developer/src/tike/xml/layoutbuilder/images/ui-icons_222222_256x240.png new file mode 100644 index 0000000000..c7dab31206 Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-icons_222222_256x240.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-icons_2e83ff_256x240.png b/developer/src/tike/xml/layoutbuilder/images/ui-icons_2e83ff_256x240.png new file mode 100644 index 0000000000..e04e87a76b Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-icons_2e83ff_256x240.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-icons_454545_256x240.png b/developer/src/tike/xml/layoutbuilder/images/ui-icons_454545_256x240.png new file mode 100644 index 0000000000..825ce7bf07 Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-icons_454545_256x240.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-icons_888888_256x240.png b/developer/src/tike/xml/layoutbuilder/images/ui-icons_888888_256x240.png new file mode 100644 index 0000000000..e2d9f906b7 Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-icons_888888_256x240.png differ diff --git a/developer/src/tike/xml/layoutbuilder/images/ui-icons_cd0a0a_256x240.png b/developer/src/tike/xml/layoutbuilder/images/ui-icons_cd0a0a_256x240.png new file mode 100644 index 0000000000..b13299903c Binary files /dev/null and b/developer/src/tike/xml/layoutbuilder/images/ui-icons_cd0a0a_256x240.png differ diff --git a/developer/src/tike/xml/layoutbuilder/jquery-ui.js b/developer/src/tike/xml/layoutbuilder/jquery-ui.js deleted file mode 100644 index 7b727e7435..0000000000 --- a/developer/src/tike/xml/layoutbuilder/jquery-ui.js +++ /dev/null @@ -1,15003 +0,0 @@ -/*! jQuery UI - v1.10.3 - 2013-05-03 -* http://jqueryui.com -* Includes: jquery.ui.core.js, jquery.ui.widget.js, jquery.ui.mouse.js, jquery.ui.draggable.js, jquery.ui.droppable.js, jquery.ui.resizable.js, jquery.ui.selectable.js, jquery.ui.sortable.js, jquery.ui.effect.js, jquery.ui.accordion.js, jquery.ui.autocomplete.js, jquery.ui.button.js, jquery.ui.datepicker.js, jquery.ui.dialog.js, jquery.ui.effect-blind.js, jquery.ui.effect-bounce.js, jquery.ui.effect-clip.js, jquery.ui.effect-drop.js, jquery.ui.effect-explode.js, jquery.ui.effect-fade.js, jquery.ui.effect-fold.js, jquery.ui.effect-highlight.js, jquery.ui.effect-pulsate.js, jquery.ui.effect-scale.js, jquery.ui.effect-shake.js, jquery.ui.effect-slide.js, jquery.ui.effect-transfer.js, jquery.ui.menu.js, jquery.ui.position.js, jquery.ui.progressbar.js, jquery.ui.slider.js, jquery.ui.spinner.js, jquery.ui.tabs.js, jquery.ui.tooltip.js -* Copyright 2013 jQuery Foundation and other contributors; Licensed MIT */ -(function( $, undefined ) { - -var uuid = 0, - runiqueId = /^ui-id-\d+$/; - -// $.ui might exist from components with no dependencies, e.g., $.ui.position -$.ui = $.ui || {}; - -$.extend( $.ui, { - version: "1.10.3", - - keyCode: { - BACKSPACE: 8, - COMMA: 188, - DELETE: 46, - DOWN: 40, - END: 35, - ENTER: 13, - ESCAPE: 27, - HOME: 36, - LEFT: 37, - NUMPAD_ADD: 107, - NUMPAD_DECIMAL: 110, - NUMPAD_DIVIDE: 111, - NUMPAD_ENTER: 108, - NUMPAD_MULTIPLY: 106, - NUMPAD_SUBTRACT: 109, - PAGE_DOWN: 34, - PAGE_UP: 33, - PERIOD: 190, - RIGHT: 39, - SPACE: 32, - TAB: 9, - UP: 38 - } -}); - -// plugins -$.fn.extend({ - focus: (function( orig ) { - return function( delay, fn ) { - return typeof delay === "number" ? - this.each(function() { - var elem = this; - setTimeout(function() { - $( elem ).focus(); - if ( fn ) { - fn.call( elem ); - } - }, delay ); - }) : - orig.apply( this, arguments ); - }; - })( $.fn.focus ), - - scrollParent: function() { - var scrollParent; - if (($.ui.ie && (/(static|relative)/).test(this.css("position"))) || (/absolute/).test(this.css("position"))) { - scrollParent = this.parents().filter(function() { - return (/(relative|absolute|fixed)/).test($.css(this,"position")) && (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } else { - scrollParent = this.parents().filter(function() { - return (/(auto|scroll)/).test($.css(this,"overflow")+$.css(this,"overflow-y")+$.css(this,"overflow-x")); - }).eq(0); - } - - return (/fixed/).test(this.css("position")) || !scrollParent.length ? $(document) : scrollParent; - }, - - zIndex: function( zIndex ) { - if ( zIndex !== undefined ) { - return this.css( "zIndex", zIndex ); - } - - if ( this.length ) { - var elem = $( this[ 0 ] ), position, value; - while ( elem.length && elem[ 0 ] !== document ) { - // Ignore z-index if position is set to a value where z-index is ignored by the browser - // This makes behavior of this function consistent across browsers - // WebKit always returns auto if the element is positioned - position = elem.css( "position" ); - if ( position === "absolute" || position === "relative" || position === "fixed" ) { - // IE returns 0 when zIndex is not specified - // other browsers return a string - // we ignore the case of nested elements with an explicit value of 0 - //
- value = parseInt( elem.css( "zIndex" ), 10 ); - if ( !isNaN( value ) && value !== 0 ) { - return value; - } - } - elem = elem.parent(); - } - } - - return 0; - }, - - uniqueId: function() { - return this.each(function() { - if ( !this.id ) { - this.id = "ui-id-" + (++uuid); - } - }); - }, - - removeUniqueId: function() { - return this.each(function() { - if ( runiqueId.test( this.id ) ) { - $( this ).removeAttr( "id" ); - } - }); - } -}); - -// selectors -function focusable( element, isTabIndexNotNaN ) { - var map, mapName, img, - nodeName = element.nodeName.toLowerCase(); - if ( "area" === nodeName ) { - map = element.parentNode; - mapName = map.name; - if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { - return false; - } - img = $( "img[usemap=#" + mapName + "]" )[0]; - return !!img && visible( img ); - } - return ( /input|select|textarea|button|object/.test( nodeName ) ? - !element.disabled : - "a" === nodeName ? - element.href || isTabIndexNotNaN : - isTabIndexNotNaN) && - // the element and all of its ancestors must be visible - visible( element ); -} - -function visible( element ) { - return $.expr.filters.visible( element ) && - !$( element ).parents().addBack().filter(function() { - return $.css( this, "visibility" ) === "hidden"; - }).length; -} - -$.extend( $.expr[ ":" ], { - data: $.expr.createPseudo ? - $.expr.createPseudo(function( dataName ) { - return function( elem ) { - return !!$.data( elem, dataName ); - }; - }) : - // support: jQuery <1.8 - function( elem, i, match ) { - return !!$.data( elem, match[ 3 ] ); - }, - - focusable: function( element ) { - return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) ); - }, - - tabbable: function( element ) { - var tabIndex = $.attr( element, "tabindex" ), - isTabIndexNaN = isNaN( tabIndex ); - return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN ); - } -}); - -// support: jQuery <1.8 -if ( !$( "" ).outerWidth( 1 ).jquery ) { - $.each( [ "Width", "Height" ], function( i, name ) { - var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ], - type = name.toLowerCase(), - orig = { - innerWidth: $.fn.innerWidth, - innerHeight: $.fn.innerHeight, - outerWidth: $.fn.outerWidth, - outerHeight: $.fn.outerHeight - }; - - function reduce( elem, size, border, margin ) { - $.each( side, function() { - size -= parseFloat( $.css( elem, "padding" + this ) ) || 0; - if ( border ) { - size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0; - } - if ( margin ) { - size -= parseFloat( $.css( elem, "margin" + this ) ) || 0; - } - }); - return size; - } - - $.fn[ "inner" + name ] = function( size ) { - if ( size === undefined ) { - return orig[ "inner" + name ].call( this ); - } - - return this.each(function() { - $( this ).css( type, reduce( this, size ) + "px" ); - }); - }; - - $.fn[ "outer" + name] = function( size, margin ) { - if ( typeof size !== "number" ) { - return orig[ "outer" + name ].call( this, size ); - } - - return this.each(function() { - $( this).css( type, reduce( this, size, true, margin ) + "px" ); - }); - }; - }); -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413) -if ( $( "" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) { - $.fn.removeData = (function( removeData ) { - return function( key ) { - if ( arguments.length ) { - return removeData.call( this, $.camelCase( key ) ); - } else { - return removeData.call( this ); - } - }; - })( $.fn.removeData ); -} - - - - - -// deprecated -$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() ); - -$.support.selectstart = "onselectstart" in document.createElement( "div" ); -$.fn.extend({ - disableSelection: function() { - return this.bind( ( $.support.selectstart ? "selectstart" : "mousedown" ) + - ".ui-disableSelection", function( event ) { - event.preventDefault(); - }); - }, - - enableSelection: function() { - return this.unbind( ".ui-disableSelection" ); - } -}); - -$.extend( $.ui, { - // $.ui.plugin is deprecated. Use $.widget() extensions instead. - plugin: { - add: function( module, option, set ) { - var i, - proto = $.ui[ module ].prototype; - for ( i in set ) { - proto.plugins[ i ] = proto.plugins[ i ] || []; - proto.plugins[ i ].push( [ option, set[ i ] ] ); - } - }, - call: function( instance, name, args ) { - var i, - set = instance.plugins[ name ]; - if ( !set || !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) { - return; - } - - for ( i = 0; i < set.length; i++ ) { - if ( instance.options[ set[ i ][ 0 ] ] ) { - set[ i ][ 1 ].apply( instance.element, args ); - } - } - } - }, - - // only used by resizable - hasScroll: function( el, a ) { - - //If overflow is hidden, the element might have extra content, but the user wants to hide it - if ( $( el ).css( "overflow" ) === "hidden") { - return false; - } - - var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop", - has = false; - - if ( el[ scroll ] > 0 ) { - return true; - } - - // TODO: determine which cases actually cause this to happen - // if the element doesn't have the scroll set, see if it's possible to - // set the scroll - el[ scroll ] = 1; - has = ( el[ scroll ] > 0 ); - el[ scroll ] = 0; - return has; - } -}); - -})( jQuery ); - -(function( $, undefined ) { - -var uuid = 0, - slice = Array.prototype.slice, - _cleanData = $.cleanData; -$.cleanData = function( elems ) { - for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { - try { - $( elem ).triggerHandler( "remove" ); - // http://bugs.jquery.com/ticket/8235 - } catch( e ) {} - } - _cleanData( elems ); -}; - -$.widget = function( name, base, prototype ) { - var fullName, existingConstructor, constructor, basePrototype, - // proxiedPrototype allows the provided prototype to remain unmodified - // so that it can be used as a mixin for multiple widgets (#8876) - proxiedPrototype = {}, - namespace = name.split( "." )[ 0 ]; - - name = name.split( "." )[ 1 ]; - fullName = namespace + "-" + name; - - if ( !prototype ) { - prototype = base; - base = $.Widget; - } - - // create selector for plugin - $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { - return !!$.data( elem, fullName ); - }; - - $[ namespace ] = $[ namespace ] || {}; - existingConstructor = $[ namespace ][ name ]; - constructor = $[ namespace ][ name ] = function( options, element ) { - // allow instantiation without "new" keyword - if ( !this._createWidget ) { - return new constructor( options, element ); - } - - // allow instantiation without initializing for simple inheritance - // must use "new" keyword (the code above always passes args) - if ( arguments.length ) { - this._createWidget( options, element ); - } - }; - // extend with the existing constructor to carry over any static properties - $.extend( constructor, existingConstructor, { - version: prototype.version, - // copy the object used to create the prototype in case we need to - // redefine the widget later - _proto: $.extend( {}, prototype ), - // track widgets that inherit from this widget in case this widget is - // redefined after a widget inherits from it - _childConstructors: [] - }); - - basePrototype = new base(); - // we need to make the options hash a property directly on the new instance - // otherwise we'll modify the options hash on the prototype that we're - // inheriting from - basePrototype.options = $.widget.extend( {}, basePrototype.options ); - $.each( prototype, function( prop, value ) { - if ( !$.isFunction( value ) ) { - proxiedPrototype[ prop ] = value; - return; - } - proxiedPrototype[ prop ] = (function() { - var _super = function() { - return base.prototype[ prop ].apply( this, arguments ); - }, - _superApply = function( args ) { - return base.prototype[ prop ].apply( this, args ); - }; - return function() { - var __super = this._super, - __superApply = this._superApply, - returnValue; - - this._super = _super; - this._superApply = _superApply; - - returnValue = value.apply( this, arguments ); - - this._super = __super; - this._superApply = __superApply; - - return returnValue; - }; - })(); - }); - constructor.prototype = $.widget.extend( basePrototype, { - // TODO: remove support for widgetEventPrefix - // always use the name + a colon as the prefix, e.g., draggable:start - // don't prefix for widgets that aren't DOM-based - widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name - }, proxiedPrototype, { - constructor: constructor, - namespace: namespace, - widgetName: name, - widgetFullName: fullName - }); - - // If this widget is being redefined then we need to find all widgets that - // are inheriting from it and redefine all of them so that they inherit from - // the new version of this widget. We're essentially trying to replace one - // level in the prototype chain. - if ( existingConstructor ) { - $.each( existingConstructor._childConstructors, function( i, child ) { - var childPrototype = child.prototype; - - // redefine the child widget using the same prototype that was - // originally used, but inherit from the new version of the base - $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); - }); - // remove the list of existing child constructors from the old constructor - // so the old child constructors can be garbage collected - delete existingConstructor._childConstructors; - } else { - base._childConstructors.push( constructor ); - } - - $.widget.bridge( name, constructor ); -}; - -$.widget.extend = function( target ) { - var input = slice.call( arguments, 1 ), - inputIndex = 0, - inputLength = input.length, - key, - value; - for ( ; inputIndex < inputLength; inputIndex++ ) { - for ( key in input[ inputIndex ] ) { - value = input[ inputIndex ][ key ]; - if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { - // Clone objects - if ( $.isPlainObject( value ) ) { - target[ key ] = $.isPlainObject( target[ key ] ) ? - $.widget.extend( {}, target[ key ], value ) : - // Don't extend strings, arrays, etc. with objects - $.widget.extend( {}, value ); - // Copy everything else by reference - } else { - target[ key ] = value; - } - } - } - } - return target; -}; - -$.widget.bridge = function( name, object ) { - var fullName = object.prototype.widgetFullName || name; - $.fn[ name ] = function( options ) { - var isMethodCall = typeof options === "string", - args = slice.call( arguments, 1 ), - returnValue = this; - - // allow multiple hashes to be passed on init - options = !isMethodCall && args.length ? - $.widget.extend.apply( null, [ options ].concat(args) ) : - options; - - if ( isMethodCall ) { - this.each(function() { - var methodValue, - instance = $.data( this, fullName ); - if ( !instance ) { - return $.error( "cannot call methods on " + name + " prior to initialization; " + - "attempted to call method '" + options + "'" ); - } - if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { - return $.error( "no such method '" + options + "' for " + name + " widget instance" ); - } - methodValue = instance[ options ].apply( instance, args ); - if ( methodValue !== instance && methodValue !== undefined ) { - returnValue = methodValue && methodValue.jquery ? - returnValue.pushStack( methodValue.get() ) : - methodValue; - return false; - } - }); - } else { - this.each(function() { - var instance = $.data( this, fullName ); - if ( instance ) { - instance.option( options || {} )._init(); - } else { - $.data( this, fullName, new object( options, this ) ); - } - }); - } - - return returnValue; - }; -}; - -$.Widget = function( /* options, element */ ) {}; -$.Widget._childConstructors = []; - -$.Widget.prototype = { - widgetName: "widget", - widgetEventPrefix: "", - defaultElement: "
", - options: { - disabled: false, - - // callbacks - create: null - }, - _createWidget: function( options, element ) { - element = $( element || this.defaultElement || this )[ 0 ]; - this.element = $( element ); - this.uuid = uuid++; - this.eventNamespace = "." + this.widgetName + this.uuid; - this.options = $.widget.extend( {}, - this.options, - this._getCreateOptions(), - options ); - - this.bindings = $(); - this.hoverable = $(); - this.focusable = $(); - - if ( element !== this ) { - $.data( element, this.widgetFullName, this ); - this._on( true, this.element, { - remove: function( event ) { - if ( event.target === element ) { - this.destroy(); - } - } - }); - this.document = $( element.style ? - // element within the document - element.ownerDocument : - // element is window or document - element.document || element ); - this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); - } - - this._create(); - this._trigger( "create", null, this._getCreateEventData() ); - this._init(); - }, - _getCreateOptions: $.noop, - _getCreateEventData: $.noop, - _create: $.noop, - _init: $.noop, - - destroy: function() { - this._destroy(); - // we can probably remove the unbind calls in 2.0 - // all event bindings should go through this._on() - this.element - .unbind( this.eventNamespace ) - // 1.9 BC for #7810 - // TODO remove dual storage - .removeData( this.widgetName ) - .removeData( this.widgetFullName ) - // support: jquery <1.6.3 - // http://bugs.jquery.com/ticket/9413 - .removeData( $.camelCase( this.widgetFullName ) ); - this.widget() - .unbind( this.eventNamespace ) - .removeAttr( "aria-disabled" ) - .removeClass( - this.widgetFullName + "-disabled " + - "ui-state-disabled" ); - - // clean up events and states - this.bindings.unbind( this.eventNamespace ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - }, - _destroy: $.noop, - - widget: function() { - return this.element; - }, - - option: function( key, value ) { - var options = key, - parts, - curOption, - i; - - if ( arguments.length === 0 ) { - // don't return a reference to the internal hash - return $.widget.extend( {}, this.options ); - } - - if ( typeof key === "string" ) { - // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } - options = {}; - parts = key.split( "." ); - key = parts.shift(); - if ( parts.length ) { - curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); - for ( i = 0; i < parts.length - 1; i++ ) { - curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; - curOption = curOption[ parts[ i ] ]; - } - key = parts.pop(); - if ( value === undefined ) { - return curOption[ key ] === undefined ? null : curOption[ key ]; - } - curOption[ key ] = value; - } else { - if ( value === undefined ) { - return this.options[ key ] === undefined ? null : this.options[ key ]; - } - options[ key ] = value; - } - } - - this._setOptions( options ); - - return this; - }, - _setOptions: function( options ) { - var key; - - for ( key in options ) { - this._setOption( key, options[ key ] ); - } - - return this; - }, - _setOption: function( key, value ) { - this.options[ key ] = value; - - if ( key === "disabled" ) { - this.widget() - .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) - .attr( "aria-disabled", value ); - this.hoverable.removeClass( "ui-state-hover" ); - this.focusable.removeClass( "ui-state-focus" ); - } - - return this; - }, - - enable: function() { - return this._setOption( "disabled", false ); - }, - disable: function() { - return this._setOption( "disabled", true ); - }, - - _on: function( suppressDisabledCheck, element, handlers ) { - var delegateElement, - instance = this; - - // no suppressDisabledCheck flag, shuffle arguments - if ( typeof suppressDisabledCheck !== "boolean" ) { - handlers = element; - element = suppressDisabledCheck; - suppressDisabledCheck = false; - } - - // no element argument, shuffle and use this.element - if ( !handlers ) { - handlers = element; - element = this.element; - delegateElement = this.widget(); - } else { - // accept selectors, DOM elements - element = delegateElement = $( element ); - this.bindings = this.bindings.add( element ); - } - - $.each( handlers, function( event, handler ) { - function handlerProxy() { - // allow widgets to customize the disabled handling - // - disabled as an array instead of boolean - // - disabled class as method for disabling individual parts - if ( !suppressDisabledCheck && - ( instance.options.disabled === true || - $( this ).hasClass( "ui-state-disabled" ) ) ) { - return; - } - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - - // copy the guid so direct unbinding works - if ( typeof handler !== "string" ) { - handlerProxy.guid = handler.guid = - handler.guid || handlerProxy.guid || $.guid++; - } - - var match = event.match( /^(\w+)\s*(.*)$/ ), - eventName = match[1] + instance.eventNamespace, - selector = match[2]; - if ( selector ) { - delegateElement.delegate( selector, eventName, handlerProxy ); - } else { - element.bind( eventName, handlerProxy ); - } - }); - }, - - _off: function( element, eventName ) { - eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; - element.unbind( eventName ).undelegate( eventName ); - }, - - _delay: function( handler, delay ) { - function handlerProxy() { - return ( typeof handler === "string" ? instance[ handler ] : handler ) - .apply( instance, arguments ); - } - var instance = this; - return setTimeout( handlerProxy, delay || 0 ); - }, - - _hoverable: function( element ) { - this.hoverable = this.hoverable.add( element ); - this._on( element, { - mouseenter: function( event ) { - $( event.currentTarget ).addClass( "ui-state-hover" ); - }, - mouseleave: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-hover" ); - } - }); - }, - - _focusable: function( element ) { - this.focusable = this.focusable.add( element ); - this._on( element, { - focusin: function( event ) { - $( event.currentTarget ).addClass( "ui-state-focus" ); - }, - focusout: function( event ) { - $( event.currentTarget ).removeClass( "ui-state-focus" ); - } - }); - }, - - _trigger: function( type, event, data ) { - var prop, orig, - callback = this.options[ type ]; - - data = data || {}; - event = $.Event( event ); - event.type = ( type === this.widgetEventPrefix ? - type : - this.widgetEventPrefix + type ).toLowerCase(); - // the original event may come from any element - // so we need to reset the target on the new event - event.target = this.element[ 0 ]; - - // copy original event properties over to the new event - orig = event.originalEvent; - if ( orig ) { - for ( prop in orig ) { - if ( !( prop in event ) ) { - event[ prop ] = orig[ prop ]; - } - } - } - - this.element.trigger( event, data ); - return !( $.isFunction( callback ) && - callback.apply( this.element[0], [ event ].concat( data ) ) === false || - event.isDefaultPrevented() ); - } -}; - -$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { - $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { - if ( typeof options === "string" ) { - options = { effect: options }; - } - var hasOptions, - effectName = !options ? - method : - options === true || typeof options === "number" ? - defaultEffect : - options.effect || defaultEffect; - options = options || {}; - if ( typeof options === "number" ) { - options = { duration: options }; - } - hasOptions = !$.isEmptyObject( options ); - options.complete = callback; - if ( options.delay ) { - element.delay( options.delay ); - } - if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { - element[ method ]( options ); - } else if ( effectName !== method && element[ effectName ] ) { - element[ effectName ]( options.duration, options.easing, callback ); - } else { - element.queue(function( next ) { - $( this )[ method ](); - if ( callback ) { - callback.call( element[ 0 ] ); - } - next(); - }); - } - }; -}); - -})( jQuery ); - -(function( $, undefined ) { - -var mouseHandled = false; -$( document ).mouseup( function() { - mouseHandled = false; -}); - -$.widget("ui.mouse", { - version: "1.10.3", - options: { - cancel: "input,textarea,button,select,option", - distance: 1, - delay: 0 - }, - _mouseInit: function() { - var that = this; - - this.element - .bind("mousedown."+this.widgetName, function(event) { - return that._mouseDown(event); - }) - .bind("click."+this.widgetName, function(event) { - if (true === $.data(event.target, that.widgetName + ".preventClickEvent")) { - $.removeData(event.target, that.widgetName + ".preventClickEvent"); - event.stopImmediatePropagation(); - return false; - } - }); - - this.started = false; - }, - - // TODO: make sure destroying one instance of mouse doesn't mess with - // other instances of mouse - _mouseDestroy: function() { - this.element.unbind("."+this.widgetName); - if ( this._mouseMoveDelegate ) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - } - }, - - _mouseDown: function(event) { - // don't let more than one widget handle mouseStart - if( mouseHandled ) { return; } - - // we may have missed mouseup (out of window) - (this._mouseStarted && this._mouseUp(event)); - - this._mouseDownEvent = event; - - var that = this, - btnIsLeft = (event.which === 1), - // event.target.nodeName works around a bug in IE 8 with - // disabled inputs (#7620) - elIsCancel = (typeof this.options.cancel === "string" && event.target.nodeName ? $(event.target).closest(this.options.cancel).length : false); - if (!btnIsLeft || elIsCancel || !this._mouseCapture(event)) { - return true; - } - - this.mouseDelayMet = !this.options.delay; - if (!this.mouseDelayMet) { - this._mouseDelayTimer = setTimeout(function() { - that.mouseDelayMet = true; - }, this.options.delay); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = (this._mouseStart(event) !== false); - if (!this._mouseStarted) { - event.preventDefault(); - return true; - } - } - - // Click event may never have fired (Gecko & Opera) - if (true === $.data(event.target, this.widgetName + ".preventClickEvent")) { - $.removeData(event.target, this.widgetName + ".preventClickEvent"); - } - - // these delegates are required to keep context - this._mouseMoveDelegate = function(event) { - return that._mouseMove(event); - }; - this._mouseUpDelegate = function(event) { - return that._mouseUp(event); - }; - $(document) - .bind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .bind("mouseup."+this.widgetName, this._mouseUpDelegate); - - event.preventDefault(); - - mouseHandled = true; - return true; - }, - - _mouseMove: function(event) { - // IE mouseup check - mouseup happened when mouse was out of window - if ($.ui.ie && ( !document.documentMode || document.documentMode < 9 ) && !event.button) { - return this._mouseUp(event); - } - - if (this._mouseStarted) { - this._mouseDrag(event); - return event.preventDefault(); - } - - if (this._mouseDistanceMet(event) && this._mouseDelayMet(event)) { - this._mouseStarted = - (this._mouseStart(this._mouseDownEvent, event) !== false); - (this._mouseStarted ? this._mouseDrag(event) : this._mouseUp(event)); - } - - return !this._mouseStarted; - }, - - _mouseUp: function(event) { - $(document) - .unbind("mousemove."+this.widgetName, this._mouseMoveDelegate) - .unbind("mouseup."+this.widgetName, this._mouseUpDelegate); - - if (this._mouseStarted) { - this._mouseStarted = false; - - if (event.target === this._mouseDownEvent.target) { - $.data(event.target, this.widgetName + ".preventClickEvent", true); - } - - this._mouseStop(event); - } - - return false; - }, - - _mouseDistanceMet: function(event) { - return (Math.max( - Math.abs(this._mouseDownEvent.pageX - event.pageX), - Math.abs(this._mouseDownEvent.pageY - event.pageY) - ) >= this.options.distance - ); - }, - - _mouseDelayMet: function(/* event */) { - return this.mouseDelayMet; - }, - - // These are placeholder methods, to be overriden by extending plugin - _mouseStart: function(/* event */) {}, - _mouseDrag: function(/* event */) {}, - _mouseStop: function(/* event */) {}, - _mouseCapture: function(/* event */) { return true; } -}); - -})(jQuery); - -(function( $, undefined ) { - -$.widget("ui.draggable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "drag", - options: { - addClasses: true, - appendTo: "parent", - axis: false, - connectToSortable: false, - containment: false, - cursor: "auto", - cursorAt: false, - grid: false, - handle: false, - helper: "original", - iframeFix: false, - opacity: false, - refreshPositions: false, - revert: false, - revertDuration: 500, - scope: "default", - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - snap: false, - snapMode: "both", - snapTolerance: 20, - stack: false, - zIndex: false, - - // callbacks - drag: null, - start: null, - stop: null - }, - _create: function() { - - if (this.options.helper === "original" && !(/^(?:r|a|f)/).test(this.element.css("position"))) { - this.element[0].style.position = "relative"; - } - if (this.options.addClasses){ - this.element.addClass("ui-draggable"); - } - if (this.options.disabled){ - this.element.addClass("ui-draggable-disabled"); - } - - this._mouseInit(); - - }, - - _destroy: function() { - this.element.removeClass( "ui-draggable ui-draggable-dragging ui-draggable-disabled" ); - this._mouseDestroy(); - }, - - _mouseCapture: function(event) { - - var o = this.options; - - // among others, prevent a drag on a resizable-handle - if (this.helper || o.disabled || $(event.target).closest(".ui-resizable-handle").length > 0) { - return false; - } - - //Quit if we're not on a valid handle - this.handle = this._getHandle(event); - if (!this.handle) { - return false; - } - - $(o.iframeFix === true ? "iframe" : o.iframeFix).each(function() { - $("
") - .css({ - width: this.offsetWidth+"px", height: this.offsetHeight+"px", - position: "absolute", opacity: "0.001", zIndex: 1000 - }) - .css($(this).offset()) - .appendTo("body"); - }); - - return true; - - }, - - _mouseStart: function(event) { - - var o = this.options; - - //Create and append the visible helper - this.helper = this._createHelper(event); - - this.helper.addClass("ui-draggable-dragging"); - - //Cache the helper size - this._cacheHelperProportions(); - - //If ddmanager is used for droppables, set the global draggable - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Store the helper's css position - this.cssPosition = this.helper.css( "position" ); - this.scrollParent = this.helper.scrollParent(); - this.offsetParent = this.helper.offsetParent(); - this.offsetParentCssPosition = this.offsetParent.css( "position" ); - - //The element's absolute position on the page minus margins - this.offset = this.positionAbs = this.element.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - //Reset scroll cache - this.offset.scroll = false; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - //Generate the original position - this.originalPosition = this.position = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Set a containment if given in the options - this._setContainment(); - - //Trigger event + callbacks - if(this._trigger("start", event) === false) { - this._clear(); - return false; - } - - //Recache the helper size - this._cacheHelperProportions(); - - //Prepare the droppable offsets - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - - this._mouseDrag(event, true); //Execute the drag once - this causes the helper not to be visible before getting its correct position - - //If the ddmanager is used for droppables, inform the manager that dragging has started (see #5003) - if ( $.ui.ddmanager ) { - $.ui.ddmanager.dragStart(this, event); - } - - return true; - }, - - _mouseDrag: function(event, noPropagation) { - // reset any necessary cached properties (see #5009) - if ( this.offsetParentCssPosition === "fixed" ) { - this.offset.parent = this._getParentOffset(); - } - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - //Call plugins and callbacks and use the resulting position if something is returned - if (!noPropagation) { - var ui = this._uiHash(); - if(this._trigger("drag", event, ui) === false) { - this._mouseUp({}); - return false; - } - this.position = ui.position; - } - - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - return false; - }, - - _mouseStop: function(event) { - - //If we are using droppables, inform the manager about the drop - var that = this, - dropped = false; - if ($.ui.ddmanager && !this.options.dropBehaviour) { - dropped = $.ui.ddmanager.drop(this, event); - } - - //if a drop comes from outside (a sortable) - if(this.dropped) { - dropped = this.dropped; - this.dropped = false; - } - - //if the original element is no longer in the DOM don't bother to continue (see #8269) - if ( this.options.helper === "original" && !$.contains( this.element[ 0 ].ownerDocument, this.element[ 0 ] ) ) { - return false; - } - - if((this.options.revert === "invalid" && !dropped) || (this.options.revert === "valid" && dropped) || this.options.revert === true || ($.isFunction(this.options.revert) && this.options.revert.call(this.element, dropped))) { - $(this.helper).animate(this.originalPosition, parseInt(this.options.revertDuration, 10), function() { - if(that._trigger("stop", event) !== false) { - that._clear(); - } - }); - } else { - if(this._trigger("stop", event) !== false) { - this._clear(); - } - } - - return false; - }, - - _mouseUp: function(event) { - //Remove frame helpers - $("div.ui-draggable-iframeFix").each(function() { - this.parentNode.removeChild(this); - }); - - //If the ddmanager is used for droppables, inform the manager that dragging has stopped (see #5003) - if( $.ui.ddmanager ) { - $.ui.ddmanager.dragStop(this, event); - } - - return $.ui.mouse.prototype._mouseUp.call(this, event); - }, - - cancel: function() { - - if(this.helper.is(".ui-draggable-dragging")) { - this._mouseUp({}); - } else { - this._clear(); - } - - return this; - - }, - - _getHandle: function(event) { - return this.options.handle ? - !!$( event.target ).closest( this.element.find( this.options.handle ) ).length : - true; - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event])) : (o.helper === "clone" ? this.element.clone().removeAttr("id") : this.element); - - if(!helper.parents("body").length) { - helper.appendTo((o.appendTo === "parent" ? this.element[0].parentNode : o.appendTo)); - } - - if(helper[0] !== this.element[0] && !(/(fixed|absolute)/).test(helper.css("position"))) { - helper.css("position", "absolute"); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - //Get the offsetParent and cache its position - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - //This needs to be actually done for all browsers, since pageX/pageY includes this information - //Ugly IE fix - if((this.offsetParent[0] === document.body) || - (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.element.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.element.css("marginLeft"),10) || 0), - top: (parseInt(this.element.css("marginTop"),10) || 0), - right: (parseInt(this.element.css("marginRight"),10) || 0), - bottom: (parseInt(this.element.css("marginBottom"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var over, c, ce, - o = this.options; - - if ( !o.containment ) { - this.containment = null; - return; - } - - if ( o.containment === "window" ) { - this.containment = [ - $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left, - $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top, - $( window ).scrollLeft() + $( window ).width() - this.helperProportions.width - this.margins.left, - $( window ).scrollTop() + ( $( window ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top - ]; - return; - } - - if ( o.containment === "document") { - this.containment = [ - 0, - 0, - $( document ).width() - this.helperProportions.width - this.margins.left, - ( $( document ).height() || document.body.parentNode.scrollHeight ) - this.helperProportions.height - this.margins.top - ]; - return; - } - - if ( o.containment.constructor === Array ) { - this.containment = o.containment; - return; - } - - if ( o.containment === "parent" ) { - o.containment = this.helper[ 0 ].parentNode; - } - - c = $( o.containment ); - ce = c[ 0 ]; - - if( !ce ) { - return; - } - - over = c.css( "overflow" ) !== "hidden"; - - this.containment = [ - ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ), - ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) + ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ) , - ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) - ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) - this.helperProportions.width - this.margins.left - this.margins.right, - ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) - ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) - ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) - this.helperProportions.height - this.margins.top - this.margins.bottom - ]; - this.relative_container = c; - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent; - - //Cache the scroll - if (!this.offset.scroll) { - this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()}; - } - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) * mod ) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) * mod ) - ) - }; - - }, - - _generatePosition: function(event) { - - var containment, co, top, left, - o = this.options, - scroll = this.cssPosition === "absolute" && !( this.scrollParent[ 0 ] !== document && $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ? this.offsetParent : this.scrollParent, - pageX = event.pageX, - pageY = event.pageY; - - //Cache the scroll - if (!this.offset.scroll) { - this.offset.scroll = {top : scroll.scrollTop(), left : scroll.scrollLeft()}; - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - // If we are not dragging yet, we won't check for options - if ( this.originalPosition ) { - if ( this.containment ) { - if ( this.relative_container ){ - co = this.relative_container.offset(); - containment = [ - this.containment[ 0 ] + co.left, - this.containment[ 1 ] + co.top, - this.containment[ 2 ] + co.left, - this.containment[ 3 ] + co.top - ]; - } - else { - containment = this.containment; - } - - if(event.pageX - this.offset.click.left < containment[0]) { - pageX = containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < containment[1]) { - pageY = containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > containment[2]) { - pageX = containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > containment[3]) { - pageY = containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - //Check for grid elements set to 0 to prevent divide by 0 error causing invalid argument errors in IE (see ticket #6950) - top = o.grid[1] ? this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1] : this.originalPageY; - pageY = containment ? ((top - this.offset.click.top >= containment[1] || top - this.offset.click.top > containment[3]) ? top : ((top - this.offset.click.top >= containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = o.grid[0] ? this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0] : this.originalPageX; - pageX = containment ? ((left - this.offset.click.left >= containment[0] || left - this.offset.click.left > containment[2]) ? left : ((left - this.offset.click.left >= containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : this.offset.scroll.top ) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : this.offset.scroll.left ) - ) - }; - - }, - - _clear: function() { - this.helper.removeClass("ui-draggable-dragging"); - if(this.helper[0] !== this.element[0] && !this.cancelHelperRemoval) { - this.helper.remove(); - } - this.helper = null; - this.cancelHelperRemoval = false; - }, - - // From now on bulk stuff - mainly helpers - - _trigger: function(type, event, ui) { - ui = ui || this._uiHash(); - $.ui.plugin.call(this, type, [event, ui]); - //The absolute position has to be recalculated after plugins - if(type === "drag") { - this.positionAbs = this._convertPositionTo("absolute"); - } - return $.Widget.prototype._trigger.call(this, type, event, ui); - }, - - plugins: {}, - - _uiHash: function() { - return { - helper: this.helper, - position: this.position, - originalPosition: this.originalPosition, - offset: this.positionAbs - }; - } - -}); - -$.ui.plugin.add("draggable", "connectToSortable", { - start: function(event, ui) { - - var inst = $(this).data("ui-draggable"), o = inst.options, - uiSortable = $.extend({}, ui, { item: inst.element }); - inst.sortables = []; - $(o.connectToSortable).each(function() { - var sortable = $.data(this, "ui-sortable"); - if (sortable && !sortable.options.disabled) { - inst.sortables.push({ - instance: sortable, - shouldRevert: sortable.options.revert - }); - sortable.refreshPositions(); // Call the sortable's refreshPositions at drag start to refresh the containerCache since the sortable container cache is used in drag and needs to be up to date (this will ensure it's initialised as well as being kept in step with any changes that might have happened on the page). - sortable._trigger("activate", event, uiSortable); - } - }); - - }, - stop: function(event, ui) { - - //If we are still over the sortable, we fake the stop event of the sortable, but also remove helper - var inst = $(this).data("ui-draggable"), - uiSortable = $.extend({}, ui, { item: inst.element }); - - $.each(inst.sortables, function() { - if(this.instance.isOver) { - - this.instance.isOver = 0; - - inst.cancelHelperRemoval = true; //Don't remove the helper in the draggable instance - this.instance.cancelHelperRemoval = false; //Remove it in the sortable instance (so sortable plugins like revert still work) - - //The sortable revert is supported, and we have to set a temporary dropped variable on the draggable to support revert: "valid/invalid" - if(this.shouldRevert) { - this.instance.options.revert = this.shouldRevert; - } - - //Trigger the stop of the sortable - this.instance._mouseStop(event); - - this.instance.options.helper = this.instance.options._helper; - - //If the helper has been the original item, restore properties in the sortable - if(inst.options.helper === "original") { - this.instance.currentItem.css({ top: "auto", left: "auto" }); - } - - } else { - this.instance.cancelHelperRemoval = false; //Remove the helper in the sortable instance - this.instance._trigger("deactivate", event, uiSortable); - } - - }); - - }, - drag: function(event, ui) { - - var inst = $(this).data("ui-draggable"), that = this; - - $.each(inst.sortables, function() { - - var innermostIntersecting = false, - thisSortable = this; - - //Copy over some variables to allow calling the sortable's native _intersectsWith - this.instance.positionAbs = inst.positionAbs; - this.instance.helperProportions = inst.helperProportions; - this.instance.offset.click = inst.offset.click; - - if(this.instance._intersectsWith(this.instance.containerCache)) { - innermostIntersecting = true; - $.each(inst.sortables, function () { - this.instance.positionAbs = inst.positionAbs; - this.instance.helperProportions = inst.helperProportions; - this.instance.offset.click = inst.offset.click; - if (this !== thisSortable && - this.instance._intersectsWith(this.instance.containerCache) && - $.contains(thisSortable.instance.element[0], this.instance.element[0]) - ) { - innermostIntersecting = false; - } - return innermostIntersecting; - }); - } - - - if(innermostIntersecting) { - //If it intersects, we use a little isOver variable and set it once, so our move-in stuff gets fired only once - if(!this.instance.isOver) { - - this.instance.isOver = 1; - //Now we fake the start of dragging for the sortable instance, - //by cloning the list group item, appending it to the sortable and using it as inst.currentItem - //We can then fire the start event of the sortable with our passed browser event, and our own helper (so it doesn't create a new one) - this.instance.currentItem = $(that).clone().removeAttr("id").appendTo(this.instance.element).data("ui-sortable-item", true); - this.instance.options._helper = this.instance.options.helper; //Store helper option to later restore it - this.instance.options.helper = function() { return ui.helper[0]; }; - - event.target = this.instance.currentItem[0]; - this.instance._mouseCapture(event, true); - this.instance._mouseStart(event, true, true); - - //Because the browser event is way off the new appended portlet, we modify a couple of variables to reflect the changes - this.instance.offset.click.top = inst.offset.click.top; - this.instance.offset.click.left = inst.offset.click.left; - this.instance.offset.parent.left -= inst.offset.parent.left - this.instance.offset.parent.left; - this.instance.offset.parent.top -= inst.offset.parent.top - this.instance.offset.parent.top; - - inst._trigger("toSortable", event); - inst.dropped = this.instance.element; //draggable revert needs that - //hack so receive/update callbacks work (mostly) - inst.currentItem = inst.element; - this.instance.fromOutside = inst; - - } - - //Provided we did all the previous steps, we can fire the drag event of the sortable on every draggable drag, when it intersects with the sortable - if(this.instance.currentItem) { - this.instance._mouseDrag(event); - } - - } else { - - //If it doesn't intersect with the sortable, and it intersected before, - //we fake the drag stop of the sortable, but make sure it doesn't remove the helper by using cancelHelperRemoval - if(this.instance.isOver) { - - this.instance.isOver = 0; - this.instance.cancelHelperRemoval = true; - - //Prevent reverting on this forced stop - this.instance.options.revert = false; - - // The out event needs to be triggered independently - this.instance._trigger("out", event, this.instance._uiHash(this.instance)); - - this.instance._mouseStop(event, true); - this.instance.options.helper = this.instance.options._helper; - - //Now we remove our currentItem, the list group clone again, and the placeholder, and animate the helper back to it's original size - this.instance.currentItem.remove(); - if(this.instance.placeholder) { - this.instance.placeholder.remove(); - } - - inst._trigger("fromSortable", event); - inst.dropped = false; //draggable revert needs that - } - - } - - }); - - } -}); - -$.ui.plugin.add("draggable", "cursor", { - start: function() { - var t = $("body"), o = $(this).data("ui-draggable").options; - if (t.css("cursor")) { - o._cursor = t.css("cursor"); - } - t.css("cursor", o.cursor); - }, - stop: function() { - var o = $(this).data("ui-draggable").options; - if (o._cursor) { - $("body").css("cursor", o._cursor); - } - } -}); - -$.ui.plugin.add("draggable", "opacity", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("ui-draggable").options; - if(t.css("opacity")) { - o._opacity = t.css("opacity"); - } - t.css("opacity", o.opacity); - }, - stop: function(event, ui) { - var o = $(this).data("ui-draggable").options; - if(o._opacity) { - $(ui.helper).css("opacity", o._opacity); - } - } -}); - -$.ui.plugin.add("draggable", "scroll", { - start: function() { - var i = $(this).data("ui-draggable"); - if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { - i.overflowOffset = i.scrollParent.offset(); - } - }, - drag: function( event ) { - - var i = $(this).data("ui-draggable"), o = i.options, scrolled = false; - - if(i.scrollParent[0] !== document && i.scrollParent[0].tagName !== "HTML") { - - if(!o.axis || o.axis !== "x") { - if((i.overflowOffset.top + i.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - i.overflowOffset.top < o.scrollSensitivity) { - i.scrollParent[0].scrollTop = scrolled = i.scrollParent[0].scrollTop - o.scrollSpeed; - } - } - - if(!o.axis || o.axis !== "y") { - if((i.overflowOffset.left + i.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - i.overflowOffset.left < o.scrollSensitivity) { - i.scrollParent[0].scrollLeft = scrolled = i.scrollParent[0].scrollLeft - o.scrollSpeed; - } - } - - } else { - - if(!o.axis || o.axis !== "x") { - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - } - - if(!o.axis || o.axis !== "y") { - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(i, event); - } - - } -}); - -$.ui.plugin.add("draggable", "snap", { - start: function() { - - var i = $(this).data("ui-draggable"), - o = i.options; - - i.snapElements = []; - - $(o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap).each(function() { - var $t = $(this), - $o = $t.offset(); - if(this !== i.element[0]) { - i.snapElements.push({ - item: this, - width: $t.outerWidth(), height: $t.outerHeight(), - top: $o.top, left: $o.left - }); - } - }); - - }, - drag: function(event, ui) { - - var ts, bs, ls, rs, l, r, t, b, i, first, - inst = $(this).data("ui-draggable"), - o = inst.options, - d = o.snapTolerance, - x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width, - y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height; - - for (i = inst.snapElements.length - 1; i >= 0; i--){ - - l = inst.snapElements[i].left; - r = l + inst.snapElements[i].width; - t = inst.snapElements[i].top; - b = t + inst.snapElements[i].height; - - if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d || !$.contains( inst.snapElements[ i ].item.ownerDocument, inst.snapElements[ i ].item ) ) { - if(inst.snapElements[i].snapping) { - (inst.options.snap.release && inst.options.snap.release.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - } - inst.snapElements[i].snapping = false; - continue; - } - - if(o.snapMode !== "inner") { - ts = Math.abs(t - y2) <= d; - bs = Math.abs(b - y1) <= d; - ls = Math.abs(l - x2) <= d; - rs = Math.abs(r - x1) <= d; - if(ts) { - ui.position.top = inst._convertPositionTo("relative", { top: t - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - } - if(bs) { - ui.position.top = inst._convertPositionTo("relative", { top: b, left: 0 }).top - inst.margins.top; - } - if(ls) { - ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l - inst.helperProportions.width }).left - inst.margins.left; - } - if(rs) { - ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r }).left - inst.margins.left; - } - } - - first = (ts || bs || ls || rs); - - if(o.snapMode !== "outer") { - ts = Math.abs(t - y1) <= d; - bs = Math.abs(b - y2) <= d; - ls = Math.abs(l - x1) <= d; - rs = Math.abs(r - x2) <= d; - if(ts) { - ui.position.top = inst._convertPositionTo("relative", { top: t, left: 0 }).top - inst.margins.top; - } - if(bs) { - ui.position.top = inst._convertPositionTo("relative", { top: b - inst.helperProportions.height, left: 0 }).top - inst.margins.top; - } - if(ls) { - ui.position.left = inst._convertPositionTo("relative", { top: 0, left: l }).left - inst.margins.left; - } - if(rs) { - ui.position.left = inst._convertPositionTo("relative", { top: 0, left: r - inst.helperProportions.width }).left - inst.margins.left; - } - } - - if(!inst.snapElements[i].snapping && (ts || bs || ls || rs || first)) { - (inst.options.snap.snap && inst.options.snap.snap.call(inst.element, event, $.extend(inst._uiHash(), { snapItem: inst.snapElements[i].item }))); - } - inst.snapElements[i].snapping = (ts || bs || ls || rs || first); - - } - - } -}); - -$.ui.plugin.add("draggable", "stack", { - start: function() { - var min, - o = this.data("ui-draggable").options, - group = $.makeArray($(o.stack)).sort(function(a,b) { - return (parseInt($(a).css("zIndex"),10) || 0) - (parseInt($(b).css("zIndex"),10) || 0); - }); - - if (!group.length) { return; } - - min = parseInt($(group[0]).css("zIndex"), 10) || 0; - $(group).each(function(i) { - $(this).css("zIndex", min + i); - }); - this.css("zIndex", (min + group.length)); - } -}); - -$.ui.plugin.add("draggable", "zIndex", { - start: function(event, ui) { - var t = $(ui.helper), o = $(this).data("ui-draggable").options; - if(t.css("zIndex")) { - o._zIndex = t.css("zIndex"); - } - t.css("zIndex", o.zIndex); - }, - stop: function(event, ui) { - var o = $(this).data("ui-draggable").options; - if(o._zIndex) { - $(ui.helper).css("zIndex", o._zIndex); - } - } -}); - -})(jQuery); - -(function( $, undefined ) { - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -$.widget("ui.droppable", { - version: "1.10.3", - widgetEventPrefix: "drop", - options: { - accept: "*", - activeClass: false, - addClasses: true, - greedy: false, - hoverClass: false, - scope: "default", - tolerance: "intersect", - - // callbacks - activate: null, - deactivate: null, - drop: null, - out: null, - over: null - }, - _create: function() { - - var o = this.options, - accept = o.accept; - - this.isover = false; - this.isout = true; - - this.accept = $.isFunction(accept) ? accept : function(d) { - return d.is(accept); - }; - - //Store the droppable's proportions - this.proportions = { width: this.element[0].offsetWidth, height: this.element[0].offsetHeight }; - - // Add the reference and positions to the manager - $.ui.ddmanager.droppables[o.scope] = $.ui.ddmanager.droppables[o.scope] || []; - $.ui.ddmanager.droppables[o.scope].push(this); - - (o.addClasses && this.element.addClass("ui-droppable")); - - }, - - _destroy: function() { - var i = 0, - drop = $.ui.ddmanager.droppables[this.options.scope]; - - for ( ; i < drop.length; i++ ) { - if ( drop[i] === this ) { - drop.splice(i, 1); - } - } - - this.element.removeClass("ui-droppable ui-droppable-disabled"); - }, - - _setOption: function(key, value) { - - if(key === "accept") { - this.accept = $.isFunction(value) ? value : function(d) { - return d.is(value); - }; - } - $.Widget.prototype._setOption.apply(this, arguments); - }, - - _activate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) { - this.element.addClass(this.options.activeClass); - } - if(draggable){ - this._trigger("activate", event, this.ui(draggable)); - } - }, - - _deactivate: function(event) { - var draggable = $.ui.ddmanager.current; - if(this.options.activeClass) { - this.element.removeClass(this.options.activeClass); - } - if(draggable){ - this._trigger("deactivate", event, this.ui(draggable)); - } - }, - - _over: function(event) { - - var draggable = $.ui.ddmanager.current; - - // Bail if draggable and droppable are same element - if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { - return; - } - - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) { - this.element.addClass(this.options.hoverClass); - } - this._trigger("over", event, this.ui(draggable)); - } - - }, - - _out: function(event) { - - var draggable = $.ui.ddmanager.current; - - // Bail if draggable and droppable are same element - if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { - return; - } - - if (this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.hoverClass) { - this.element.removeClass(this.options.hoverClass); - } - this._trigger("out", event, this.ui(draggable)); - } - - }, - - _drop: function(event,custom) { - - var draggable = custom || $.ui.ddmanager.current, - childrenIntersection = false; - - // Bail if draggable and droppable are same element - if (!draggable || (draggable.currentItem || draggable.element)[0] === this.element[0]) { - return false; - } - - this.element.find(":data(ui-droppable)").not(".ui-draggable-dragging").each(function() { - var inst = $.data(this, "ui-droppable"); - if( - inst.options.greedy && - !inst.options.disabled && - inst.options.scope === draggable.options.scope && - inst.accept.call(inst.element[0], (draggable.currentItem || draggable.element)) && - $.ui.intersect(draggable, $.extend(inst, { offset: inst.element.offset() }), inst.options.tolerance) - ) { childrenIntersection = true; return false; } - }); - if(childrenIntersection) { - return false; - } - - if(this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - if(this.options.activeClass) { - this.element.removeClass(this.options.activeClass); - } - if(this.options.hoverClass) { - this.element.removeClass(this.options.hoverClass); - } - this._trigger("drop", event, this.ui(draggable)); - return this.element; - } - - return false; - - }, - - ui: function(c) { - return { - draggable: (c.currentItem || c.element), - helper: c.helper, - position: c.position, - offset: c.positionAbs - }; - } - -}); - -$.ui.intersect = function(draggable, droppable, toleranceMode) { - - if (!droppable.offset) { - return false; - } - - var draggableLeft, draggableTop, - x1 = (draggable.positionAbs || draggable.position.absolute).left, x2 = x1 + draggable.helperProportions.width, - y1 = (draggable.positionAbs || draggable.position.absolute).top, y2 = y1 + draggable.helperProportions.height, - l = droppable.offset.left, r = l + droppable.proportions.width, - t = droppable.offset.top, b = t + droppable.proportions.height; - - switch (toleranceMode) { - case "fit": - return (l <= x1 && x2 <= r && t <= y1 && y2 <= b); - case "intersect": - return (l < x1 + (draggable.helperProportions.width / 2) && // Right Half - x2 - (draggable.helperProportions.width / 2) < r && // Left Half - t < y1 + (draggable.helperProportions.height / 2) && // Bottom Half - y2 - (draggable.helperProportions.height / 2) < b ); // Top Half - case "pointer": - draggableLeft = ((draggable.positionAbs || draggable.position.absolute).left + (draggable.clickOffset || draggable.offset.click).left); - draggableTop = ((draggable.positionAbs || draggable.position.absolute).top + (draggable.clickOffset || draggable.offset.click).top); - return isOverAxis( draggableTop, t, droppable.proportions.height ) && isOverAxis( draggableLeft, l, droppable.proportions.width ); - case "touch": - return ( - (y1 >= t && y1 <= b) || // Top edge touching - (y2 >= t && y2 <= b) || // Bottom edge touching - (y1 < t && y2 > b) // Surrounded vertically - ) && ( - (x1 >= l && x1 <= r) || // Left edge touching - (x2 >= l && x2 <= r) || // Right edge touching - (x1 < l && x2 > r) // Surrounded horizontally - ); - default: - return false; - } - -}; - -/* - This manager tracks offsets of draggables and droppables -*/ -$.ui.ddmanager = { - current: null, - droppables: { "default": [] }, - prepareOffsets: function(t, event) { - - var i, j, - m = $.ui.ddmanager.droppables[t.options.scope] || [], - type = event ? event.type : null, // workaround for #2317 - list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(); - - droppablesLoop: for (i = 0; i < m.length; i++) { - - //No disabled and non-accepted - if(m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0],(t.currentItem || t.element)))) { - continue; - } - - // Filter out elements in the current dragged item - for (j=0; j < list.length; j++) { - if(list[j] === m[i].element[0]) { - m[i].proportions.height = 0; - continue droppablesLoop; - } - } - - m[i].visible = m[i].element.css("display") !== "none"; - if(!m[i].visible) { - continue; - } - - //Activate the droppable if used directly from draggables - if(type === "mousedown") { - m[i]._activate.call(m[i], event); - } - - m[i].offset = m[i].element.offset(); - m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight }; - - } - - }, - drop: function(draggable, event) { - - var dropped = false; - // Create a copy of the droppables in case the list changes during the drop (#9116) - $.each(($.ui.ddmanager.droppables[draggable.options.scope] || []).slice(), function() { - - if(!this.options) { - return; - } - if (!this.options.disabled && this.visible && $.ui.intersect(draggable, this, this.options.tolerance)) { - dropped = this._drop.call(this, event) || dropped; - } - - if (!this.options.disabled && this.visible && this.accept.call(this.element[0],(draggable.currentItem || draggable.element))) { - this.isout = true; - this.isover = false; - this._deactivate.call(this, event); - } - - }); - return dropped; - - }, - dragStart: function( draggable, event ) { - //Listen for scrolling so that if the dragging causes scrolling the position of the droppables can be recalculated (see #5003) - draggable.element.parentsUntil( "body" ).bind( "scroll.droppable", function() { - if( !draggable.options.refreshPositions ) { - $.ui.ddmanager.prepareOffsets( draggable, event ); - } - }); - }, - drag: function(draggable, event) { - - //If you have a highly dynamic page, you might try this option. It renders positions every time you move the mouse. - if(draggable.options.refreshPositions) { - $.ui.ddmanager.prepareOffsets(draggable, event); - } - - //Run through all droppables and check their positions based on specific tolerance options - $.each($.ui.ddmanager.droppables[draggable.options.scope] || [], function() { - - if(this.options.disabled || this.greedyChild || !this.visible) { - return; - } - - var parentInstance, scope, parent, - intersects = $.ui.intersect(draggable, this, this.options.tolerance), - c = !intersects && this.isover ? "isout" : (intersects && !this.isover ? "isover" : null); - if(!c) { - return; - } - - if (this.options.greedy) { - // find droppable parents with same scope - scope = this.options.scope; - parent = this.element.parents(":data(ui-droppable)").filter(function () { - return $.data(this, "ui-droppable").options.scope === scope; - }); - - if (parent.length) { - parentInstance = $.data(parent[0], "ui-droppable"); - parentInstance.greedyChild = (c === "isover"); - } - } - - // we just moved into a greedy child - if (parentInstance && c === "isover") { - parentInstance.isover = false; - parentInstance.isout = true; - parentInstance._out.call(parentInstance, event); - } - - this[c] = true; - this[c === "isout" ? "isover" : "isout"] = false; - this[c === "isover" ? "_over" : "_out"].call(this, event); - - // we just moved out of a greedy child - if (parentInstance && c === "isout") { - parentInstance.isout = false; - parentInstance.isover = true; - parentInstance._over.call(parentInstance, event); - } - }); - - }, - dragStop: function( draggable, event ) { - draggable.element.parentsUntil( "body" ).unbind( "scroll.droppable" ); - //Call prepareOffsets one final time since IE does not fire return scroll events when overflow was caused by drag (see #5003) - if( !draggable.options.refreshPositions ) { - $.ui.ddmanager.prepareOffsets( draggable, event ); - } - } -}; - -})(jQuery); - -(function( $, undefined ) { - -function num(v) { - return parseInt(v, 10) || 0; -} - -function isNumber(value) { - return !isNaN(parseInt(value, 10)); -} - -$.widget("ui.resizable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "resize", - options: { - alsoResize: false, - animate: false, - animateDuration: "slow", - animateEasing: "swing", - aspectRatio: false, - autoHide: false, - containment: false, - ghost: false, - grid: false, - handles: "e,s,se", - helper: false, - maxHeight: null, - maxWidth: null, - minHeight: 10, - minWidth: 10, - // See #7960 - zIndex: 90, - - // callbacks - resize: null, - start: null, - stop: null - }, - _create: function() { - - var n, i, handle, axis, hname, - that = this, - o = this.options; - this.element.addClass("ui-resizable"); - - $.extend(this, { - _aspectRatio: !!(o.aspectRatio), - aspectRatio: o.aspectRatio, - originalElement: this.element, - _proportionallyResizeElements: [], - _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null - }); - - //Wrap the element if it cannot hold child nodes - if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)) { - - //Create a wrapper element and set the wrapper to the new current internal element - this.element.wrap( - $("
").css({ - position: this.element.css("position"), - width: this.element.outerWidth(), - height: this.element.outerHeight(), - top: this.element.css("top"), - left: this.element.css("left") - }) - ); - - //Overwrite the original this.element - this.element = this.element.parent().data( - "ui-resizable", this.element.data("ui-resizable") - ); - - this.elementIsWrapper = true; - - //Move margins to the wrapper - this.element.css({ marginLeft: this.originalElement.css("marginLeft"), marginTop: this.originalElement.css("marginTop"), marginRight: this.originalElement.css("marginRight"), marginBottom: this.originalElement.css("marginBottom") }); - this.originalElement.css({ marginLeft: 0, marginTop: 0, marginRight: 0, marginBottom: 0}); - - //Prevent Safari textarea resize - this.originalResizeStyle = this.originalElement.css("resize"); - this.originalElement.css("resize", "none"); - - //Push the actual element to our proportionallyResize internal array - this._proportionallyResizeElements.push(this.originalElement.css({ position: "static", zoom: 1, display: "block" })); - - // avoid IE jump (hard set the margin) - this.originalElement.css({ margin: this.originalElement.css("margin") }); - - // fix handlers offset - this._proportionallyResize(); - - } - - this.handles = o.handles || (!$(".ui-resizable-handle", this.element).length ? "e,s,se" : { n: ".ui-resizable-n", e: ".ui-resizable-e", s: ".ui-resizable-s", w: ".ui-resizable-w", se: ".ui-resizable-se", sw: ".ui-resizable-sw", ne: ".ui-resizable-ne", nw: ".ui-resizable-nw" }); - if(this.handles.constructor === String) { - - if ( this.handles === "all") { - this.handles = "n,e,s,w,se,sw,ne,nw"; - } - - n = this.handles.split(","); - this.handles = {}; - - for(i = 0; i < n.length; i++) { - - handle = $.trim(n[i]); - hname = "ui-resizable-"+handle; - axis = $("
"); - - // Apply zIndex to all handles - see #7960 - axis.css({ zIndex: o.zIndex }); - - //TODO : What's going on here? - if ("se" === handle) { - axis.addClass("ui-icon ui-icon-gripsmall-diagonal-se"); - } - - //Insert into internal handles object and append to element - this.handles[handle] = ".ui-resizable-"+handle; - this.element.append(axis); - } - - } - - this._renderAxis = function(target) { - - var i, axis, padPos, padWrapper; - - target = target || this.element; - - for(i in this.handles) { - - if(this.handles[i].constructor === String) { - this.handles[i] = $(this.handles[i], this.element).show(); - } - - //Apply pad to wrapper element, needed to fix axis position (textarea, inputs, scrolls) - if (this.elementIsWrapper && this.originalElement[0].nodeName.match(/textarea|input|select|button/i)) { - - axis = $(this.handles[i], this.element); - - //Checking the correct pad and border - padWrapper = /sw|ne|nw|se|n|s/.test(i) ? axis.outerHeight() : axis.outerWidth(); - - //The padding type i have to apply... - padPos = [ "padding", - /ne|nw|n/.test(i) ? "Top" : - /se|sw|s/.test(i) ? "Bottom" : - /^e$/.test(i) ? "Right" : "Left" ].join(""); - - target.css(padPos, padWrapper); - - this._proportionallyResize(); - - } - - //TODO: What's that good for? There's not anything to be executed left - if(!$(this.handles[i]).length) { - continue; - } - } - }; - - //TODO: make renderAxis a prototype function - this._renderAxis(this.element); - - this._handles = $(".ui-resizable-handle", this.element) - .disableSelection(); - - //Matching axis name - this._handles.mouseover(function() { - if (!that.resizing) { - if (this.className) { - axis = this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i); - } - //Axis, default = se - that.axis = axis && axis[1] ? axis[1] : "se"; - } - }); - - //If we want to auto hide the elements - if (o.autoHide) { - this._handles.hide(); - $(this.element) - .addClass("ui-resizable-autohide") - .mouseenter(function() { - if (o.disabled) { - return; - } - $(this).removeClass("ui-resizable-autohide"); - that._handles.show(); - }) - .mouseleave(function(){ - if (o.disabled) { - return; - } - if (!that.resizing) { - $(this).addClass("ui-resizable-autohide"); - that._handles.hide(); - } - }); - } - - //Initialize the mouse interaction - this._mouseInit(); - - }, - - _destroy: function() { - - this._mouseDestroy(); - - var wrapper, - _destroy = function(exp) { - $(exp).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing") - .removeData("resizable").removeData("ui-resizable").unbind(".resizable").find(".ui-resizable-handle").remove(); - }; - - //TODO: Unwrap at same DOM position - if (this.elementIsWrapper) { - _destroy(this.element); - wrapper = this.element; - this.originalElement.css({ - position: wrapper.css("position"), - width: wrapper.outerWidth(), - height: wrapper.outerHeight(), - top: wrapper.css("top"), - left: wrapper.css("left") - }).insertAfter( wrapper ); - wrapper.remove(); - } - - this.originalElement.css("resize", this.originalResizeStyle); - _destroy(this.originalElement); - - return this; - }, - - _mouseCapture: function(event) { - var i, handle, - capture = false; - - for (i in this.handles) { - handle = $(this.handles[i])[0]; - if (handle === event.target || $.contains(handle, event.target)) { - capture = true; - } - } - - return !this.options.disabled && capture; - }, - - _mouseStart: function(event) { - - var curleft, curtop, cursor, - o = this.options, - iniPos = this.element.position(), - el = this.element; - - this.resizing = true; - - // bugfix for http://dev.jquery.com/ticket/1749 - if ( (/absolute/).test( el.css("position") ) ) { - el.css({ position: "absolute", top: el.css("top"), left: el.css("left") }); - } else if (el.is(".ui-draggable")) { - el.css({ position: "absolute", top: iniPos.top, left: iniPos.left }); - } - - this._renderProxy(); - - curleft = num(this.helper.css("left")); - curtop = num(this.helper.css("top")); - - if (o.containment) { - curleft += $(o.containment).scrollLeft() || 0; - curtop += $(o.containment).scrollTop() || 0; - } - - //Store needed variables - this.offset = this.helper.offset(); - this.position = { left: curleft, top: curtop }; - this.size = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalSize = this._helper ? { width: el.outerWidth(), height: el.outerHeight() } : { width: el.width(), height: el.height() }; - this.originalPosition = { left: curleft, top: curtop }; - this.sizeDiff = { width: el.outerWidth() - el.width(), height: el.outerHeight() - el.height() }; - this.originalMousePosition = { left: event.pageX, top: event.pageY }; - - //Aspect Ratio - this.aspectRatio = (typeof o.aspectRatio === "number") ? o.aspectRatio : ((this.originalSize.width / this.originalSize.height) || 1); - - cursor = $(".ui-resizable-" + this.axis).css("cursor"); - $("body").css("cursor", cursor === "auto" ? this.axis + "-resize" : cursor); - - el.addClass("ui-resizable-resizing"); - this._propagate("start", event); - return true; - }, - - _mouseDrag: function(event) { - - //Increase performance, avoid regex - var data, - el = this.helper, props = {}, - smp = this.originalMousePosition, - a = this.axis, - prevTop = this.position.top, - prevLeft = this.position.left, - prevWidth = this.size.width, - prevHeight = this.size.height, - dx = (event.pageX-smp.left)||0, - dy = (event.pageY-smp.top)||0, - trigger = this._change[a]; - - if (!trigger) { - return false; - } - - // Calculate the attrs that will be change - data = trigger.apply(this, [event, dx, dy]); - - // Put this in the mouseDrag handler since the user can start pressing shift while resizing - this._updateVirtualBoundaries(event.shiftKey); - if (this._aspectRatio || event.shiftKey) { - data = this._updateRatio(data, event); - } - - data = this._respectSize(data, event); - - this._updateCache(data); - - // plugins callbacks need to be called first - this._propagate("resize", event); - - if (this.position.top !== prevTop) { - props.top = this.position.top + "px"; - } - if (this.position.left !== prevLeft) { - props.left = this.position.left + "px"; - } - if (this.size.width !== prevWidth) { - props.width = this.size.width + "px"; - } - if (this.size.height !== prevHeight) { - props.height = this.size.height + "px"; - } - el.css(props); - - if (!this._helper && this._proportionallyResizeElements.length) { - this._proportionallyResize(); - } - - // Call the user callback if the element was resized - if ( ! $.isEmptyObject(props) ) { - this._trigger("resize", event, this.ui()); - } - - return false; - }, - - _mouseStop: function(event) { - - this.resizing = false; - var pr, ista, soffseth, soffsetw, s, left, top, - o = this.options, that = this; - - if(this._helper) { - - pr = this._proportionallyResizeElements; - ista = pr.length && (/textarea/i).test(pr[0].nodeName); - soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height; - soffsetw = ista ? 0 : that.sizeDiff.width; - - s = { width: (that.helper.width() - soffsetw), height: (that.helper.height() - soffseth) }; - left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null; - top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; - - if (!o.animate) { - this.element.css($.extend(s, { top: top, left: left })); - } - - that.helper.height(that.size.height); - that.helper.width(that.size.width); - - if (this._helper && !o.animate) { - this._proportionallyResize(); - } - } - - $("body").css("cursor", "auto"); - - this.element.removeClass("ui-resizable-resizing"); - - this._propagate("stop", event); - - if (this._helper) { - this.helper.remove(); - } - - return false; - - }, - - _updateVirtualBoundaries: function(forceAspectRatio) { - var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b, - o = this.options; - - b = { - minWidth: isNumber(o.minWidth) ? o.minWidth : 0, - maxWidth: isNumber(o.maxWidth) ? o.maxWidth : Infinity, - minHeight: isNumber(o.minHeight) ? o.minHeight : 0, - maxHeight: isNumber(o.maxHeight) ? o.maxHeight : Infinity - }; - - if(this._aspectRatio || forceAspectRatio) { - // We want to create an enclosing box whose aspect ration is the requested one - // First, compute the "projected" size for each dimension based on the aspect ratio and other dimension - pMinWidth = b.minHeight * this.aspectRatio; - pMinHeight = b.minWidth / this.aspectRatio; - pMaxWidth = b.maxHeight * this.aspectRatio; - pMaxHeight = b.maxWidth / this.aspectRatio; - - if(pMinWidth > b.minWidth) { - b.minWidth = pMinWidth; - } - if(pMinHeight > b.minHeight) { - b.minHeight = pMinHeight; - } - if(pMaxWidth < b.maxWidth) { - b.maxWidth = pMaxWidth; - } - if(pMaxHeight < b.maxHeight) { - b.maxHeight = pMaxHeight; - } - } - this._vBoundaries = b; - }, - - _updateCache: function(data) { - this.offset = this.helper.offset(); - if (isNumber(data.left)) { - this.position.left = data.left; - } - if (isNumber(data.top)) { - this.position.top = data.top; - } - if (isNumber(data.height)) { - this.size.height = data.height; - } - if (isNumber(data.width)) { - this.size.width = data.width; - } - }, - - _updateRatio: function( data ) { - - var cpos = this.position, - csize = this.size, - a = this.axis; - - if (isNumber(data.height)) { - data.width = (data.height * this.aspectRatio); - } else if (isNumber(data.width)) { - data.height = (data.width / this.aspectRatio); - } - - if (a === "sw") { - data.left = cpos.left + (csize.width - data.width); - data.top = null; - } - if (a === "nw") { - data.top = cpos.top + (csize.height - data.height); - data.left = cpos.left + (csize.width - data.width); - } - - return data; - }, - - _respectSize: function( data ) { - - var o = this._vBoundaries, - a = this.axis, - ismaxw = isNumber(data.width) && o.maxWidth && (o.maxWidth < data.width), ismaxh = isNumber(data.height) && o.maxHeight && (o.maxHeight < data.height), - isminw = isNumber(data.width) && o.minWidth && (o.minWidth > data.width), isminh = isNumber(data.height) && o.minHeight && (o.minHeight > data.height), - dw = this.originalPosition.left + this.originalSize.width, - dh = this.position.top + this.size.height, - cw = /sw|nw|w/.test(a), ch = /nw|ne|n/.test(a); - if (isminw) { - data.width = o.minWidth; - } - if (isminh) { - data.height = o.minHeight; - } - if (ismaxw) { - data.width = o.maxWidth; - } - if (ismaxh) { - data.height = o.maxHeight; - } - - if (isminw && cw) { - data.left = dw - o.minWidth; - } - if (ismaxw && cw) { - data.left = dw - o.maxWidth; - } - if (isminh && ch) { - data.top = dh - o.minHeight; - } - if (ismaxh && ch) { - data.top = dh - o.maxHeight; - } - - // fixing jump error on top/left - bug #2330 - if (!data.width && !data.height && !data.left && data.top) { - data.top = null; - } else if (!data.width && !data.height && !data.top && data.left) { - data.left = null; - } - - return data; - }, - - _proportionallyResize: function() { - - if (!this._proportionallyResizeElements.length) { - return; - } - - var i, j, borders, paddings, prel, - element = this.helper || this.element; - - for ( i=0; i < this._proportionallyResizeElements.length; i++) { - - prel = this._proportionallyResizeElements[i]; - - if (!this.borderDif) { - this.borderDif = []; - borders = [prel.css("borderTopWidth"), prel.css("borderRightWidth"), prel.css("borderBottomWidth"), prel.css("borderLeftWidth")]; - paddings = [prel.css("paddingTop"), prel.css("paddingRight"), prel.css("paddingBottom"), prel.css("paddingLeft")]; - - for ( j = 0; j < borders.length; j++ ) { - this.borderDif[ j ] = ( parseInt( borders[ j ], 10 ) || 0 ) + ( parseInt( paddings[ j ], 10 ) || 0 ); - } - } - - prel.css({ - height: (element.height() - this.borderDif[0] - this.borderDif[2]) || 0, - width: (element.width() - this.borderDif[1] - this.borderDif[3]) || 0 - }); - - } - - }, - - _renderProxy: function() { - - var el = this.element, o = this.options; - this.elementOffset = el.offset(); - - if(this._helper) { - - this.helper = this.helper || $("
"); - - this.helper.addClass(this._helper).css({ - width: this.element.outerWidth() - 1, - height: this.element.outerHeight() - 1, - position: "absolute", - left: this.elementOffset.left +"px", - top: this.elementOffset.top +"px", - zIndex: ++o.zIndex //TODO: Don't modify option - }); - - this.helper - .appendTo("body") - .disableSelection(); - - } else { - this.helper = this.element; - } - - }, - - _change: { - e: function(event, dx) { - return { width: this.originalSize.width + dx }; - }, - w: function(event, dx) { - var cs = this.originalSize, sp = this.originalPosition; - return { left: sp.left + dx, width: cs.width - dx }; - }, - n: function(event, dx, dy) { - var cs = this.originalSize, sp = this.originalPosition; - return { top: sp.top + dy, height: cs.height - dy }; - }, - s: function(event, dx, dy) { - return { height: this.originalSize.height + dy }; - }, - se: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - sw: function(event, dx, dy) { - return $.extend(this._change.s.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - }, - ne: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.e.apply(this, [event, dx, dy])); - }, - nw: function(event, dx, dy) { - return $.extend(this._change.n.apply(this, arguments), this._change.w.apply(this, [event, dx, dy])); - } - }, - - _propagate: function(n, event) { - $.ui.plugin.call(this, n, [event, this.ui()]); - (n !== "resize" && this._trigger(n, event, this.ui())); - }, - - plugins: {}, - - ui: function() { - return { - originalElement: this.originalElement, - element: this.element, - helper: this.helper, - position: this.position, - size: this.size, - originalSize: this.originalSize, - originalPosition: this.originalPosition - }; - } - -}); - -/* - * Resizable Extensions - */ - -$.ui.plugin.add("resizable", "animate", { - - stop: function( event ) { - var that = $(this).data("ui-resizable"), - o = that.options, - pr = that._proportionallyResizeElements, - ista = pr.length && (/textarea/i).test(pr[0].nodeName), - soffseth = ista && $.ui.hasScroll(pr[0], "left") /* TODO - jump height */ ? 0 : that.sizeDiff.height, - soffsetw = ista ? 0 : that.sizeDiff.width, - style = { width: (that.size.width - soffsetw), height: (that.size.height - soffseth) }, - left = (parseInt(that.element.css("left"), 10) + (that.position.left - that.originalPosition.left)) || null, - top = (parseInt(that.element.css("top"), 10) + (that.position.top - that.originalPosition.top)) || null; - - that.element.animate( - $.extend(style, top && left ? { top: top, left: left } : {}), { - duration: o.animateDuration, - easing: o.animateEasing, - step: function() { - - var data = { - width: parseInt(that.element.css("width"), 10), - height: parseInt(that.element.css("height"), 10), - top: parseInt(that.element.css("top"), 10), - left: parseInt(that.element.css("left"), 10) - }; - - if (pr && pr.length) { - $(pr[0]).css({ width: data.width, height: data.height }); - } - - // propagating resize, and updating values for each animation step - that._updateCache(data); - that._propagate("resize", event); - - } - } - ); - } - -}); - -$.ui.plugin.add("resizable", "containment", { - - start: function() { - var element, p, co, ch, cw, width, height, - that = $(this).data("ui-resizable"), - o = that.options, - el = that.element, - oc = o.containment, - ce = (oc instanceof $) ? oc.get(0) : (/parent/.test(oc)) ? el.parent().get(0) : oc; - - if (!ce) { - return; - } - - that.containerElement = $(ce); - - if (/document/.test(oc) || oc === document) { - that.containerOffset = { left: 0, top: 0 }; - that.containerPosition = { left: 0, top: 0 }; - - that.parentData = { - element: $(document), left: 0, top: 0, - width: $(document).width(), height: $(document).height() || document.body.parentNode.scrollHeight - }; - } - - // i'm a node, so compute top, left, right, bottom - else { - element = $(ce); - p = []; - $([ "Top", "Right", "Left", "Bottom" ]).each(function(i, name) { p[i] = num(element.css("padding" + name)); }); - - that.containerOffset = element.offset(); - that.containerPosition = element.position(); - that.containerSize = { height: (element.innerHeight() - p[3]), width: (element.innerWidth() - p[1]) }; - - co = that.containerOffset; - ch = that.containerSize.height; - cw = that.containerSize.width; - width = ($.ui.hasScroll(ce, "left") ? ce.scrollWidth : cw ); - height = ($.ui.hasScroll(ce) ? ce.scrollHeight : ch); - - that.parentData = { - element: ce, left: co.left, top: co.top, width: width, height: height - }; - } - }, - - resize: function( event ) { - var woset, hoset, isParent, isOffsetRelative, - that = $(this).data("ui-resizable"), - o = that.options, - co = that.containerOffset, cp = that.position, - pRatio = that._aspectRatio || event.shiftKey, - cop = { top:0, left:0 }, ce = that.containerElement; - - if (ce[0] !== document && (/static/).test(ce.css("position"))) { - cop = co; - } - - if (cp.left < (that._helper ? co.left : 0)) { - that.size.width = that.size.width + (that._helper ? (that.position.left - co.left) : (that.position.left - cop.left)); - if (pRatio) { - that.size.height = that.size.width / that.aspectRatio; - } - that.position.left = o.helper ? co.left : 0; - } - - if (cp.top < (that._helper ? co.top : 0)) { - that.size.height = that.size.height + (that._helper ? (that.position.top - co.top) : that.position.top); - if (pRatio) { - that.size.width = that.size.height * that.aspectRatio; - } - that.position.top = that._helper ? co.top : 0; - } - - that.offset.left = that.parentData.left+that.position.left; - that.offset.top = that.parentData.top+that.position.top; - - woset = Math.abs( (that._helper ? that.offset.left - cop.left : (that.offset.left - cop.left)) + that.sizeDiff.width ); - hoset = Math.abs( (that._helper ? that.offset.top - cop.top : (that.offset.top - co.top)) + that.sizeDiff.height ); - - isParent = that.containerElement.get(0) === that.element.parent().get(0); - isOffsetRelative = /relative|absolute/.test(that.containerElement.css("position")); - - if(isParent && isOffsetRelative) { - woset -= that.parentData.left; - } - - if (woset + that.size.width >= that.parentData.width) { - that.size.width = that.parentData.width - woset; - if (pRatio) { - that.size.height = that.size.width / that.aspectRatio; - } - } - - if (hoset + that.size.height >= that.parentData.height) { - that.size.height = that.parentData.height - hoset; - if (pRatio) { - that.size.width = that.size.height * that.aspectRatio; - } - } - }, - - stop: function(){ - var that = $(this).data("ui-resizable"), - o = that.options, - co = that.containerOffset, - cop = that.containerPosition, - ce = that.containerElement, - helper = $(that.helper), - ho = helper.offset(), - w = helper.outerWidth() - that.sizeDiff.width, - h = helper.outerHeight() - that.sizeDiff.height; - - if (that._helper && !o.animate && (/relative/).test(ce.css("position"))) { - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - } - - if (that._helper && !o.animate && (/static/).test(ce.css("position"))) { - $(this).css({ left: ho.left - cop.left - co.left, width: w, height: h }); - } - - } -}); - -$.ui.plugin.add("resizable", "alsoResize", { - - start: function () { - var that = $(this).data("ui-resizable"), - o = that.options, - _store = function (exp) { - $(exp).each(function() { - var el = $(this); - el.data("ui-resizable-alsoresize", { - width: parseInt(el.width(), 10), height: parseInt(el.height(), 10), - left: parseInt(el.css("left"), 10), top: parseInt(el.css("top"), 10) - }); - }); - }; - - if (typeof(o.alsoResize) === "object" && !o.alsoResize.parentNode) { - if (o.alsoResize.length) { o.alsoResize = o.alsoResize[0]; _store(o.alsoResize); } - else { $.each(o.alsoResize, function (exp) { _store(exp); }); } - }else{ - _store(o.alsoResize); - } - }, - - resize: function (event, ui) { - var that = $(this).data("ui-resizable"), - o = that.options, - os = that.originalSize, - op = that.originalPosition, - delta = { - height: (that.size.height - os.height) || 0, width: (that.size.width - os.width) || 0, - top: (that.position.top - op.top) || 0, left: (that.position.left - op.left) || 0 - }, - - _alsoResize = function (exp, c) { - $(exp).each(function() { - var el = $(this), start = $(this).data("ui-resizable-alsoresize"), style = {}, - css = c && c.length ? c : el.parents(ui.originalElement[0]).length ? ["width", "height"] : ["width", "height", "top", "left"]; - - $.each(css, function (i, prop) { - var sum = (start[prop]||0) + (delta[prop]||0); - if (sum && sum >= 0) { - style[prop] = sum || null; - } - }); - - el.css(style); - }); - }; - - if (typeof(o.alsoResize) === "object" && !o.alsoResize.nodeType) { - $.each(o.alsoResize, function (exp, c) { _alsoResize(exp, c); }); - }else{ - _alsoResize(o.alsoResize); - } - }, - - stop: function () { - $(this).removeData("resizable-alsoresize"); - } -}); - -$.ui.plugin.add("resizable", "ghost", { - - start: function() { - - var that = $(this).data("ui-resizable"), o = that.options, cs = that.size; - - that.ghost = that.originalElement.clone(); - that.ghost - .css({ opacity: 0.25, display: "block", position: "relative", height: cs.height, width: cs.width, margin: 0, left: 0, top: 0 }) - .addClass("ui-resizable-ghost") - .addClass(typeof o.ghost === "string" ? o.ghost : ""); - - that.ghost.appendTo(that.helper); - - }, - - resize: function(){ - var that = $(this).data("ui-resizable"); - if (that.ghost) { - that.ghost.css({ position: "relative", height: that.size.height, width: that.size.width }); - } - }, - - stop: function() { - var that = $(this).data("ui-resizable"); - if (that.ghost && that.helper) { - that.helper.get(0).removeChild(that.ghost.get(0)); - } - } - -}); - -$.ui.plugin.add("resizable", "grid", { - - resize: function() { - var that = $(this).data("ui-resizable"), - o = that.options, - cs = that.size, - os = that.originalSize, - op = that.originalPosition, - a = that.axis, - grid = typeof o.grid === "number" ? [o.grid, o.grid] : o.grid, - gridX = (grid[0]||1), - gridY = (grid[1]||1), - ox = Math.round((cs.width - os.width) / gridX) * gridX, - oy = Math.round((cs.height - os.height) / gridY) * gridY, - newWidth = os.width + ox, - newHeight = os.height + oy, - isMaxWidth = o.maxWidth && (o.maxWidth < newWidth), - isMaxHeight = o.maxHeight && (o.maxHeight < newHeight), - isMinWidth = o.minWidth && (o.minWidth > newWidth), - isMinHeight = o.minHeight && (o.minHeight > newHeight); - - o.grid = grid; - - if (isMinWidth) { - newWidth = newWidth + gridX; - } - if (isMinHeight) { - newHeight = newHeight + gridY; - } - if (isMaxWidth) { - newWidth = newWidth - gridX; - } - if (isMaxHeight) { - newHeight = newHeight - gridY; - } - - if (/^(se|s|e)$/.test(a)) { - that.size.width = newWidth; - that.size.height = newHeight; - } else if (/^(ne)$/.test(a)) { - that.size.width = newWidth; - that.size.height = newHeight; - that.position.top = op.top - oy; - } else if (/^(sw)$/.test(a)) { - that.size.width = newWidth; - that.size.height = newHeight; - that.position.left = op.left - ox; - } else { - that.size.width = newWidth; - that.size.height = newHeight; - that.position.top = op.top - oy; - that.position.left = op.left - ox; - } - } - -}); - -})(jQuery); - -(function( $, undefined ) { - -$.widget("ui.selectable", $.ui.mouse, { - version: "1.10.3", - options: { - appendTo: "body", - autoRefresh: true, - distance: 0, - filter: "*", - tolerance: "touch", - - // callbacks - selected: null, - selecting: null, - start: null, - stop: null, - unselected: null, - unselecting: null - }, - _create: function() { - var selectees, - that = this; - - this.element.addClass("ui-selectable"); - - this.dragged = false; - - // cache selectee children based on filter - this.refresh = function() { - selectees = $(that.options.filter, that.element[0]); - selectees.addClass("ui-selectee"); - selectees.each(function() { - var $this = $(this), - pos = $this.offset(); - $.data(this, "selectable-item", { - element: this, - $element: $this, - left: pos.left, - top: pos.top, - right: pos.left + $this.outerWidth(), - bottom: pos.top + $this.outerHeight(), - startselected: false, - selected: $this.hasClass("ui-selected"), - selecting: $this.hasClass("ui-selecting"), - unselecting: $this.hasClass("ui-unselecting") - }); - }); - }; - this.refresh(); - - this.selectees = selectees.addClass("ui-selectee"); - - this._mouseInit(); - - this.helper = $("
"); - }, - - _destroy: function() { - this.selectees - .removeClass("ui-selectee") - .removeData("selectable-item"); - this.element - .removeClass("ui-selectable ui-selectable-disabled"); - this._mouseDestroy(); - }, - - _mouseStart: function(event) { - var that = this, - options = this.options; - - this.opos = [event.pageX, event.pageY]; - - if (this.options.disabled) { - return; - } - - this.selectees = $(options.filter, this.element[0]); - - this._trigger("start", event); - - $(options.appendTo).append(this.helper); - // position helper (lasso) - this.helper.css({ - "left": event.pageX, - "top": event.pageY, - "width": 0, - "height": 0 - }); - - if (options.autoRefresh) { - this.refresh(); - } - - this.selectees.filter(".ui-selected").each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.startselected = true; - if (!event.metaKey && !event.ctrlKey) { - selectee.$element.removeClass("ui-selected"); - selectee.selected = false; - selectee.$element.addClass("ui-unselecting"); - selectee.unselecting = true; - // selectable UNSELECTING callback - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - }); - - $(event.target).parents().addBack().each(function() { - var doSelect, - selectee = $.data(this, "selectable-item"); - if (selectee) { - doSelect = (!event.metaKey && !event.ctrlKey) || !selectee.$element.hasClass("ui-selected"); - selectee.$element - .removeClass(doSelect ? "ui-unselecting" : "ui-selected") - .addClass(doSelect ? "ui-selecting" : "ui-unselecting"); - selectee.unselecting = !doSelect; - selectee.selecting = doSelect; - selectee.selected = doSelect; - // selectable (UN)SELECTING callback - if (doSelect) { - that._trigger("selecting", event, { - selecting: selectee.element - }); - } else { - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - return false; - } - }); - - }, - - _mouseDrag: function(event) { - - this.dragged = true; - - if (this.options.disabled) { - return; - } - - var tmp, - that = this, - options = this.options, - x1 = this.opos[0], - y1 = this.opos[1], - x2 = event.pageX, - y2 = event.pageY; - - if (x1 > x2) { tmp = x2; x2 = x1; x1 = tmp; } - if (y1 > y2) { tmp = y2; y2 = y1; y1 = tmp; } - this.helper.css({left: x1, top: y1, width: x2-x1, height: y2-y1}); - - this.selectees.each(function() { - var selectee = $.data(this, "selectable-item"), - hit = false; - - //prevent helper from being selected if appendTo: selectable - if (!selectee || selectee.element === that.element[0]) { - return; - } - - if (options.tolerance === "touch") { - hit = ( !(selectee.left > x2 || selectee.right < x1 || selectee.top > y2 || selectee.bottom < y1) ); - } else if (options.tolerance === "fit") { - hit = (selectee.left > x1 && selectee.right < x2 && selectee.top > y1 && selectee.bottom < y2); - } - - if (hit) { - // SELECT - if (selectee.selected) { - selectee.$element.removeClass("ui-selected"); - selectee.selected = false; - } - if (selectee.unselecting) { - selectee.$element.removeClass("ui-unselecting"); - selectee.unselecting = false; - } - if (!selectee.selecting) { - selectee.$element.addClass("ui-selecting"); - selectee.selecting = true; - // selectable SELECTING callback - that._trigger("selecting", event, { - selecting: selectee.element - }); - } - } else { - // UNSELECT - if (selectee.selecting) { - if ((event.metaKey || event.ctrlKey) && selectee.startselected) { - selectee.$element.removeClass("ui-selecting"); - selectee.selecting = false; - selectee.$element.addClass("ui-selected"); - selectee.selected = true; - } else { - selectee.$element.removeClass("ui-selecting"); - selectee.selecting = false; - if (selectee.startselected) { - selectee.$element.addClass("ui-unselecting"); - selectee.unselecting = true; - } - // selectable UNSELECTING callback - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - if (selectee.selected) { - if (!event.metaKey && !event.ctrlKey && !selectee.startselected) { - selectee.$element.removeClass("ui-selected"); - selectee.selected = false; - - selectee.$element.addClass("ui-unselecting"); - selectee.unselecting = true; - // selectable UNSELECTING callback - that._trigger("unselecting", event, { - unselecting: selectee.element - }); - } - } - } - }); - - return false; - }, - - _mouseStop: function(event) { - var that = this; - - this.dragged = false; - - $(".ui-unselecting", this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass("ui-unselecting"); - selectee.unselecting = false; - selectee.startselected = false; - that._trigger("unselected", event, { - unselected: selectee.element - }); - }); - $(".ui-selecting", this.element[0]).each(function() { - var selectee = $.data(this, "selectable-item"); - selectee.$element.removeClass("ui-selecting").addClass("ui-selected"); - selectee.selecting = false; - selectee.selected = true; - selectee.startselected = true; - that._trigger("selected", event, { - selected: selectee.element - }); - }); - this._trigger("stop", event); - - this.helper.remove(); - - return false; - } - -}); - -})(jQuery); - -(function( $, undefined ) { - -/*jshint loopfunc: true */ - -function isOverAxis( x, reference, size ) { - return ( x > reference ) && ( x < ( reference + size ) ); -} - -function isFloating(item) { - return (/left|right/).test(item.css("float")) || (/inline|table-cell/).test(item.css("display")); -} - -$.widget("ui.sortable", $.ui.mouse, { - version: "1.10.3", - widgetEventPrefix: "sort", - ready: false, - options: { - appendTo: "parent", - axis: false, - connectWith: false, - containment: false, - cursor: "auto", - cursorAt: false, - dropOnEmpty: true, - forcePlaceholderSize: false, - forceHelperSize: false, - grid: false, - handle: false, - helper: "original", - items: "> *", - opacity: false, - placeholder: false, - revert: false, - scroll: true, - scrollSensitivity: 20, - scrollSpeed: 20, - scope: "default", - tolerance: "intersect", - zIndex: 1000, - - // callbacks - activate: null, - beforeStop: null, - change: null, - deactivate: null, - out: null, - over: null, - receive: null, - remove: null, - sort: null, - start: null, - stop: null, - update: null - }, - _create: function() { - - var o = this.options; - this.containerCache = {}; - this.element.addClass("ui-sortable"); - - //Get the items - this.refresh(); - - //Let's determine if the items are being displayed horizontally - this.floating = this.items.length ? o.axis === "x" || isFloating(this.items[0].item) : false; - - //Let's determine the parent's offset - this.offset = this.element.offset(); - - //Initialize mouse events for interaction - this._mouseInit(); - - //We're ready to go - this.ready = true; - - }, - - _destroy: function() { - this.element - .removeClass("ui-sortable ui-sortable-disabled"); - this._mouseDestroy(); - - for ( var i = this.items.length - 1; i >= 0; i-- ) { - this.items[i].item.removeData(this.widgetName + "-item"); - } - - return this; - }, - - _setOption: function(key, value){ - if ( key === "disabled" ) { - this.options[ key ] = value; - - this.widget().toggleClass( "ui-sortable-disabled", !!value ); - } else { - // Don't call widget base _setOption for disable as it adds ui-state-disabled class - $.Widget.prototype._setOption.apply(this, arguments); - } - }, - - _mouseCapture: function(event, overrideHandle) { - var currentItem = null, - validHandle = false, - that = this; - - if (this.reverting) { - return false; - } - - if(this.options.disabled || this.options.type === "static") { - return false; - } - - //We have to refresh the items data once first - this._refreshItems(event); - - //Find out if the clicked node (or one of its parents) is a actual item in this.items - $(event.target).parents().each(function() { - if($.data(this, that.widgetName + "-item") === that) { - currentItem = $(this); - return false; - } - }); - if($.data(event.target, that.widgetName + "-item") === that) { - currentItem = $(event.target); - } - - if(!currentItem) { - return false; - } - if(this.options.handle && !overrideHandle) { - $(this.options.handle, currentItem).find("*").addBack().each(function() { - if(this === event.target) { - validHandle = true; - } - }); - if(!validHandle) { - return false; - } - } - - this.currentItem = currentItem; - this._removeCurrentsFromItems(); - return true; - - }, - - _mouseStart: function(event, overrideHandle, noActivation) { - - var i, body, - o = this.options; - - this.currentContainer = this; - - //We only need to call refreshPositions, because the refreshItems call has been moved to mouseCapture - this.refreshPositions(); - - //Create and append the visible helper - this.helper = this._createHelper(event); - - //Cache the helper size - this._cacheHelperProportions(); - - /* - * - Position generation - - * This block generates everything position related - it's the core of draggables. - */ - - //Cache the margins of the original element - this._cacheMargins(); - - //Get the next scrolling parent - this.scrollParent = this.helper.scrollParent(); - - //The element's absolute position on the page minus margins - this.offset = this.currentItem.offset(); - this.offset = { - top: this.offset.top - this.margins.top, - left: this.offset.left - this.margins.left - }; - - $.extend(this.offset, { - click: { //Where the click happened, relative to the element - left: event.pageX - this.offset.left, - top: event.pageY - this.offset.top - }, - parent: this._getParentOffset(), - relative: this._getRelativeOffset() //This is a relative to absolute position minus the actual position calculation - only used for relative positioned helper - }); - - // Only after we got the offset, we can change the helper's position to absolute - // TODO: Still need to figure out a way to make relative sorting possible - this.helper.css("position", "absolute"); - this.cssPosition = this.helper.css("position"); - - //Generate the original position - this.originalPosition = this._generatePosition(event); - this.originalPageX = event.pageX; - this.originalPageY = event.pageY; - - //Adjust the mouse offset relative to the helper if "cursorAt" is supplied - (o.cursorAt && this._adjustOffsetFromHelper(o.cursorAt)); - - //Cache the former DOM position - this.domPosition = { prev: this.currentItem.prev()[0], parent: this.currentItem.parent()[0] }; - - //If the helper is not the original, hide the original so it's not playing any role during the drag, won't cause anything bad this way - if(this.helper[0] !== this.currentItem[0]) { - this.currentItem.hide(); - } - - //Create the placeholder - this._createPlaceholder(); - - //Set a containment if given in the options - if(o.containment) { - this._setContainment(); - } - - if( o.cursor && o.cursor !== "auto" ) { // cursor option - body = this.document.find( "body" ); - - // support: IE - this.storedCursor = body.css( "cursor" ); - body.css( "cursor", o.cursor ); - - this.storedStylesheet = $( "" ).appendTo( body ); - } - - if(o.opacity) { // opacity option - if (this.helper.css("opacity")) { - this._storedOpacity = this.helper.css("opacity"); - } - this.helper.css("opacity", o.opacity); - } - - if(o.zIndex) { // zIndex option - if (this.helper.css("zIndex")) { - this._storedZIndex = this.helper.css("zIndex"); - } - this.helper.css("zIndex", o.zIndex); - } - - //Prepare scrolling - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - this.overflowOffset = this.scrollParent.offset(); - } - - //Call callbacks - this._trigger("start", event, this._uiHash()); - - //Recache the helper size - if(!this._preserveHelperProportions) { - this._cacheHelperProportions(); - } - - - //Post "activate" events to possible containers - if( !noActivation ) { - for ( i = this.containers.length - 1; i >= 0; i-- ) { - this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) ); - } - } - - //Prepare possible droppables - if($.ui.ddmanager) { - $.ui.ddmanager.current = this; - } - - if ($.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - - this.dragging = true; - - this.helper.addClass("ui-sortable-helper"); - this._mouseDrag(event); //Execute the drag once - this causes the helper not to be visible before getting its correct position - return true; - - }, - - _mouseDrag: function(event) { - var i, item, itemElement, intersection, - o = this.options, - scrolled = false; - - //Compute the helpers position - this.position = this._generatePosition(event); - this.positionAbs = this._convertPositionTo("absolute"); - - if (!this.lastPositionAbs) { - this.lastPositionAbs = this.positionAbs; - } - - //Do scrolling - if(this.options.scroll) { - if(this.scrollParent[0] !== document && this.scrollParent[0].tagName !== "HTML") { - - if((this.overflowOffset.top + this.scrollParent[0].offsetHeight) - event.pageY < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop + o.scrollSpeed; - } else if(event.pageY - this.overflowOffset.top < o.scrollSensitivity) { - this.scrollParent[0].scrollTop = scrolled = this.scrollParent[0].scrollTop - o.scrollSpeed; - } - - if((this.overflowOffset.left + this.scrollParent[0].offsetWidth) - event.pageX < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft + o.scrollSpeed; - } else if(event.pageX - this.overflowOffset.left < o.scrollSensitivity) { - this.scrollParent[0].scrollLeft = scrolled = this.scrollParent[0].scrollLeft - o.scrollSpeed; - } - - } else { - - if(event.pageY - $(document).scrollTop() < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() - o.scrollSpeed); - } else if($(window).height() - (event.pageY - $(document).scrollTop()) < o.scrollSensitivity) { - scrolled = $(document).scrollTop($(document).scrollTop() + o.scrollSpeed); - } - - if(event.pageX - $(document).scrollLeft() < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() - o.scrollSpeed); - } else if($(window).width() - (event.pageX - $(document).scrollLeft()) < o.scrollSensitivity) { - scrolled = $(document).scrollLeft($(document).scrollLeft() + o.scrollSpeed); - } - - } - - if(scrolled !== false && $.ui.ddmanager && !o.dropBehaviour) { - $.ui.ddmanager.prepareOffsets(this, event); - } - } - - //Regenerate the absolute position used for position checks - this.positionAbs = this._convertPositionTo("absolute"); - - //Set the helper position - if(!this.options.axis || this.options.axis !== "y") { - this.helper[0].style.left = this.position.left+"px"; - } - if(!this.options.axis || this.options.axis !== "x") { - this.helper[0].style.top = this.position.top+"px"; - } - - //Rearrange - for (i = this.items.length - 1; i >= 0; i--) { - - //Cache variables and intersection, continue if no intersection - item = this.items[i]; - itemElement = item.item[0]; - intersection = this._intersectsWithPointer(item); - if (!intersection) { - continue; - } - - // Only put the placeholder inside the current Container, skip all - // items form other containers. This works because when moving - // an item from one container to another the - // currentContainer is switched before the placeholder is moved. - // - // Without this moving items in "sub-sortables" can cause the placeholder to jitter - // beetween the outer and inner container. - if (item.instance !== this.currentContainer) { - continue; - } - - // cannot intersect with itself - // no useless actions that have been done before - // no action if the item moved is the parent of the item checked - if (itemElement !== this.currentItem[0] && - this.placeholder[intersection === 1 ? "next" : "prev"]()[0] !== itemElement && - !$.contains(this.placeholder[0], itemElement) && - (this.options.type === "semi-dynamic" ? !$.contains(this.element[0], itemElement) : true) - ) { - - this.direction = intersection === 1 ? "down" : "up"; - - if (this.options.tolerance === "pointer" || this._intersectsWithSides(item)) { - this._rearrange(event, item); - } else { - break; - } - - this._trigger("change", event, this._uiHash()); - break; - } - } - - //Post events to containers - this._contactContainers(event); - - //Interconnect with droppables - if($.ui.ddmanager) { - $.ui.ddmanager.drag(this, event); - } - - //Call callbacks - this._trigger("sort", event, this._uiHash()); - - this.lastPositionAbs = this.positionAbs; - return false; - - }, - - _mouseStop: function(event, noPropagation) { - - if(!event) { - return; - } - - //If we are using droppables, inform the manager about the drop - if ($.ui.ddmanager && !this.options.dropBehaviour) { - $.ui.ddmanager.drop(this, event); - } - - if(this.options.revert) { - var that = this, - cur = this.placeholder.offset(), - axis = this.options.axis, - animation = {}; - - if ( !axis || axis === "x" ) { - animation.left = cur.left - this.offset.parent.left - this.margins.left + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollLeft); - } - if ( !axis || axis === "y" ) { - animation.top = cur.top - this.offset.parent.top - this.margins.top + (this.offsetParent[0] === document.body ? 0 : this.offsetParent[0].scrollTop); - } - this.reverting = true; - $(this.helper).animate( animation, parseInt(this.options.revert, 10) || 500, function() { - that._clear(event); - }); - } else { - this._clear(event, noPropagation); - } - - return false; - - }, - - cancel: function() { - - if(this.dragging) { - - this._mouseUp({ target: null }); - - if(this.options.helper === "original") { - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - //Post deactivating events to containers - for (var i = this.containers.length - 1; i >= 0; i--){ - this.containers[i]._trigger("deactivate", null, this._uiHash(this)); - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", null, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - if (this.placeholder) { - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - if(this.placeholder[0].parentNode) { - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - } - if(this.options.helper !== "original" && this.helper && this.helper[0].parentNode) { - this.helper.remove(); - } - - $.extend(this, { - helper: null, - dragging: false, - reverting: false, - _noFinalSort: null - }); - - if(this.domPosition.prev) { - $(this.domPosition.prev).after(this.currentItem); - } else { - $(this.domPosition.parent).prepend(this.currentItem); - } - } - - return this; - - }, - - serialize: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - str = []; - o = o || {}; - - $(items).each(function() { - var res = ($(o.item || this).attr(o.attribute || "id") || "").match(o.expression || (/(.+)[\-=_](.+)/)); - if (res) { - str.push((o.key || res[1]+"[]")+"="+(o.key && o.expression ? res[1] : res[2])); - } - }); - - if(!str.length && o.key) { - str.push(o.key + "="); - } - - return str.join("&"); - - }, - - toArray: function(o) { - - var items = this._getItemsAsjQuery(o && o.connected), - ret = []; - - o = o || {}; - - items.each(function() { ret.push($(o.item || this).attr(o.attribute || "id") || ""); }); - return ret; - - }, - - /* Be careful with the following core functions */ - _intersectsWith: function(item) { - - var x1 = this.positionAbs.left, - x2 = x1 + this.helperProportions.width, - y1 = this.positionAbs.top, - y2 = y1 + this.helperProportions.height, - l = item.left, - r = l + item.width, - t = item.top, - b = t + item.height, - dyClick = this.offset.click.top, - dxClick = this.offset.click.left, - isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t && ( y1 + dyClick ) < b ), - isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l && ( x1 + dxClick ) < r ), - isOverElement = isOverElementHeight && isOverElementWidth; - - if ( this.options.tolerance === "pointer" || - this.options.forcePointerForContainers || - (this.options.tolerance !== "pointer" && this.helperProportions[this.floating ? "width" : "height"] > item[this.floating ? "width" : "height"]) - ) { - return isOverElement; - } else { - - return (l < x1 + (this.helperProportions.width / 2) && // Right Half - x2 - (this.helperProportions.width / 2) < r && // Left Half - t < y1 + (this.helperProportions.height / 2) && // Bottom Half - y2 - (this.helperProportions.height / 2) < b ); // Top Half - - } - }, - - _intersectsWithPointer: function(item) { - - var isOverElementHeight = (this.options.axis === "x") || isOverAxis(this.positionAbs.top + this.offset.click.top, item.top, item.height), - isOverElementWidth = (this.options.axis === "y") || isOverAxis(this.positionAbs.left + this.offset.click.left, item.left, item.width), - isOverElement = isOverElementHeight && isOverElementWidth, - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (!isOverElement) { - return false; - } - - return this.floating ? - ( ((horizontalDirection && horizontalDirection === "right") || verticalDirection === "down") ? 2 : 1 ) - : ( verticalDirection && (verticalDirection === "down" ? 2 : 1) ); - - }, - - _intersectsWithSides: function(item) { - - var isOverBottomHalf = isOverAxis(this.positionAbs.top + this.offset.click.top, item.top + (item.height/2), item.height), - isOverRightHalf = isOverAxis(this.positionAbs.left + this.offset.click.left, item.left + (item.width/2), item.width), - verticalDirection = this._getDragVerticalDirection(), - horizontalDirection = this._getDragHorizontalDirection(); - - if (this.floating && horizontalDirection) { - return ((horizontalDirection === "right" && isOverRightHalf) || (horizontalDirection === "left" && !isOverRightHalf)); - } else { - return verticalDirection && ((verticalDirection === "down" && isOverBottomHalf) || (verticalDirection === "up" && !isOverBottomHalf)); - } - - }, - - _getDragVerticalDirection: function() { - var delta = this.positionAbs.top - this.lastPositionAbs.top; - return delta !== 0 && (delta > 0 ? "down" : "up"); - }, - - _getDragHorizontalDirection: function() { - var delta = this.positionAbs.left - this.lastPositionAbs.left; - return delta !== 0 && (delta > 0 ? "right" : "left"); - }, - - refresh: function(event) { - this._refreshItems(event); - this.refreshPositions(); - return this; - }, - - _connectWith: function() { - var options = this.options; - return options.connectWith.constructor === String ? [options.connectWith] : options.connectWith; - }, - - _getItemsAsjQuery: function(connected) { - - var i, j, cur, inst, - items = [], - queries = [], - connectWith = this._connectWith(); - - if(connectWith && connected) { - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for ( j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element) : $(inst.options.items, inst.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), inst]); - } - } - } - } - - queries.push([$.isFunction(this.options.items) ? this.options.items.call(this.element, null, { options: this.options, item: this.currentItem }) : $(this.options.items, this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"), this]); - - for (i = queries.length - 1; i >= 0; i--){ - queries[i][0].each(function() { - items.push(this); - }); - } - - return $(items); - - }, - - _removeCurrentsFromItems: function() { - - var list = this.currentItem.find(":data(" + this.widgetName + "-item)"); - - this.items = $.grep(this.items, function (item) { - for (var j=0; j < list.length; j++) { - if(list[j] === item.item[0]) { - return false; - } - } - return true; - }); - - }, - - _refreshItems: function(event) { - - this.items = []; - this.containers = [this]; - - var i, j, cur, inst, targetData, _queries, item, queriesLength, - items = this.items, - queries = [[$.isFunction(this.options.items) ? this.options.items.call(this.element[0], event, { item: this.currentItem }) : $(this.options.items, this.element), this]], - connectWith = this._connectWith(); - - if(connectWith && this.ready) { //Shouldn't be run the first time through due to massive slow-down - for (i = connectWith.length - 1; i >= 0; i--){ - cur = $(connectWith[i]); - for (j = cur.length - 1; j >= 0; j--){ - inst = $.data(cur[j], this.widgetFullName); - if(inst && inst !== this && !inst.options.disabled) { - queries.push([$.isFunction(inst.options.items) ? inst.options.items.call(inst.element[0], event, { item: this.currentItem }) : $(inst.options.items, inst.element), inst]); - this.containers.push(inst); - } - } - } - } - - for (i = queries.length - 1; i >= 0; i--) { - targetData = queries[i][1]; - _queries = queries[i][0]; - - for (j=0, queriesLength = _queries.length; j < queriesLength; j++) { - item = $(_queries[j]); - - item.data(this.widgetName + "-item", targetData); // Data for target checking (mouse manager) - - items.push({ - item: item, - instance: targetData, - width: 0, height: 0, - left: 0, top: 0 - }); - } - } - - }, - - refreshPositions: function(fast) { - - //This has to be redone because due to the item being moved out/into the offsetParent, the offsetParent's position will change - if(this.offsetParent && this.helper) { - this.offset.parent = this._getParentOffset(); - } - - var i, item, t, p; - - for (i = this.items.length - 1; i >= 0; i--){ - item = this.items[i]; - - //We ignore calculating positions of all connected containers when we're not over them - if(item.instance !== this.currentContainer && this.currentContainer && item.item[0] !== this.currentItem[0]) { - continue; - } - - t = this.options.toleranceElement ? $(this.options.toleranceElement, item.item) : item.item; - - if (!fast) { - item.width = t.outerWidth(); - item.height = t.outerHeight(); - } - - p = t.offset(); - item.left = p.left; - item.top = p.top; - } - - if(this.options.custom && this.options.custom.refreshContainers) { - this.options.custom.refreshContainers.call(this); - } else { - for (i = this.containers.length - 1; i >= 0; i--){ - p = this.containers[i].element.offset(); - this.containers[i].containerCache.left = p.left; - this.containers[i].containerCache.top = p.top; - this.containers[i].containerCache.width = this.containers[i].element.outerWidth(); - this.containers[i].containerCache.height = this.containers[i].element.outerHeight(); - } - } - - return this; - }, - - _createPlaceholder: function(that) { - that = that || this; - var className, - o = that.options; - - if(!o.placeholder || o.placeholder.constructor === String) { - className = o.placeholder; - o.placeholder = { - element: function() { - - var nodeName = that.currentItem[0].nodeName.toLowerCase(), - element = $( "<" + nodeName + ">", that.document[0] ) - .addClass(className || that.currentItem[0].className+" ui-sortable-placeholder") - .removeClass("ui-sortable-helper"); - - if ( nodeName === "tr" ) { - that.currentItem.children().each(function() { - $( " ", that.document[0] ) - .attr( "colspan", $( this ).attr( "colspan" ) || 1 ) - .appendTo( element ); - }); - } else if ( nodeName === "img" ) { - element.attr( "src", that.currentItem.attr( "src" ) ); - } - - if ( !className ) { - element.css( "visibility", "hidden" ); - } - - return element; - }, - update: function(container, p) { - - // 1. If a className is set as 'placeholder option, we don't force sizes - the class is responsible for that - // 2. The option 'forcePlaceholderSize can be enabled to force it even if a class name is specified - if(className && !o.forcePlaceholderSize) { - return; - } - - //If the element doesn't have a actual height by itself (without styles coming from a stylesheet), it receives the inline height from the dragged item - if(!p.height()) { p.height(that.currentItem.innerHeight() - parseInt(that.currentItem.css("paddingTop")||0, 10) - parseInt(that.currentItem.css("paddingBottom")||0, 10)); } - if(!p.width()) { p.width(that.currentItem.innerWidth() - parseInt(that.currentItem.css("paddingLeft")||0, 10) - parseInt(that.currentItem.css("paddingRight")||0, 10)); } - } - }; - } - - //Create the placeholder - that.placeholder = $(o.placeholder.element.call(that.element, that.currentItem)); - - //Append it after the actual current item - that.currentItem.after(that.placeholder); - - //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317) - o.placeholder.update(that, that.placeholder); - - }, - - _contactContainers: function(event) { - var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, base, cur, nearBottom, floating, - innermostContainer = null, - innermostIndex = null; - - // get innermost container that intersects with item - for (i = this.containers.length - 1; i >= 0; i--) { - - // never consider a container that's located within the item itself - if($.contains(this.currentItem[0], this.containers[i].element[0])) { - continue; - } - - if(this._intersectsWith(this.containers[i].containerCache)) { - - // if we've already found a container and it's more "inner" than this, then continue - if(innermostContainer && $.contains(this.containers[i].element[0], innermostContainer.element[0])) { - continue; - } - - innermostContainer = this.containers[i]; - innermostIndex = i; - - } else { - // container doesn't intersect. trigger "out" event if necessary - if(this.containers[i].containerCache.over) { - this.containers[i]._trigger("out", event, this._uiHash(this)); - this.containers[i].containerCache.over = 0; - } - } - - } - - // if no intersecting containers found, return - if(!innermostContainer) { - return; - } - - // move the item into the container if it's not there already - if(this.containers.length === 1) { - if (!this.containers[innermostIndex].containerCache.over) { - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - } else { - - //When entering a new container, we will find the item with the least distance and append our item near it - dist = 10000; - itemWithLeastDistance = null; - floating = innermostContainer.floating || isFloating(this.currentItem); - posProperty = floating ? "left" : "top"; - sizeProperty = floating ? "width" : "height"; - base = this.positionAbs[posProperty] + this.offset.click[posProperty]; - for (j = this.items.length - 1; j >= 0; j--) { - if(!$.contains(this.containers[innermostIndex].element[0], this.items[j].item[0])) { - continue; - } - if(this.items[j].item[0] === this.currentItem[0]) { - continue; - } - if (floating && !isOverAxis(this.positionAbs.top + this.offset.click.top, this.items[j].top, this.items[j].height)) { - continue; - } - cur = this.items[j].item.offset()[posProperty]; - nearBottom = false; - if(Math.abs(cur - base) > Math.abs(cur + this.items[j][sizeProperty] - base)){ - nearBottom = true; - cur += this.items[j][sizeProperty]; - } - - if(Math.abs(cur - base) < dist) { - dist = Math.abs(cur - base); itemWithLeastDistance = this.items[j]; - this.direction = nearBottom ? "up": "down"; - } - } - - //Check if dropOnEmpty is enabled - if(!itemWithLeastDistance && !this.options.dropOnEmpty) { - return; - } - - if(this.currentContainer === this.containers[innermostIndex]) { - return; - } - - itemWithLeastDistance ? this._rearrange(event, itemWithLeastDistance, null, true) : this._rearrange(event, null, this.containers[innermostIndex].element, true); - this._trigger("change", event, this._uiHash()); - this.containers[innermostIndex]._trigger("change", event, this._uiHash(this)); - this.currentContainer = this.containers[innermostIndex]; - - //Update the placeholder - this.options.placeholder.update(this.currentContainer, this.placeholder); - - this.containers[innermostIndex]._trigger("over", event, this._uiHash(this)); - this.containers[innermostIndex].containerCache.over = 1; - } - - - }, - - _createHelper: function(event) { - - var o = this.options, - helper = $.isFunction(o.helper) ? $(o.helper.apply(this.element[0], [event, this.currentItem])) : (o.helper === "clone" ? this.currentItem.clone() : this.currentItem); - - //Add the helper to the DOM if that didn't happen already - if(!helper.parents("body").length) { - $(o.appendTo !== "parent" ? o.appendTo : this.currentItem[0].parentNode)[0].appendChild(helper[0]); - } - - if(helper[0] === this.currentItem[0]) { - this._storedCSS = { width: this.currentItem[0].style.width, height: this.currentItem[0].style.height, position: this.currentItem.css("position"), top: this.currentItem.css("top"), left: this.currentItem.css("left") }; - } - - if(!helper[0].style.width || o.forceHelperSize) { - helper.width(this.currentItem.width()); - } - if(!helper[0].style.height || o.forceHelperSize) { - helper.height(this.currentItem.height()); - } - - return helper; - - }, - - _adjustOffsetFromHelper: function(obj) { - if (typeof obj === "string") { - obj = obj.split(" "); - } - if ($.isArray(obj)) { - obj = {left: +obj[0], top: +obj[1] || 0}; - } - if ("left" in obj) { - this.offset.click.left = obj.left + this.margins.left; - } - if ("right" in obj) { - this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left; - } - if ("top" in obj) { - this.offset.click.top = obj.top + this.margins.top; - } - if ("bottom" in obj) { - this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top; - } - }, - - _getParentOffset: function() { - - - //Get the offsetParent and cache its position - this.offsetParent = this.helper.offsetParent(); - var po = this.offsetParent.offset(); - - // This is a special case where we need to modify a offset calculated on start, since the following happened: - // 1. The position of the helper is absolute, so it's position is calculated based on the next positioned parent - // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't the document, which means that - // the scroll is included in the initial calculation of the offset of the parent, and never recalculated upon drag - if(this.cssPosition === "absolute" && this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) { - po.left += this.scrollParent.scrollLeft(); - po.top += this.scrollParent.scrollTop(); - } - - // This needs to be actually done for all browsers, since pageX/pageY includes this information - // with an ugly IE fix - if( this.offsetParent[0] === document.body || (this.offsetParent[0].tagName && this.offsetParent[0].tagName.toLowerCase() === "html" && $.ui.ie)) { - po = { top: 0, left: 0 }; - } - - return { - top: po.top + (parseInt(this.offsetParent.css("borderTopWidth"),10) || 0), - left: po.left + (parseInt(this.offsetParent.css("borderLeftWidth"),10) || 0) - }; - - }, - - _getRelativeOffset: function() { - - if(this.cssPosition === "relative") { - var p = this.currentItem.position(); - return { - top: p.top - (parseInt(this.helper.css("top"),10) || 0) + this.scrollParent.scrollTop(), - left: p.left - (parseInt(this.helper.css("left"),10) || 0) + this.scrollParent.scrollLeft() - }; - } else { - return { top: 0, left: 0 }; - } - - }, - - _cacheMargins: function() { - this.margins = { - left: (parseInt(this.currentItem.css("marginLeft"),10) || 0), - top: (parseInt(this.currentItem.css("marginTop"),10) || 0) - }; - }, - - _cacheHelperProportions: function() { - this.helperProportions = { - width: this.helper.outerWidth(), - height: this.helper.outerHeight() - }; - }, - - _setContainment: function() { - - var ce, co, over, - o = this.options; - if(o.containment === "parent") { - o.containment = this.helper[0].parentNode; - } - if(o.containment === "document" || o.containment === "window") { - this.containment = [ - 0 - this.offset.relative.left - this.offset.parent.left, - 0 - this.offset.relative.top - this.offset.parent.top, - $(o.containment === "document" ? document : window).width() - this.helperProportions.width - this.margins.left, - ($(o.containment === "document" ? document : window).height() || document.body.parentNode.scrollHeight) - this.helperProportions.height - this.margins.top - ]; - } - - if(!(/^(document|window|parent)$/).test(o.containment)) { - ce = $(o.containment)[0]; - co = $(o.containment).offset(); - over = ($(ce).css("overflow") !== "hidden"); - - this.containment = [ - co.left + (parseInt($(ce).css("borderLeftWidth"),10) || 0) + (parseInt($(ce).css("paddingLeft"),10) || 0) - this.margins.left, - co.top + (parseInt($(ce).css("borderTopWidth"),10) || 0) + (parseInt($(ce).css("paddingTop"),10) || 0) - this.margins.top, - co.left+(over ? Math.max(ce.scrollWidth,ce.offsetWidth) : ce.offsetWidth) - (parseInt($(ce).css("borderLeftWidth"),10) || 0) - (parseInt($(ce).css("paddingRight"),10) || 0) - this.helperProportions.width - this.margins.left, - co.top+(over ? Math.max(ce.scrollHeight,ce.offsetHeight) : ce.offsetHeight) - (parseInt($(ce).css("borderTopWidth"),10) || 0) - (parseInt($(ce).css("paddingBottom"),10) || 0) - this.helperProportions.height - this.margins.top - ]; - } - - }, - - _convertPositionTo: function(d, pos) { - - if(!pos) { - pos = this.position; - } - var mod = d === "absolute" ? 1 : -1, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, - scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - return { - top: ( - pos.top + // The absolute mouse position - this.offset.relative.top * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod) - ), - left: ( - pos.left + // The absolute mouse position - this.offset.relative.left * mod + // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left * mod - // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() ) * mod) - ) - }; - - }, - - _generatePosition: function(event) { - - var top, left, - o = this.options, - pageX = event.pageX, - pageY = event.pageY, - scroll = this.cssPosition === "absolute" && !(this.scrollParent[0] !== document && $.contains(this.scrollParent[0], this.offsetParent[0])) ? this.offsetParent : this.scrollParent, scrollIsRootNode = (/(html|body)/i).test(scroll[0].tagName); - - // This is another very weird special case that only happens for relative elements: - // 1. If the css position is relative - // 2. and the scroll parent is the document or similar to the offset parent - // we have to refresh the relative offset during the scroll so there are no jumps - if(this.cssPosition === "relative" && !(this.scrollParent[0] !== document && this.scrollParent[0] !== this.offsetParent[0])) { - this.offset.relative = this._getRelativeOffset(); - } - - /* - * - Position constraining - - * Constrain the position to a mix of grid, containment. - */ - - if(this.originalPosition) { //If we are not dragging yet, we won't check for options - - if(this.containment) { - if(event.pageX - this.offset.click.left < this.containment[0]) { - pageX = this.containment[0] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top < this.containment[1]) { - pageY = this.containment[1] + this.offset.click.top; - } - if(event.pageX - this.offset.click.left > this.containment[2]) { - pageX = this.containment[2] + this.offset.click.left; - } - if(event.pageY - this.offset.click.top > this.containment[3]) { - pageY = this.containment[3] + this.offset.click.top; - } - } - - if(o.grid) { - top = this.originalPageY + Math.round((pageY - this.originalPageY) / o.grid[1]) * o.grid[1]; - pageY = this.containment ? ( (top - this.offset.click.top >= this.containment[1] && top - this.offset.click.top <= this.containment[3]) ? top : ((top - this.offset.click.top >= this.containment[1]) ? top - o.grid[1] : top + o.grid[1])) : top; - - left = this.originalPageX + Math.round((pageX - this.originalPageX) / o.grid[0]) * o.grid[0]; - pageX = this.containment ? ( (left - this.offset.click.left >= this.containment[0] && left - this.offset.click.left <= this.containment[2]) ? left : ((left - this.offset.click.left >= this.containment[0]) ? left - o.grid[0] : left + o.grid[0])) : left; - } - - } - - return { - top: ( - pageY - // The absolute mouse position - this.offset.click.top - // Click offset (relative to the element) - this.offset.relative.top - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.top + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollTop() : ( scrollIsRootNode ? 0 : scroll.scrollTop() ) )) - ), - left: ( - pageX - // The absolute mouse position - this.offset.click.left - // Click offset (relative to the element) - this.offset.relative.left - // Only for relative positioned nodes: Relative offset from element to offset parent - this.offset.parent.left + // The offsetParent's offset without borders (offset + border) - ( ( this.cssPosition === "fixed" ? -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 : scroll.scrollLeft() )) - ) - }; - - }, - - _rearrange: function(event, i, a, hardRefresh) { - - a ? a[0].appendChild(this.placeholder[0]) : i.item[0].parentNode.insertBefore(this.placeholder[0], (this.direction === "down" ? i.item[0] : i.item[0].nextSibling)); - - //Various things done here to improve the performance: - // 1. we create a setTimeout, that calls refreshPositions - // 2. on the instance, we have a counter variable, that get's higher after every append - // 3. on the local scope, we copy the counter variable, and check in the timeout, if it's still the same - // 4. this lets only the last addition to the timeout stack through - this.counter = this.counter ? ++this.counter : 1; - var counter = this.counter; - - this._delay(function() { - if(counter === this.counter) { - this.refreshPositions(!hardRefresh); //Precompute after each DOM insertion, NOT on mousemove - } - }); - - }, - - _clear: function(event, noPropagation) { - - this.reverting = false; - // We delay all events that have to be triggered to after the point where the placeholder has been removed and - // everything else normalized again - var i, - delayedTriggers = []; - - // We first have to update the dom position of the actual currentItem - // Note: don't do it if the current item is already removed (by a user), or it gets reappended (see #4088) - if(!this._noFinalSort && this.currentItem.parent().length) { - this.placeholder.before(this.currentItem); - } - this._noFinalSort = null; - - if(this.helper[0] === this.currentItem[0]) { - for(i in this._storedCSS) { - if(this._storedCSS[i] === "auto" || this._storedCSS[i] === "static") { - this._storedCSS[i] = ""; - } - } - this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"); - } else { - this.currentItem.show(); - } - - if(this.fromOutside && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("receive", event, this._uiHash(this.fromOutside)); }); - } - if((this.fromOutside || this.domPosition.prev !== this.currentItem.prev().not(".ui-sortable-helper")[0] || this.domPosition.parent !== this.currentItem.parent()[0]) && !noPropagation) { - delayedTriggers.push(function(event) { this._trigger("update", event, this._uiHash()); }); //Trigger update callback if the DOM position has changed - } - - // Check if the items Container has Changed and trigger appropriate - // events. - if (this !== this.currentContainer) { - if(!noPropagation) { - delayedTriggers.push(function(event) { this._trigger("remove", event, this._uiHash()); }); - delayedTriggers.push((function(c) { return function(event) { c._trigger("receive", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - delayedTriggers.push((function(c) { return function(event) { c._trigger("update", event, this._uiHash(this)); }; }).call(this, this.currentContainer)); - } - } - - - //Post events to containers - for (i = this.containers.length - 1; i >= 0; i--){ - if(!noPropagation) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("deactivate", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - } - if(this.containers[i].containerCache.over) { - delayedTriggers.push((function(c) { return function(event) { c._trigger("out", event, this._uiHash(this)); }; }).call(this, this.containers[i])); - this.containers[i].containerCache.over = 0; - } - } - - //Do what was originally in plugins - if ( this.storedCursor ) { - this.document.find( "body" ).css( "cursor", this.storedCursor ); - this.storedStylesheet.remove(); - } - if(this._storedOpacity) { - this.helper.css("opacity", this._storedOpacity); - } - if(this._storedZIndex) { - this.helper.css("zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex); - } - - this.dragging = false; - if(this.cancelHelperRemoval) { - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return false; - } - - if(!noPropagation) { - this._trigger("beforeStop", event, this._uiHash()); - } - - //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately, it unbinds ALL events from the original node! - this.placeholder[0].parentNode.removeChild(this.placeholder[0]); - - if(this.helper[0] !== this.currentItem[0]) { - this.helper.remove(); - } - this.helper = null; - - if(!noPropagation) { - for (i=0; i < delayedTriggers.length; i++) { - delayedTriggers[i].call(this, event); - } //Trigger all delayed events - this._trigger("stop", event, this._uiHash()); - } - - this.fromOutside = false; - return true; - - }, - - _trigger: function() { - if ($.Widget.prototype._trigger.apply(this, arguments) === false) { - this.cancel(); - } - }, - - _uiHash: function(_inst) { - var inst = _inst || this; - return { - helper: inst.helper, - placeholder: inst.placeholder || $([]), - position: inst.position, - originalPosition: inst.originalPosition, - offset: inst.positionAbs, - item: inst.currentItem, - sender: _inst ? _inst.element : null - }; - } - -}); - -})(jQuery); - -(function($, undefined) { - -var dataSpace = "ui-effects-"; - -$.effects = { - effect: {} -}; - -/*! - * jQuery Color Animations v2.1.2 - * https://github.com/jquery/jquery-color - * - * Copyright 2013 jQuery Foundation and other contributors - * Released under the MIT license. - * http://jquery.org/license - * - * Date: Wed Jan 16 08:47:09 2013 -0600 - */ -(function( jQuery, undefined ) { - - var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", - - // plusequals test for += 100 -= 100 - rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, - // a set of RE's that can match strings and generate color tuples. - stringParsers = [{ - re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, - parse: function( execResult ) { - return [ - execResult[ 1 ], - execResult[ 2 ], - execResult[ 3 ], - execResult[ 4 ] - ]; - } - }, { - re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, - parse: function( execResult ) { - return [ - execResult[ 1 ] * 2.55, - execResult[ 2 ] * 2.55, - execResult[ 3 ] * 2.55, - execResult[ 4 ] - ]; - } - }, { - // this regex ignores A-F because it's compared against an already lowercased string - re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, - parse: function( execResult ) { - return [ - parseInt( execResult[ 1 ], 16 ), - parseInt( execResult[ 2 ], 16 ), - parseInt( execResult[ 3 ], 16 ) - ]; - } - }, { - // this regex ignores A-F because it's compared against an already lowercased string - re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, - parse: function( execResult ) { - return [ - parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), - parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), - parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ) - ]; - } - }, { - re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, - space: "hsla", - parse: function( execResult ) { - return [ - execResult[ 1 ], - execResult[ 2 ] / 100, - execResult[ 3 ] / 100, - execResult[ 4 ] - ]; - } - }], - - // jQuery.Color( ) - color = jQuery.Color = function( color, green, blue, alpha ) { - return new jQuery.Color.fn.parse( color, green, blue, alpha ); - }, - spaces = { - rgba: { - props: { - red: { - idx: 0, - type: "byte" - }, - green: { - idx: 1, - type: "byte" - }, - blue: { - idx: 2, - type: "byte" - } - } - }, - - hsla: { - props: { - hue: { - idx: 0, - type: "degrees" - }, - saturation: { - idx: 1, - type: "percent" - }, - lightness: { - idx: 2, - type: "percent" - } - } - } - }, - propTypes = { - "byte": { - floor: true, - max: 255 - }, - "percent": { - max: 1 - }, - "degrees": { - mod: 360, - floor: true - } - }, - support = color.support = {}, - - // element for support tests - supportElem = jQuery( "

" )[ 0 ], - - // colors = jQuery.Color.names - colors, - - // local aliases of functions called often - each = jQuery.each; - -// determine rgba support immediately -supportElem.style.cssText = "background-color:rgba(1,1,1,.5)"; -support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1; - -// define cache name and alpha properties -// for rgba and hsla spaces -each( spaces, function( spaceName, space ) { - space.cache = "_" + spaceName; - space.props.alpha = { - idx: 3, - type: "percent", - def: 1 - }; -}); - -function clamp( value, prop, allowEmpty ) { - var type = propTypes[ prop.type ] || {}; - - if ( value == null ) { - return (allowEmpty || !prop.def) ? null : prop.def; - } - - // ~~ is an short way of doing floor for positive numbers - value = type.floor ? ~~value : parseFloat( value ); - - // IE will pass in empty strings as value for alpha, - // which will hit this case - if ( isNaN( value ) ) { - return prop.def; - } - - if ( type.mod ) { - // we add mod before modding to make sure that negatives values - // get converted properly: -10 -> 350 - return (value + type.mod) % type.mod; - } - - // for now all property types without mod have min and max - return 0 > value ? 0 : type.max < value ? type.max : value; -} - -function stringParse( string ) { - var inst = color(), - rgba = inst._rgba = []; - - string = string.toLowerCase(); - - each( stringParsers, function( i, parser ) { - var parsed, - match = parser.re.exec( string ), - values = match && parser.parse( match ), - spaceName = parser.space || "rgba"; - - if ( values ) { - parsed = inst[ spaceName ]( values ); - - // if this was an rgba parse the assignment might happen twice - // oh well.... - inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; - rgba = inst._rgba = parsed._rgba; - - // exit each( stringParsers ) here because we matched - return false; - } - }); - - // Found a stringParser that handled it - if ( rgba.length ) { - - // if this came from a parsed string, force "transparent" when alpha is 0 - // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) - if ( rgba.join() === "0,0,0,0" ) { - jQuery.extend( rgba, colors.transparent ); - } - return inst; - } - - // named colors - return colors[ string ]; -} - -color.fn = jQuery.extend( color.prototype, { - parse: function( red, green, blue, alpha ) { - if ( red === undefined ) { - this._rgba = [ null, null, null, null ]; - return this; - } - if ( red.jquery || red.nodeType ) { - red = jQuery( red ).css( green ); - green = undefined; - } - - var inst = this, - type = jQuery.type( red ), - rgba = this._rgba = []; - - // more than 1 argument specified - assume ( red, green, blue, alpha ) - if ( green !== undefined ) { - red = [ red, green, blue, alpha ]; - type = "array"; - } - - if ( type === "string" ) { - return this.parse( stringParse( red ) || colors._default ); - } - - if ( type === "array" ) { - each( spaces.rgba.props, function( key, prop ) { - rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); - }); - return this; - } - - if ( type === "object" ) { - if ( red instanceof color ) { - each( spaces, function( spaceName, space ) { - if ( red[ space.cache ] ) { - inst[ space.cache ] = red[ space.cache ].slice(); - } - }); - } else { - each( spaces, function( spaceName, space ) { - var cache = space.cache; - each( space.props, function( key, prop ) { - - // if the cache doesn't exist, and we know how to convert - if ( !inst[ cache ] && space.to ) { - - // if the value was null, we don't need to copy it - // if the key was alpha, we don't need to copy it either - if ( key === "alpha" || red[ key ] == null ) { - return; - } - inst[ cache ] = space.to( inst._rgba ); - } - - // this is the only case where we allow nulls for ALL properties. - // call clamp with alwaysAllowEmpty - inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); - }); - - // everything defined but alpha? - if ( inst[ cache ] && jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) { - // use the default of 1 - inst[ cache ][ 3 ] = 1; - if ( space.from ) { - inst._rgba = space.from( inst[ cache ] ); - } - } - }); - } - return this; - } - }, - is: function( compare ) { - var is = color( compare ), - same = true, - inst = this; - - each( spaces, function( _, space ) { - var localCache, - isCache = is[ space.cache ]; - if (isCache) { - localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; - each( space.props, function( _, prop ) { - if ( isCache[ prop.idx ] != null ) { - same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); - return same; - } - }); - } - return same; - }); - return same; - }, - _space: function() { - var used = [], - inst = this; - each( spaces, function( spaceName, space ) { - if ( inst[ space.cache ] ) { - used.push( spaceName ); - } - }); - return used.pop(); - }, - transition: function( other, distance ) { - var end = color( other ), - spaceName = end._space(), - space = spaces[ spaceName ], - startColor = this.alpha() === 0 ? color( "transparent" ) : this, - start = startColor[ space.cache ] || space.to( startColor._rgba ), - result = start.slice(); - - end = end[ space.cache ]; - each( space.props, function( key, prop ) { - var index = prop.idx, - startValue = start[ index ], - endValue = end[ index ], - type = propTypes[ prop.type ] || {}; - - // if null, don't override start value - if ( endValue === null ) { - return; - } - // if null - use end - if ( startValue === null ) { - result[ index ] = endValue; - } else { - if ( type.mod ) { - if ( endValue - startValue > type.mod / 2 ) { - startValue += type.mod; - } else if ( startValue - endValue > type.mod / 2 ) { - startValue -= type.mod; - } - } - result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); - } - }); - return this[ spaceName ]( result ); - }, - blend: function( opaque ) { - // if we are already opaque - return ourself - if ( this._rgba[ 3 ] === 1 ) { - return this; - } - - var rgb = this._rgba.slice(), - a = rgb.pop(), - blend = color( opaque )._rgba; - - return color( jQuery.map( rgb, function( v, i ) { - return ( 1 - a ) * blend[ i ] + a * v; - })); - }, - toRgbaString: function() { - var prefix = "rgba(", - rgba = jQuery.map( this._rgba, function( v, i ) { - return v == null ? ( i > 2 ? 1 : 0 ) : v; - }); - - if ( rgba[ 3 ] === 1 ) { - rgba.pop(); - prefix = "rgb("; - } - - return prefix + rgba.join() + ")"; - }, - toHslaString: function() { - var prefix = "hsla(", - hsla = jQuery.map( this.hsla(), function( v, i ) { - if ( v == null ) { - v = i > 2 ? 1 : 0; - } - - // catch 1 and 2 - if ( i && i < 3 ) { - v = Math.round( v * 100 ) + "%"; - } - return v; - }); - - if ( hsla[ 3 ] === 1 ) { - hsla.pop(); - prefix = "hsl("; - } - return prefix + hsla.join() + ")"; - }, - toHexString: function( includeAlpha ) { - var rgba = this._rgba.slice(), - alpha = rgba.pop(); - - if ( includeAlpha ) { - rgba.push( ~~( alpha * 255 ) ); - } - - return "#" + jQuery.map( rgba, function( v ) { - - // default to 0 when nulls exist - v = ( v || 0 ).toString( 16 ); - return v.length === 1 ? "0" + v : v; - }).join(""); - }, - toString: function() { - return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString(); - } -}); -color.fn.parse.prototype = color.fn; - -// hsla conversions adapted from: -// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 - -function hue2rgb( p, q, h ) { - h = ( h + 1 ) % 1; - if ( h * 6 < 1 ) { - return p + (q - p) * h * 6; - } - if ( h * 2 < 1) { - return q; - } - if ( h * 3 < 2 ) { - return p + (q - p) * ((2/3) - h) * 6; - } - return p; -} - -spaces.hsla.to = function ( rgba ) { - if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { - return [ null, null, null, rgba[ 3 ] ]; - } - var r = rgba[ 0 ] / 255, - g = rgba[ 1 ] / 255, - b = rgba[ 2 ] / 255, - a = rgba[ 3 ], - max = Math.max( r, g, b ), - min = Math.min( r, g, b ), - diff = max - min, - add = max + min, - l = add * 0.5, - h, s; - - if ( min === max ) { - h = 0; - } else if ( r === max ) { - h = ( 60 * ( g - b ) / diff ) + 360; - } else if ( g === max ) { - h = ( 60 * ( b - r ) / diff ) + 120; - } else { - h = ( 60 * ( r - g ) / diff ) + 240; - } - - // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% - // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) - if ( diff === 0 ) { - s = 0; - } else if ( l <= 0.5 ) { - s = diff / add; - } else { - s = diff / ( 2 - add ); - } - return [ Math.round(h) % 360, s, l, a == null ? 1 : a ]; -}; - -spaces.hsla.from = function ( hsla ) { - if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { - return [ null, null, null, hsla[ 3 ] ]; - } - var h = hsla[ 0 ] / 360, - s = hsla[ 1 ], - l = hsla[ 2 ], - a = hsla[ 3 ], - q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, - p = 2 * l - q; - - return [ - Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), - Math.round( hue2rgb( p, q, h ) * 255 ), - Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), - a - ]; -}; - - -each( spaces, function( spaceName, space ) { - var props = space.props, - cache = space.cache, - to = space.to, - from = space.from; - - // makes rgba() and hsla() - color.fn[ spaceName ] = function( value ) { - - // generate a cache for this space if it doesn't exist - if ( to && !this[ cache ] ) { - this[ cache ] = to( this._rgba ); - } - if ( value === undefined ) { - return this[ cache ].slice(); - } - - var ret, - type = jQuery.type( value ), - arr = ( type === "array" || type === "object" ) ? value : arguments, - local = this[ cache ].slice(); - - each( props, function( key, prop ) { - var val = arr[ type === "object" ? key : prop.idx ]; - if ( val == null ) { - val = local[ prop.idx ]; - } - local[ prop.idx ] = clamp( val, prop ); - }); - - if ( from ) { - ret = color( from( local ) ); - ret[ cache ] = local; - return ret; - } else { - return color( local ); - } - }; - - // makes red() green() blue() alpha() hue() saturation() lightness() - each( props, function( key, prop ) { - // alpha is included in more than one space - if ( color.fn[ key ] ) { - return; - } - color.fn[ key ] = function( value ) { - var vtype = jQuery.type( value ), - fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ), - local = this[ fn ](), - cur = local[ prop.idx ], - match; - - if ( vtype === "undefined" ) { - return cur; - } - - if ( vtype === "function" ) { - value = value.call( this, cur ); - vtype = jQuery.type( value ); - } - if ( value == null && prop.empty ) { - return this; - } - if ( vtype === "string" ) { - match = rplusequals.exec( value ); - if ( match ) { - value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); - } - } - local[ prop.idx ] = value; - return this[ fn ]( local ); - }; - }); -}); - -// add cssHook and .fx.step function for each named hook. -// accept a space separated string of properties -color.hook = function( hook ) { - var hooks = hook.split( " " ); - each( hooks, function( i, hook ) { - jQuery.cssHooks[ hook ] = { - set: function( elem, value ) { - var parsed, curElem, - backgroundColor = ""; - - if ( value !== "transparent" && ( jQuery.type( value ) !== "string" || ( parsed = stringParse( value ) ) ) ) { - value = color( parsed || value ); - if ( !support.rgba && value._rgba[ 3 ] !== 1 ) { - curElem = hook === "backgroundColor" ? elem.parentNode : elem; - while ( - (backgroundColor === "" || backgroundColor === "transparent") && - curElem && curElem.style - ) { - try { - backgroundColor = jQuery.css( curElem, "backgroundColor" ); - curElem = curElem.parentNode; - } catch ( e ) { - } - } - - value = value.blend( backgroundColor && backgroundColor !== "transparent" ? - backgroundColor : - "_default" ); - } - - value = value.toRgbaString(); - } - try { - elem.style[ hook ] = value; - } catch( e ) { - // wrapped to prevent IE from throwing errors on "invalid" values like 'auto' or 'inherit' - } - } - }; - jQuery.fx.step[ hook ] = function( fx ) { - if ( !fx.colorInit ) { - fx.start = color( fx.elem, hook ); - fx.end = color( fx.end ); - fx.colorInit = true; - } - jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); - }; - }); - -}; - -color.hook( stepHooks ); - -jQuery.cssHooks.borderColor = { - expand: function( value ) { - var expanded = {}; - - each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) { - expanded[ "border" + part + "Color" ] = value; - }); - return expanded; - } -}; - -// Basic color names only. -// Usage of any of the other color names requires adding yourself or including -// jquery.color.svg-names.js. -colors = jQuery.Color.names = { - // 4.1. Basic color keywords - aqua: "#00ffff", - black: "#000000", - blue: "#0000ff", - fuchsia: "#ff00ff", - gray: "#808080", - green: "#008000", - lime: "#00ff00", - maroon: "#800000", - navy: "#000080", - olive: "#808000", - purple: "#800080", - red: "#ff0000", - silver: "#c0c0c0", - teal: "#008080", - white: "#ffffff", - yellow: "#ffff00", - - // 4.2.3. "transparent" color keyword - transparent: [ null, null, null, 0 ], - - _default: "#ffffff" -}; - -})( jQuery ); - - -/******************************************************************************/ -/****************************** CLASS ANIMATIONS ******************************/ -/******************************************************************************/ -(function() { - -var classAnimationActions = [ "add", "remove", "toggle" ], - shorthandStyles = { - border: 1, - borderBottom: 1, - borderColor: 1, - borderLeft: 1, - borderRight: 1, - borderTop: 1, - borderWidth: 1, - margin: 1, - padding: 1 - }; - -$.each([ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], function( _, prop ) { - $.fx.step[ prop ] = function( fx ) { - if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { - jQuery.style( fx.elem, prop, fx.end ); - fx.setAttr = true; - } - }; -}); - -function getElementStyles( elem ) { - var key, len, - style = elem.ownerDocument.defaultView ? - elem.ownerDocument.defaultView.getComputedStyle( elem, null ) : - elem.currentStyle, - styles = {}; - - if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) { - len = style.length; - while ( len-- ) { - key = style[ len ]; - if ( typeof style[ key ] === "string" ) { - styles[ $.camelCase( key ) ] = style[ key ]; - } - } - // support: Opera, IE <9 - } else { - for ( key in style ) { - if ( typeof style[ key ] === "string" ) { - styles[ key ] = style[ key ]; - } - } - } - - return styles; -} - - -function styleDifference( oldStyle, newStyle ) { - var diff = {}, - name, value; - - for ( name in newStyle ) { - value = newStyle[ name ]; - if ( oldStyle[ name ] !== value ) { - if ( !shorthandStyles[ name ] ) { - if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { - diff[ name ] = value; - } - } - } - } - - return diff; -} - -// support: jQuery <1.8 -if ( !$.fn.addBack ) { - $.fn.addBack = function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - }; -} - -$.effects.animateClass = function( value, duration, easing, callback ) { - var o = $.speed( duration, easing, callback ); - - return this.queue( function() { - var animated = $( this ), - baseClass = animated.attr( "class" ) || "", - applyClassChange, - allAnimations = o.children ? animated.find( "*" ).addBack() : animated; - - // map the animated objects to store the original styles. - allAnimations = allAnimations.map(function() { - var el = $( this ); - return { - el: el, - start: getElementStyles( this ) - }; - }); - - // apply class change - applyClassChange = function() { - $.each( classAnimationActions, function(i, action) { - if ( value[ action ] ) { - animated[ action + "Class" ]( value[ action ] ); - } - }); - }; - applyClassChange(); - - // map all animated objects again - calculate new styles and diff - allAnimations = allAnimations.map(function() { - this.end = getElementStyles( this.el[ 0 ] ); - this.diff = styleDifference( this.start, this.end ); - return this; - }); - - // apply original class - animated.attr( "class", baseClass ); - - // map all animated objects again - this time collecting a promise - allAnimations = allAnimations.map(function() { - var styleInfo = this, - dfd = $.Deferred(), - opts = $.extend({}, o, { - queue: false, - complete: function() { - dfd.resolve( styleInfo ); - } - }); - - this.el.animate( this.diff, opts ); - return dfd.promise(); - }); - - // once all animations have completed: - $.when.apply( $, allAnimations.get() ).done(function() { - - // set the final class - applyClassChange(); - - // for each animated element, - // clear all css properties that were animated - $.each( arguments, function() { - var el = this.el; - $.each( this.diff, function(key) { - el.css( key, "" ); - }); - }); - - // this is guarnteed to be there if you use jQuery.speed() - // it also handles dequeuing the next anim... - o.complete.call( animated[ 0 ] ); - }); - }); -}; - -$.fn.extend({ - addClass: (function( orig ) { - return function( classNames, speed, easing, callback ) { - return speed ? - $.effects.animateClass.call( this, - { add: classNames }, speed, easing, callback ) : - orig.apply( this, arguments ); - }; - })( $.fn.addClass ), - - removeClass: (function( orig ) { - return function( classNames, speed, easing, callback ) { - return arguments.length > 1 ? - $.effects.animateClass.call( this, - { remove: classNames }, speed, easing, callback ) : - orig.apply( this, arguments ); - }; - })( $.fn.removeClass ), - - toggleClass: (function( orig ) { - return function( classNames, force, speed, easing, callback ) { - if ( typeof force === "boolean" || force === undefined ) { - if ( !speed ) { - // without speed parameter - return orig.apply( this, arguments ); - } else { - return $.effects.animateClass.call( this, - (force ? { add: classNames } : { remove: classNames }), - speed, easing, callback ); - } - } else { - // without force parameter - return $.effects.animateClass.call( this, - { toggle: classNames }, force, speed, easing ); - } - }; - })( $.fn.toggleClass ), - - switchClass: function( remove, add, speed, easing, callback) { - return $.effects.animateClass.call( this, { - add: add, - remove: remove - }, speed, easing, callback ); - } -}); - -})(); - -/******************************************************************************/ -/*********************************** EFFECTS **********************************/ -/******************************************************************************/ - -(function() { - -$.extend( $.effects, { - version: "1.10.3", - - // Saves a set of properties in a data storage - save: function( element, set ) { - for( var i=0; i < set.length; i++ ) { - if ( set[ i ] !== null ) { - element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); - } - } - }, - - // Restores a set of previously saved properties from a data storage - restore: function( element, set ) { - var val, i; - for( i=0; i < set.length; i++ ) { - if ( set[ i ] !== null ) { - val = element.data( dataSpace + set[ i ] ); - // support: jQuery 1.6.2 - // http://bugs.jquery.com/ticket/9917 - // jQuery 1.6.2 incorrectly returns undefined for any falsy value. - // We can't differentiate between "" and 0 here, so we just assume - // empty string since it's likely to be a more common value... - if ( val === undefined ) { - val = ""; - } - element.css( set[ i ], val ); - } - } - }, - - setMode: function( el, mode ) { - if (mode === "toggle") { - mode = el.is( ":hidden" ) ? "show" : "hide"; - } - return mode; - }, - - // Translates a [top,left] array into a baseline value - // this should be a little more flexible in the future to handle a string & hash - getBaseline: function( origin, original ) { - var y, x; - switch ( origin[ 0 ] ) { - case "top": y = 0; break; - case "middle": y = 0.5; break; - case "bottom": y = 1; break; - default: y = origin[ 0 ] / original.height; - } - switch ( origin[ 1 ] ) { - case "left": x = 0; break; - case "center": x = 0.5; break; - case "right": x = 1; break; - default: x = origin[ 1 ] / original.width; - } - return { - x: x, - y: y - }; - }, - - // Wraps the element around a wrapper that copies position properties - createWrapper: function( element ) { - - // if the element is already wrapped, return it - if ( element.parent().is( ".ui-effects-wrapper" )) { - return element.parent(); - } - - // wrap the element - var props = { - width: element.outerWidth(true), - height: element.outerHeight(true), - "float": element.css( "float" ) - }, - wrapper = $( "

" ) - .addClass( "ui-effects-wrapper" ) - .css({ - fontSize: "100%", - background: "transparent", - border: "none", - margin: 0, - padding: 0 - }), - // Store the size in case width/height are defined in % - Fixes #5245 - size = { - width: element.width(), - height: element.height() - }, - active = document.activeElement; - - // support: Firefox - // Firefox incorrectly exposes anonymous content - // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 - try { - active.id; - } catch( e ) { - active = document.body; - } - - element.wrap( wrapper ); - - // Fixes #7595 - Elements lose focus when wrapped. - if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { - $( active ).focus(); - } - - wrapper = element.parent(); //Hotfix for jQuery 1.4 since some change in wrap() seems to actually lose the reference to the wrapped element - - // transfer positioning properties to the wrapper - if ( element.css( "position" ) === "static" ) { - wrapper.css({ position: "relative" }); - element.css({ position: "relative" }); - } else { - $.extend( props, { - position: element.css( "position" ), - zIndex: element.css( "z-index" ) - }); - $.each([ "top", "left", "bottom", "right" ], function(i, pos) { - props[ pos ] = element.css( pos ); - if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { - props[ pos ] = "auto"; - } - }); - element.css({ - position: "relative", - top: 0, - left: 0, - right: "auto", - bottom: "auto" - }); - } - element.css(size); - - return wrapper.css( props ).show(); - }, - - removeWrapper: function( element ) { - var active = document.activeElement; - - if ( element.parent().is( ".ui-effects-wrapper" ) ) { - element.parent().replaceWith( element ); - - // Fixes #7595 - Elements lose focus when wrapped. - if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { - $( active ).focus(); - } - } - - - return element; - }, - - setTransition: function( element, list, factor, value ) { - value = value || {}; - $.each( list, function( i, x ) { - var unit = element.cssUnit( x ); - if ( unit[ 0 ] > 0 ) { - value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; - } - }); - return value; - } -}); - -// return an effect options object for the given parameters: -function _normalizeArguments( effect, options, speed, callback ) { - - // allow passing all options as the first parameter - if ( $.isPlainObject( effect ) ) { - options = effect; - effect = effect.effect; - } - - // convert to an object - effect = { effect: effect }; - - // catch (effect, null, ...) - if ( options == null ) { - options = {}; - } - - // catch (effect, callback) - if ( $.isFunction( options ) ) { - callback = options; - speed = null; - options = {}; - } - - // catch (effect, speed, ?) - if ( typeof options === "number" || $.fx.speeds[ options ] ) { - callback = speed; - speed = options; - options = {}; - } - - // catch (effect, options, callback) - if ( $.isFunction( speed ) ) { - callback = speed; - speed = null; - } - - // add options to effect - if ( options ) { - $.extend( effect, options ); - } - - speed = speed || options.duration; - effect.duration = $.fx.off ? 0 : - typeof speed === "number" ? speed : - speed in $.fx.speeds ? $.fx.speeds[ speed ] : - $.fx.speeds._default; - - effect.complete = callback || options.complete; - - return effect; -} - -function standardAnimationOption( option ) { - // Valid standard speeds (nothing, number, named speed) - if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { - return true; - } - - // Invalid strings - treat as "normal" speed - if ( typeof option === "string" && !$.effects.effect[ option ] ) { - return true; - } - - // Complete callback - if ( $.isFunction( option ) ) { - return true; - } - - // Options hash (but not naming an effect) - if ( typeof option === "object" && !option.effect ) { - return true; - } - - // Didn't match any standard API - return false; -} - -$.fn.extend({ - effect: function( /* effect, options, speed, callback */ ) { - var args = _normalizeArguments.apply( this, arguments ), - mode = args.mode, - queue = args.queue, - effectMethod = $.effects.effect[ args.effect ]; - - if ( $.fx.off || !effectMethod ) { - // delegate to the original method (e.g., .show()) if possible - if ( mode ) { - return this[ mode ]( args.duration, args.complete ); - } else { - return this.each( function() { - if ( args.complete ) { - args.complete.call( this ); - } - }); - } - } - - function run( next ) { - var elem = $( this ), - complete = args.complete, - mode = args.mode; - - function done() { - if ( $.isFunction( complete ) ) { - complete.call( elem[0] ); - } - if ( $.isFunction( next ) ) { - next(); - } - } - - // If the element already has the correct final state, delegate to - // the core methods so the internal tracking of "olddisplay" works. - if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { - elem[ mode ](); - done(); - } else { - effectMethod.call( elem[0], args, done ); - } - } - - return queue === false ? this.each( run ) : this.queue( queue || "fx", run ); - }, - - show: (function( orig ) { - return function( option ) { - if ( standardAnimationOption( option ) ) { - return orig.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "show"; - return this.effect.call( this, args ); - } - }; - })( $.fn.show ), - - hide: (function( orig ) { - return function( option ) { - if ( standardAnimationOption( option ) ) { - return orig.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "hide"; - return this.effect.call( this, args ); - } - }; - })( $.fn.hide ), - - toggle: (function( orig ) { - return function( option ) { - if ( standardAnimationOption( option ) || typeof option === "boolean" ) { - return orig.apply( this, arguments ); - } else { - var args = _normalizeArguments.apply( this, arguments ); - args.mode = "toggle"; - return this.effect.call( this, args ); - } - }; - })( $.fn.toggle ), - - // helper functions - cssUnit: function(key) { - var style = this.css( key ), - val = []; - - $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { - if ( style.indexOf( unit ) > 0 ) { - val = [ parseFloat( style ), unit ]; - } - }); - return val; - } -}); - -})(); - -/******************************************************************************/ -/*********************************** EASING ***********************************/ -/******************************************************************************/ - -(function() { - -// based on easing equations from Robert Penner (http://www.robertpenner.com/easing) - -var baseEasings = {}; - -$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { - baseEasings[ name ] = function( p ) { - return Math.pow( p, i + 2 ); - }; -}); - -$.extend( baseEasings, { - Sine: function ( p ) { - return 1 - Math.cos( p * Math.PI / 2 ); - }, - Circ: function ( p ) { - return 1 - Math.sqrt( 1 - p * p ); - }, - Elastic: function( p ) { - return p === 0 || p === 1 ? p : - -Math.pow( 2, 8 * (p - 1) ) * Math.sin( ( (p - 1) * 80 - 7.5 ) * Math.PI / 15 ); - }, - Back: function( p ) { - return p * p * ( 3 * p - 2 ); - }, - Bounce: function ( p ) { - var pow2, - bounce = 4; - - while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} - return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); - } -}); - -$.each( baseEasings, function( name, easeIn ) { - $.easing[ "easeIn" + name ] = easeIn; - $.easing[ "easeOut" + name ] = function( p ) { - return 1 - easeIn( 1 - p ); - }; - $.easing[ "easeInOut" + name ] = function( p ) { - return p < 0.5 ? - easeIn( p * 2 ) / 2 : - 1 - easeIn( p * -2 + 2 ) / 2; - }; -}); - -})(); - -})(jQuery); - -(function( $, undefined ) { - -var uid = 0, - hideProps = {}, - showProps = {}; - -hideProps.height = hideProps.paddingTop = hideProps.paddingBottom = - hideProps.borderTopWidth = hideProps.borderBottomWidth = "hide"; -showProps.height = showProps.paddingTop = showProps.paddingBottom = - showProps.borderTopWidth = showProps.borderBottomWidth = "show"; - -$.widget( "ui.accordion", { - version: "1.10.3", - options: { - active: 0, - animate: {}, - collapsible: false, - event: "click", - header: "> li > :first-child,> :not(li):even", - heightStyle: "auto", - icons: { - activeHeader: "ui-icon-triangle-1-s", - header: "ui-icon-triangle-1-e" - }, - - // callbacks - activate: null, - beforeActivate: null - }, - - _create: function() { - var options = this.options; - this.prevShow = this.prevHide = $(); - this.element.addClass( "ui-accordion ui-widget ui-helper-reset" ) - // ARIA - .attr( "role", "tablist" ); - - // don't allow collapsible: false and active: false / null - if ( !options.collapsible && (options.active === false || options.active == null) ) { - options.active = 0; - } - - this._processPanels(); - // handle negative values - if ( options.active < 0 ) { - options.active += this.headers.length; - } - this._refresh(); - }, - - _getCreateEventData: function() { - return { - header: this.active, - panel: !this.active.length ? $() : this.active.next(), - content: !this.active.length ? $() : this.active.next() - }; - }, - - _createIcons: function() { - var icons = this.options.icons; - if ( icons ) { - $( "" ) - .addClass( "ui-accordion-header-icon ui-icon " + icons.header ) - .prependTo( this.headers ); - this.active.children( ".ui-accordion-header-icon" ) - .removeClass( icons.header ) - .addClass( icons.activeHeader ); - this.headers.addClass( "ui-accordion-icons" ); - } - }, - - _destroyIcons: function() { - this.headers - .removeClass( "ui-accordion-icons" ) - .children( ".ui-accordion-header-icon" ) - .remove(); - }, - - _destroy: function() { - var contents; - - // clean up main element - this.element - .removeClass( "ui-accordion ui-widget ui-helper-reset" ) - .removeAttr( "role" ); - - // clean up headers - this.headers - .removeClass( "ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top" ) - .removeAttr( "role" ) - .removeAttr( "aria-selected" ) - .removeAttr( "aria-controls" ) - .removeAttr( "tabIndex" ) - .each(function() { - if ( /^ui-accordion/.test( this.id ) ) { - this.removeAttribute( "id" ); - } - }); - this._destroyIcons(); - - // clean up content panels - contents = this.headers.next() - .css( "display", "" ) - .removeAttr( "role" ) - .removeAttr( "aria-expanded" ) - .removeAttr( "aria-hidden" ) - .removeAttr( "aria-labelledby" ) - .removeClass( "ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled" ) - .each(function() { - if ( /^ui-accordion/.test( this.id ) ) { - this.removeAttribute( "id" ); - } - }); - if ( this.options.heightStyle !== "content" ) { - contents.css( "height", "" ); - } - }, - - _setOption: function( key, value ) { - if ( key === "active" ) { - // _activate() will handle invalid values and update this.options - this._activate( value ); - return; - } - - if ( key === "event" ) { - if ( this.options.event ) { - this._off( this.headers, this.options.event ); - } - this._setupEvents( value ); - } - - this._super( key, value ); - - // setting collapsible: false while collapsed; open first panel - if ( key === "collapsible" && !value && this.options.active === false ) { - this._activate( 0 ); - } - - if ( key === "icons" ) { - this._destroyIcons(); - if ( value ) { - this._createIcons(); - } - } - - // #5332 - opacity doesn't cascade to positioned elements in IE - // so we need to add the disabled class to the headers and panels - if ( key === "disabled" ) { - this.headers.add( this.headers.next() ) - .toggleClass( "ui-state-disabled", !!value ); - } - }, - - _keydown: function( event ) { - /*jshint maxcomplexity:15*/ - if ( event.altKey || event.ctrlKey ) { - return; - } - - var keyCode = $.ui.keyCode, - length = this.headers.length, - currentIndex = this.headers.index( event.target ), - toFocus = false; - - switch ( event.keyCode ) { - case keyCode.RIGHT: - case keyCode.DOWN: - toFocus = this.headers[ ( currentIndex + 1 ) % length ]; - break; - case keyCode.LEFT: - case keyCode.UP: - toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; - break; - case keyCode.SPACE: - case keyCode.ENTER: - this._eventHandler( event ); - break; - case keyCode.HOME: - toFocus = this.headers[ 0 ]; - break; - case keyCode.END: - toFocus = this.headers[ length - 1 ]; - break; - } - - if ( toFocus ) { - $( event.target ).attr( "tabIndex", -1 ); - $( toFocus ).attr( "tabIndex", 0 ); - toFocus.focus(); - event.preventDefault(); - } - }, - - _panelKeyDown : function( event ) { - if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { - $( event.currentTarget ).prev().focus(); - } - }, - - refresh: function() { - var options = this.options; - this._processPanels(); - - // was collapsed or no panel - if ( ( options.active === false && options.collapsible === true ) || !this.headers.length ) { - options.active = false; - this.active = $(); - // active false only when collapsible is true - } else if ( options.active === false ) { - this._activate( 0 ); - // was active, but active panel is gone - } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { - // all remaining panel are disabled - if ( this.headers.length === this.headers.find(".ui-state-disabled").length ) { - options.active = false; - this.active = $(); - // activate previous panel - } else { - this._activate( Math.max( 0, options.active - 1 ) ); - } - // was active, active panel still exists - } else { - // make sure active index is correct - options.active = this.headers.index( this.active ); - } - - this._destroyIcons(); - - this._refresh(); - }, - - _processPanels: function() { - this.headers = this.element.find( this.options.header ) - .addClass( "ui-accordion-header ui-helper-reset ui-state-default ui-corner-all" ); - - this.headers.next() - .addClass( "ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom" ) - .filter(":not(.ui-accordion-content-active)") - .hide(); - }, - - _refresh: function() { - var maxHeight, - options = this.options, - heightStyle = options.heightStyle, - parent = this.element.parent(), - accordionId = this.accordionId = "ui-accordion-" + - (this.element.attr( "id" ) || ++uid); - - this.active = this._findActive( options.active ) - .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ) - .removeClass( "ui-corner-all" ); - this.active.next() - .addClass( "ui-accordion-content-active" ) - .show(); - - this.headers - .attr( "role", "tab" ) - .each(function( i ) { - var header = $( this ), - headerId = header.attr( "id" ), - panel = header.next(), - panelId = panel.attr( "id" ); - if ( !headerId ) { - headerId = accordionId + "-header-" + i; - header.attr( "id", headerId ); - } - if ( !panelId ) { - panelId = accordionId + "-panel-" + i; - panel.attr( "id", panelId ); - } - header.attr( "aria-controls", panelId ); - panel.attr( "aria-labelledby", headerId ); - }) - .next() - .attr( "role", "tabpanel" ); - - this.headers - .not( this.active ) - .attr({ - "aria-selected": "false", - tabIndex: -1 - }) - .next() - .attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }) - .hide(); - - // make sure at least one header is in the tab order - if ( !this.active.length ) { - this.headers.eq( 0 ).attr( "tabIndex", 0 ); - } else { - this.active.attr({ - "aria-selected": "true", - tabIndex: 0 - }) - .next() - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }); - } - - this._createIcons(); - - this._setupEvents( options.event ); - - if ( heightStyle === "fill" ) { - maxHeight = parent.height(); - this.element.siblings( ":visible" ).each(function() { - var elem = $( this ), - position = elem.css( "position" ); - - if ( position === "absolute" || position === "fixed" ) { - return; - } - maxHeight -= elem.outerHeight( true ); - }); - - this.headers.each(function() { - maxHeight -= $( this ).outerHeight( true ); - }); - - this.headers.next() - .each(function() { - $( this ).height( Math.max( 0, maxHeight - - $( this ).innerHeight() + $( this ).height() ) ); - }) - .css( "overflow", "auto" ); - } else if ( heightStyle === "auto" ) { - maxHeight = 0; - this.headers.next() - .each(function() { - maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); - }) - .height( maxHeight ); - } - }, - - _activate: function( index ) { - var active = this._findActive( index )[ 0 ]; - - // trying to activate the already active panel - if ( active === this.active[ 0 ] ) { - return; - } - - // trying to collapse, simulate a click on the currently active header - active = active || this.active[ 0 ]; - - this._eventHandler({ - target: active, - currentTarget: active, - preventDefault: $.noop - }); - }, - - _findActive: function( selector ) { - return typeof selector === "number" ? this.headers.eq( selector ) : $(); - }, - - _setupEvents: function( event ) { - var events = { - keydown: "_keydown" - }; - if ( event ) { - $.each( event.split(" "), function( index, eventName ) { - events[ eventName ] = "_eventHandler"; - }); - } - - this._off( this.headers.add( this.headers.next() ) ); - this._on( this.headers, events ); - this._on( this.headers.next(), { keydown: "_panelKeyDown" }); - this._hoverable( this.headers ); - this._focusable( this.headers ); - }, - - _eventHandler: function( event ) { - var options = this.options, - active = this.active, - clicked = $( event.currentTarget ), - clickedIsActive = clicked[ 0 ] === active[ 0 ], - collapsing = clickedIsActive && options.collapsible, - toShow = collapsing ? $() : clicked.next(), - toHide = active.next(), - eventData = { - oldHeader: active, - oldPanel: toHide, - newHeader: collapsing ? $() : clicked, - newPanel: toShow - }; - - event.preventDefault(); - - if ( - // click on active header, but not collapsible - ( clickedIsActive && !options.collapsible ) || - // allow canceling activation - ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { - return; - } - - options.active = collapsing ? false : this.headers.index( clicked ); - - // when the call to ._toggle() comes after the class changes - // it causes a very odd bug in IE 8 (see #6720) - this.active = clickedIsActive ? $() : clicked; - this._toggle( eventData ); - - // switch classes - // corner classes on the previously active header stay after the animation - active.removeClass( "ui-accordion-header-active ui-state-active" ); - if ( options.icons ) { - active.children( ".ui-accordion-header-icon" ) - .removeClass( options.icons.activeHeader ) - .addClass( options.icons.header ); - } - - if ( !clickedIsActive ) { - clicked - .removeClass( "ui-corner-all" ) - .addClass( "ui-accordion-header-active ui-state-active ui-corner-top" ); - if ( options.icons ) { - clicked.children( ".ui-accordion-header-icon" ) - .removeClass( options.icons.header ) - .addClass( options.icons.activeHeader ); - } - - clicked - .next() - .addClass( "ui-accordion-content-active" ); - } - }, - - _toggle: function( data ) { - var toShow = data.newPanel, - toHide = this.prevShow.length ? this.prevShow : data.oldPanel; - - // handle activating a panel during the animation for another activation - this.prevShow.add( this.prevHide ).stop( true, true ); - this.prevShow = toShow; - this.prevHide = toHide; - - if ( this.options.animate ) { - this._animate( toShow, toHide, data ); - } else { - toHide.hide(); - toShow.show(); - this._toggleComplete( data ); - } - - toHide.attr({ - "aria-expanded": "false", - "aria-hidden": "true" - }); - toHide.prev().attr( "aria-selected", "false" ); - // if we're switching panels, remove the old header from the tab order - // if we're opening from collapsed state, remove the previous header from the tab order - // if we're collapsing, then keep the collapsing header in the tab order - if ( toShow.length && toHide.length ) { - toHide.prev().attr( "tabIndex", -1 ); - } else if ( toShow.length ) { - this.headers.filter(function() { - return $( this ).attr( "tabIndex" ) === 0; - }) - .attr( "tabIndex", -1 ); - } - - toShow - .attr({ - "aria-expanded": "true", - "aria-hidden": "false" - }) - .prev() - .attr({ - "aria-selected": "true", - tabIndex: 0 - }); - }, - - _animate: function( toShow, toHide, data ) { - var total, easing, duration, - that = this, - adjust = 0, - down = toShow.length && - ( !toHide.length || ( toShow.index() < toHide.index() ) ), - animate = this.options.animate || {}, - options = down && animate.down || animate, - complete = function() { - that._toggleComplete( data ); - }; - - if ( typeof options === "number" ) { - duration = options; - } - if ( typeof options === "string" ) { - easing = options; - } - // fall back from options to animation in case of partial down settings - easing = easing || options.easing || animate.easing; - duration = duration || options.duration || animate.duration; - - if ( !toHide.length ) { - return toShow.animate( showProps, duration, easing, complete ); - } - if ( !toShow.length ) { - return toHide.animate( hideProps, duration, easing, complete ); - } - - total = toShow.show().outerHeight(); - toHide.animate( hideProps, { - duration: duration, - easing: easing, - step: function( now, fx ) { - fx.now = Math.round( now ); - } - }); - toShow - .hide() - .animate( showProps, { - duration: duration, - easing: easing, - complete: complete, - step: function( now, fx ) { - fx.now = Math.round( now ); - if ( fx.prop !== "height" ) { - adjust += fx.now; - } else if ( that.options.heightStyle !== "content" ) { - fx.now = Math.round( total - toHide.outerHeight() - adjust ); - adjust = 0; - } - } - }); - }, - - _toggleComplete: function( data ) { - var toHide = data.oldPanel; - - toHide - .removeClass( "ui-accordion-content-active" ) - .prev() - .removeClass( "ui-corner-top" ) - .addClass( "ui-corner-all" ); - - // Work around for rendering bug in IE (#5421) - if ( toHide.length ) { - toHide.parent()[0].className = toHide.parent()[0].className; - } - - this._trigger( "activate", null, data ); - } -}); - -})( jQuery ); - -(function( $, undefined ) { - -// used to prevent race conditions with remote data sources -var requestIndex = 0; - -$.widget( "ui.autocomplete", { - version: "1.10.3", - defaultElement: "", - options: { - appendTo: null, - autoFocus: false, - delay: 300, - minLength: 1, - position: { - my: "left top", - at: "left bottom", - collision: "none" - }, - source: null, - - // callbacks - change: null, - close: null, - focus: null, - open: null, - response: null, - search: null, - select: null - }, - - pending: 0, - - _create: function() { - // Some browsers only repeat keydown events, not keypress events, - // so we use the suppressKeyPress flag to determine if we've already - // handled the keydown event. #7269 - // Unfortunately the code for & in keypress is the same as the up arrow, - // so we use the suppressKeyPressRepeat flag to avoid handling keypress - // events when we know the keydown event was used to modify the - // search term. #7799 - var suppressKeyPress, suppressKeyPressRepeat, suppressInput, - nodeName = this.element[0].nodeName.toLowerCase(), - isTextarea = nodeName === "textarea", - isInput = nodeName === "input"; - - this.isMultiLine = - // Textareas are always multi-line - isTextarea ? true : - // Inputs are always single-line, even if inside a contentEditable element - // IE also treats inputs as contentEditable - isInput ? false : - // All other element types are determined by whether or not they're contentEditable - this.element.prop( "isContentEditable" ); - - this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; - this.isNewMenu = true; - - this.element - .addClass( "ui-autocomplete-input" ) - .attr( "autocomplete", "off" ); - - this._on( this.element, { - keydown: function( event ) { - /*jshint maxcomplexity:15*/ - if ( this.element.prop( "readOnly" ) ) { - suppressKeyPress = true; - suppressInput = true; - suppressKeyPressRepeat = true; - return; - } - - suppressKeyPress = false; - suppressInput = false; - suppressKeyPressRepeat = false; - var keyCode = $.ui.keyCode; - switch( event.keyCode ) { - case keyCode.PAGE_UP: - suppressKeyPress = true; - this._move( "previousPage", event ); - break; - case keyCode.PAGE_DOWN: - suppressKeyPress = true; - this._move( "nextPage", event ); - break; - case keyCode.UP: - suppressKeyPress = true; - this._keyEvent( "previous", event ); - break; - case keyCode.DOWN: - suppressKeyPress = true; - this._keyEvent( "next", event ); - break; - case keyCode.ENTER: - case keyCode.NUMPAD_ENTER: - // when menu is open and has focus - if ( this.menu.active ) { - // #6055 - Opera still allows the keypress to occur - // which causes forms to submit - suppressKeyPress = true; - event.preventDefault(); - this.menu.select( event ); - } - break; - case keyCode.TAB: - if ( this.menu.active ) { - this.menu.select( event ); - } - break; - case keyCode.ESCAPE: - if ( this.menu.element.is( ":visible" ) ) { - this._value( this.term ); - this.close( event ); - // Different browsers have different default behavior for escape - // Single press can mean undo or clear - // Double press in IE means clear the whole form - event.preventDefault(); - } - break; - default: - suppressKeyPressRepeat = true; - // search timeout should be triggered before the input value is changed - this._searchTimeout( event ); - break; - } - }, - keypress: function( event ) { - if ( suppressKeyPress ) { - suppressKeyPress = false; - if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { - event.preventDefault(); - } - return; - } - if ( suppressKeyPressRepeat ) { - return; - } - - // replicate some key handlers to allow them to repeat in Firefox and Opera - var keyCode = $.ui.keyCode; - switch( event.keyCode ) { - case keyCode.PAGE_UP: - this._move( "previousPage", event ); - break; - case keyCode.PAGE_DOWN: - this._move( "nextPage", event ); - break; - case keyCode.UP: - this._keyEvent( "previous", event ); - break; - case keyCode.DOWN: - this._keyEvent( "next", event ); - break; - } - }, - input: function( event ) { - if ( suppressInput ) { - suppressInput = false; - event.preventDefault(); - return; - } - this._searchTimeout( event ); - }, - focus: function() { - this.selectedItem = null; - this.previous = this._value(); - }, - blur: function( event ) { - if ( this.cancelBlur ) { - delete this.cancelBlur; - return; - } - - clearTimeout( this.searching ); - this.close( event ); - this._change( event ); - } - }); - - this._initSource(); - this.menu = $( "